#swift #swift-guard
Вопрос:
В одноэлементном классе я пытаюсь выполнить следующий код с 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: amp;cancellables)
}
Но по какой-то причине строки guard let url = urls["en"] else { return }
недостаточно, чтобы развернуть значение:
Происходит ли это потому URL
, что конструктор может вернуть ноль?
Или из-за того, что словарь может не иметь значения для ключа?
И почему здесь недостаточно заявления охраны?
Ответ №1:
urls
на самом деле это тип [String: URL?]
. Обратите внимание, что тип значения является необязательным, поскольку URL.init(string:)
он может быть сбойным.
Когда вы пытаетесь получить значение из этого словаря, вы получаете URL??
. guard
Единственный разворачивает один слой необязательного.
Один из способов развернуть вложенный необязательный элемент (независимо от количества слоев) — использовать as?
:
guard let url = urls["en"] as? URL else { return }
Комментарии:
1. Ах, есть «слои опциональности»? Я все еще учусь быстрому
2. @AlexanderFarber Да, вы можете иметь
URL?
URL??
,URL???
и т. Д. Вы можете добавить произвольное количество вопросительных знаков в конце. ДляURL??
, есть 3 случая, это может быть полностью ноль (.none
), или внешний необязательный не равен нулю, но внутренний необязательный равен нулю (.some(.none)
), или там может быть фактический URL (.some(.some(http://example.com))
).3. @AlexanderFarber Эти случаи соответствуют «ошибка поиска по словарю», «инициализатор URL-адреса не удался, но поиск по словарю удался» и «оба успешно» соответственно.
4. @AlexanderFarber В опционах нет ничего особенного. Вы можете вложить их так же, как вы можете вложить массивы или словари в другие arrys или словари.
Ответ №2:
Происходит ли это из-за того, что конструктор 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-адреса.
Ответ №3:
Это как Url
инициализатор возвращает необязательный необязательный перенос Dictionary
, если вы уверены, что все URL-адреса действительны, то
guard let url = urls["en"] else { return }
URLSession.shared.dataTaskPublisher(for: url!) // add only !
или только
URLSession.shared.dataTaskPublisher(for: urls["en"]!!) // add !!
Комментарии:
1. @AlexanderFarber, возможно, но это приведет к путанице как для вас, так и для кого-то другого, если они будут читать ваш код позже