#ios #swift
Вопрос:
Совершенно новый новичок здесь, в Swift, я пытаюсь понять типизацию здесь
У меня есть приведенный ниже код
@IBAction func randomImage(_ sender: Any) {
let path = Bundle.main.path(forResource: "imageList", ofType: "plist")
let dict = NSDictionary(contentsOfFile: path!)
let data = dict!.object(forKey: "Images") as! [String]
imageView.image = UIImage(named: data.randomElement())
}
Как показано выше, сначала я должен dict!
убедиться, что dict
он доступен, затем data
будет введен тип, в [String]
который входит массив строк.
Теперь часть, которую я не понимаю, заключается в том, почему data.randomElement()
вы даете мне ошибку
Значение необязательного типа «Строка?» должно быть развернуто до значения типа «Строка»
Объединяйтесь с помощью»??», чтобы указать значение по умолчанию, если необязательное значение содержит «ноль».
Принудительно разверните с помощью»!», чтобы прервать выполнение, если необязательное значение содержит «ноль».
конечно, основываясь на этом предложении , я могу уйти data.randomElement()!
, но зачем это нужно?
Комментарии:
1. Узнайте, как развернуть необязательное значение. docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html
2.
randomElement()
должен возвращать необязательный параметр, потому что нет гарантии, что вы вызвали его в непустом массиве. Если вы вызвали его для пустого массива, он вернетсяnil
.3. @Alexander: Ну я понимаю, если
randomElement()
нужно вернутьсяoptional
, тогда это имеет смысл, спасибо!4. @Isaac Это также относится к
first
,last
,min()
, и т.д.max()
5. @Айзек Вот документ. developer.apple.com/documentation/swift/array/…
Ответ №1:
randomElement()
Функция возвращает необязательный параметр, поскольку коллекция, из которой вы извлекаете данные, может быть пустой. если это так, функция возвращает ноль.
Откажитесь от привычки использовать оператор !
принудительного разворачивания (и такие варианты, как неявно развернутые варианты). Я называю !
оператор «сбой,если ноль». Вот что он делает.
Вы должны переписать свой код с использованием if let
синтаксиса (необязательная привязка).
@IBAction func randomImage(_ sender: Any) {
if let path = Bundle.main.path(forResource: "imageList", ofType: "plist"),
let dict = NSDictionary(contentsOfFile: path),
let data = dict.object(forKey: "Images") as? [String],
let image = UIImage(named: data.randomElement()) {
imageView.image = image
} else {
// Unable to load image
}
}
С if let
таким соединением выражение завершается на каждом шаге, если результат равен нулю. Если результат верен, он продолжает выполняться оператором if, и новая временная переменная теперь необязательна.
Как только вы пройдете последний вход в соединение, если разрешите, у вас будет изображение UI, image
которое вы можете установить в свой вид изображения.
Если какой-либо из шагов завершается неудачно, выполняется предложение else. вы можете делать там все, что захотите — установить изображение по умолчанию, установить ноль в ImageView, чтобы удалить его, распечатать на консоли, что угодно. (Хотя вы могли бы немного упростить код, если бы собирались установить нулевой образ в представление изображения.)
Редактировать:
В дополнение к if let
необязательной привязке вы также можете использовать инструкции guard.
if let
необязательная привязка гласит: «попробуйте развернуть это необязательное/дополнительное. Если это удастся, создайте переменную, которая определена только в теле оператора if, и выполните оператор if.
В отличие от этого, guard
говорит: «попробуйте развернуть это дополнительное/дополнительное предложение. Если это удастся, продолжайте. Если это не удается, выполните блок кода, который выходит из текущей области.
Заявления о защите полезны, когда вам нужно проверить целый ряд вещей и вы хотите продолжать, когда все хорошо, но спасаться, если что-то пойдет не так.
if let
необязательная привязка может привести к постоянно растущему уровню отступов:
func foo() {
if let a = anOpitonal {
// Do stuff
if let b = a.someOtherOptional {
// Do more stuff
if let c = b.yetAnotherOptional {
// Still more code that only runs if all 3 unwraps work
}
}
}
}
Напротив, вы могли бы написать это с помощью такой защиты:
func foo() {
guard let a = anOpitonal else { return }
// Do stuff
guard let b = a.someOtherOptional else { return >
// Do more stuff
guard let c = b.yetAnotherOptional else { return }
// Still more code that only runs if all 3 guard statements work
}
Комментарии:
1. Большое вам спасибо за
if let
предложение! это определенно помогает!