После того, как guard let url, значение еще нужно развернуть
В одноэлементном классе я пробую следующий код с 3 URL-адресами, хранящимися в словаре:
class DownloadManager {
static let instance = DownloadManager()
let urls = [
"en" : URL(string: "https://wordsbyfarber.com/ws/top"),
"de" : URL(string: "https://wortefarbers.de/ws/top"),
"ru" : URL(string: "https://slova.de/ws/top")
]
var cancellables = Set<AnyCancellable>()
private init() {
getTops()
}
func getTops() {
guard let url = urls["en"] else { return }
URLSession.shared.dataTaskPublisher(for: url) // COMPILE ERROR
.tryMap(handleOutput)
.decode(type: TopResponse.self, decoder: JSONDecoder())
.sink { completion in
print(completion)
} receiveValue: { fetchedTops in
// ... store entities in Core Data
}
.store(in: &cancellables)
}
Но почему-то линия
guard let url = urls["en"] else { return }
недостаточно, чтобы развернуть значение:
Это происходит потому, что
URL
конструктор может вернуть ноль?
Или из-за того, что в словаре может не быть значения для ключа?
И почему здесь недостаточно заявления охраны?
3 ответа
urls
на самом деле типа
[String: URL?]
. Обратите внимание, что тип значения не является обязательным, потому что
URL.init(string:)
не работает.
Когда вы пытаетесь получить значение из этого словаря, вы получаете
URL??
. В
guard
разворачивает только один дополнительный слой.
Один из способов развернуть вложенный необязательный элемент (независимо от количества слоев) - использовать
as?
:
guard let url = urls["en"] as? URL else { return }
Вот как
Url
инициализатор возвращает необязательный + необязательный перенос
Dictionary
, Если вы уверены, что все URL-адреса действительны, тогда
guard let url = urls["en"] else { return }
URLSession.shared.dataTaskPublisher(for: url!) // add only !
или только
URLSession.shared.dataTaskPublisher(for: urls["en"]!!) // add !!
Это происходит из-за того, что конструктор URL-адреса может вернуть ноль?
Да.
let urls = [
"en" : URL(string: "https://wordsbyfarber.com/ws/top"),
"de" : URL(string: "https://wortefarbers.de/ws/top"),
"ru" : URL(string: "https://slova.de/ws/top")
]
создает словарь с необязательными URL-адресами (
[String: URL?]
), и ваша распаковка относится только к содержимому словаря.
Использовать
let urls = [
"en" : URL(string: "https://wordsbyfarber.com/ws/top")!,
"de" : URL(string: "https://wortefarbers.de/ws/top")!,
"ru" : URL(string: "https://slova.de/ws/top")!
]
для жестко запрограммированных URL-адресов, или двойное развертывание, если неясно, действительны ли URL-адреса.