Почему Swift 2 предпочитает принудительную развертку дополнительным параметрам?

Я больше не вижу, как Xcode жалуется на то, что некоторые вещи нуждаются в дополнительных параметрах («?»). Теперь он всегда принудительно разворачивается (бах "!"). Есть ли какая-то причина использовать дополнительные параметры, когда мы принудительно развернули?


person 4thSpace    schedule 29.12.2015    source источник


Ответы (2)


Я действительно не знаю, что вы имеете в виду, когда пишете, что больше не видите, как Xcode жалуется на то, что "некоторые вещи нуждаются в дополнительных параметрах. Теперь он всегда принудительно разворачивается". Эти два предложения противоречат друг другу:

  • У вас может быть столько необязательных переменных, сколько вы пожелаете, но необязательные переменные могут быть очень полезными, когда вы узнаете все преимущества их использования.
  • Если у вас есть свойство, которое не является необязательным, то оно по определению не нуждается в развертывании.

Возможно, вы упомянули, что Xcode, по-видимому, реже жалуется, когда вы на самом деле принудительно разворачиваете необязательные параметры, или, как дурная привычка Xcode, предлагает вам принудительно развернуть вещи, чтобы избежать ошибок времени компиляции. Обычно это происходит потому, что Xcode не может знать во время компиляции, что вы только что написали код, который сломает ваше приложение во время выполнения.

Иногда кажется, что Xcode может иметь только одну единственную цель с его «умными подсказками»: а именно, устранять ошибки времени компиляции. Если вы попытаетесь присвоить значение типа String? (необязательно String) типу String, Xcode выдаст сообщение об ошибке компиляции и спросит, не хотите ли вы добавить оператор принудительной распаковки !. Умный Xcode, говорите? Мех, Xcode хорош для многих вещей, но решение о том, как вы разворачиваете свои опции, пока не является одной из них. Таким образом, даже если Xcode предлагает вам всевозможные вещи: если вы можете использовать необязательную цепочку, сделайте это.

Конечно, могут быть исключения. Для контроллерной части парадигмы проектирования MVC вы обычно используете оператор as! для «принудительного преобразования» (приведения), при этом Xcode иногда явно указывает вам использовать as! вместо as, например. "Вы имели в виду as! ... ?". В этих ситуациях Xcode иногда может фактически знать, что он делает, и делать вывод, что вы пытаетесь привести, например, пользовательский экземпляр класса UIViewController к типу UIViewController, то есть к его родительскому классу. Я бы сказал, что это, возможно, один из немногих случаев, когда я использую «принудительный» маркер ! без ухода на второй круг; принудительное преобразование в типы, которые я знаю со 100% уверенностью, что они могут быть приведены.

Но давайте оставим тему преобразования/приведения типов и перейдем к необязательным типам, переносу и необязательным цепочкам в целом.


Как правило, вам следует избегать принудительного развертывания, если только вы явно не знаете, что объект, который вы разворачиваете, не будет равен нулю. Для общих свойств класса, переменных и т. д., учитывая, что вы задаете этот вопрос так, как вы это делаете, я дам вам следующий совет:

Если вы можете использовать условную распаковку (if-let, guard-let, нулевой оператор объединения ??), то не используйте принудительную распаковку (!).

Ниже следует пример опасностей принудительной распаковки. Вы можете рассматривать первое предложение if (if arc4random...) как любой меньший или больший сегмент какой-либо программы, которую вы написали с помощью методов императивного программирования: мы на самом деле не знаем в деталях, каким будет 'name' до момента выполнения, и наш компилятор не может действительно помочь нам здесь.

var name : String?

/* 'name' might or might not have a non-nil 
    value after this if clause */
if arc4random_uniform(2) < 1 {
    name = "David"
}

/* Well-defined: us an if-let clause to try to unwrap your optional */
if let a = name {
    print("Hello world "+a)
        /* Very well-behaved, we did a safe
           unwrap of 'name', if not nil, to constant a */

    print("Hello world "+name!)
        /* Well... In this scope, we know that name is, 
           for a fact, not nil. So here, a force unwrap
           is ok (but not needed). */
}

let reallyGiveMeThatNameDammit = name!
    /* NOT well-defined. We won't spot this at compile time, but
       if 'name' is nil at runtime, we'll encounte a runtime error */

Я рекомендую вам прочитать о необязательных цепочках, ключевой теме в Swift.

person dfrib    schedule 29.12.2015
comment
Спасибо за отличный ответ. Я предполагаю, что для Xcode вместо того, чтобы делать if let или использовать охрану, теперь он просто бросает молоток за все, т. Е. Бам!. - person 4thSpace; 29.12.2015
comment
@4thSpace Рад помочь. Да, у меня тоже возникло такое ощущение. Однако, как только вы узнаете, что Xcode поможет вам удалить ошибки времени компиляции (иногда с помощью первого подручного средства), вы можете использовать подсказки, которые они вам дают (особенно в отношении принудительной распаковки), как хороший маркер того, где реализовать ваш необязательный цепочка. - person dfrib; 29.12.2015

ты имеешь в виду то самое какао? вы имеете в виду неявно развернутый?

protocol AnyObject { ... }

Протокол, которому неявно соответствуют все классы.

При использовании в качестве конкретного типа все известные методы и свойства @objc доступны как неявно-необязательные необязательные методы и свойства соответственно для каждого экземпляра AnyObject. Например:

class C {
  @objc func getCValue() -> Int { return 42 }
}

// If x has a method @objc getValue()->Int, call it and
// return the result.  Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
  if let f: ()->Int = x.getCValue { // <===
    return f()
  }
  return nil
}

// A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
  return x.getCValue?() // <===
}

// An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
  return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}
person user3441734    schedule 29.12.2015
comment
Нет. Это iOS и ничего общего с вещами @objc. - person 4thSpace; 29.12.2015
comment
только iOS? а что с ОСХ? Фреймворки Cocoa и CocoaTouch — это все @objc... поэтому, пожалуйста, предоставьте нам какой-нибудь пример того, о чем вы говорите. - person user3441734; 29.12.2015