NSXMLDelegate в вопросах Swift

Я пытаюсь реализовать NSXMLParserDelegate в Swift, но у меня возникают проблемы с использованием словаря атрибутов в некоторых из методов делегата. Например, в parser:didStartElement::

func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) {

пытаясь получить доступ к значениям attributeDict как:

if self.feedType == FeedType.RSS {
    self.insideLink = true
} else {
    if (String(attributeDict["rel"]) == "alternate") && (String(attributeDict["type"]) == "text/html") {
        self.link = String(attributeDict["href"])
        self.insideLink = false
        self.doneWithLink = true
    }
}

Я получаю сообщение об ошибке: "String не конвертируется в FeedType".

enum FeedType:String {

    case ATOM = "feed"
    case RSS = "rss"

}

class FeedParser:NSObject, NSXMLParserDelegate {

    var feedType:FeedType?

Это ошибка. То же самое для дюжины других вариаций на тему... есть идеи?

Я думаю, вопрос в том, как правильно использовать пары ключ / значение в attributeDict которые имеют тип [NSObject: AnyObject]?

1 ответ

Решение

Похоже, у вас может появиться фиктивное сообщение об ошибке: я бы порекомендовал оставить сообщение об ошибке.

Я думаю, вопрос в том, как правильно использовать пары ключ / значение в attributeDict которые имеют тип [NSObject: AnyObject]

Вы правы: это похоже на корень проблемы. Решение не состоит в том, чтобы построить String из словаря поиска, но (условно) приведение к String, То есть вместо того, чтобы пытаться создать новый String из ссылки неопределенного (и необязательного) типа спросите Swift, является ли эта ссылка чем-то, что можно интерпретировать как String:

let rel = attributeDict["rel"] as? String

Это дает вам дополнительный, потому что attributeDict может не содержать значение для ключа relи потому что условное приведение может завершиться неудачно (attributeDict["rel"] может быть значением другого типа). Поскольку вам нужно проверить два условных приведения и их развернутые значения, вы можете получить множество операторов принудительного развертывания (!) или глубоко вложенный if-let блоки... это было бы ужасно быстро.

Вместо этого вы можете воспользоваться тем, что Optional это перечисление. Его определение выглядит примерно так:

enum Optional<T> {
    case None    // aka nil
    case Some(T) // what you get when you unwrap a non-nil optional
}

При этом вы можете использовать сопоставление с шаблоном, чтобы выполнять поиск, приведение, развертывание и тестирование безопасно и кратко:

switch (attributeDict["rel"] as? String, attributeDict["type"] as? String) {
  case let (.Some(rel), .Some(type)) where rel == "alternate" && type == "text/html":
    // harvest link
  default:
    // no match... fall back to other behavior, log an error, etc
}

Обратите внимание, что на шаге "Уборка урожая" вам все равно придется условно разложить и развернуть attributeDict["href"] уважать. Вы можете сделать это, вложив if-let построить в этом caseили путем добавления третьего поиска к switch кортеж.


Кстати, все self. в Swift нотация не нужна (если только вы не в замыкании или не нуждаетесь в неоднозначности параметров метода из свойств экземпляра).

Другие вопросы по тегам