После того, как 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-адреса.

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