Значение необязательного типа «Строка?» должно быть развернуто в значение типа «Строка» в массив?

#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 предложение! это определенно помогает!