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 нотация не нужна (если только вы не в замыкании или не нуждаетесь в неоднозначности параметров метода из свойств экземпляра).