В кратком руководстве здесь, в На шаге 5 делегату назначается:

if let nav = segue.destination as? UINavigationController,
   let classBVC = nav.topViewController as? ClassBVC {
       // 'self' is ClassAVC which has been delegated.
       classBVC.delegate = self
   }

Мне трудно следовать этим утверждениям, поэтому является большим недостатком просто написать:

let nav = segue.destination as? UINavigationController
let classBVC = nav?.topViewController as? ClassBVC
classBVC!.delegate = self
3
TMOTTM 19 Сен 2017 в 22:37

3 ответа

Лучший ответ

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

Развертывание силы делает ваше второе решение небезопасным. Если любая из предыдущих необязательных операций привела к значению nil, произойдет исключение во время выполнения.

classBVC!.delegate = self

Если вам нужно развернуть необязательное значение, необязательное связывание является одним из лучших вариантов для этого. Вы можете сделать стандартный код необязательного развертывания минимальным, уменьшив количество операторов if let. В некоторых сценариях использование guard let вместо if let также может привести к более четкому коду, поскольку вам не придется вкладывать блоки друг в друга.

Используя необязательную привязку, вы никогда не увидите

неожиданно обнаружил ноль при развертывании необязательного значения

Исключение во время выполнения, которое вы, скорее всего, увидите довольно часто, если принудительно развернете опциональные объекты, которые могут иметь значение nil.

guard let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC else { return }
classBVC.delegate = self
3
Dávid Pásztor 19 Сен 2017 в 19:43

Нет ничего плохого в вашем втором шаблоне, если для успешной работы вашего приложения требуется ClassBVC контроллер верхнего вида контроллера навигации, то есть destination. На самом деле, я на самом деле предпочитаю ваш второй шаблон, потому что в случае с предыдущим шаблоном (необязательное приведение / распаковка), если какое-либо из этих приведений завершится неудачно, код будет работать незаметно, не сообщая вам о возникновении серьезной проблемы. И вам будет трудно понять, почему ваши методы делегата не были вызваны.

Единственный незначительный трюк, который я могу предложить, заключается в том, что если это действительно требование, я бы вообще убрал опциональное приведение / цепочку. Нет смысла иметь две строки необязательного приведения / цепочки, за которыми следует принудительное развертывание, которое завершится неудачей, если одна из двух предыдущих строк необязательного приведения / цепочки потерпела неудачу. Я бы сделал это явно в коде:

let nav = segue.destination as! UINavigationController
let classBVC = nav.topViewController as! ClassBVC
classBVC.delegate = self

Таким образом, при чтении кода вам не нужно переходить к третьей строке, чтобы определить, что предыдущие два приведения не были действительно необязательными, а скорее были необходимы. Этот пересмотр проясняет это.


Если вы чувствуете, что guard вынуждены противостоять ситуации, когда может произойти сбой одного из этих приведений, я бы посоветовал вам сообщить разработчику, если эти существенные (если они действительно требуются) приведения не выполнены:

guard let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC else {
    fatalError("destination should be nav controller who's top view controller is a ClassBVC")
}

classBVC.delegate = self

Лично я не думаю, что это намного лучше, чем приведенный выше шаблон (конечно, ошибка более явная, но я не думаю, что код более читабелен, и результат, приводящий к сбою при сбое приведения, будет таким же). Но если вы хотите более информативное сообщение об ошибке, это один из способов решения этой проблемы.

1
Rob 19 Сен 2017 в 21:41

Да, потому что вы заявляете, что classBVC абсолютно ClassBVC объект. Если вы поместите его в оператор if let, то если он потерпит неудачу, он не потерпит крах, развернув нулевое значение.

1
Siriss 19 Сен 2017 в 19:42