编程iOS开发者

Swift中的可失败初始化器(`init?`)是如何工作的?何时及为何使用它们,应该考虑哪些重要细节?

用 Hintsage AI 助手通过面试

回答

可失败初始化器(init?)在Swift中允许描述创建类型实例可能失败并返回nil的情况。它们通常用于验证输入数据或可能不成功的转换。在可失败初始化器中,您可以显式返回nil,表示对象创建失败。

示例:

struct User { let name: String let age: Int init?(name: String, age: Int) { guard !name.isEmpty, age > 0 else { return nil } self.name = name self.age = age } }

因此,可以防止创建不正确的对象。

重要细节:

  • 在继承链中,可失败初始化器只能被可失败初始化器重写。
  • 使用包含可失败初始化器的结构体在数组中进行映射初始化(compactMap)时,这对于过滤无效实例很方便。

刁钻问题

问题: init?init!有什么区别,以及何时使用带有隐式解包的可失败初始化器?

回答: init?返回一个可选类型(<type?>),如果初始化失败,将返回nil,这需要安全处理。init!返回一个隐式解包可选类型(<type!>),如果初始化失败,同样将返回nil,但在没有检查的情况下使用这样的对象将导致运行时崩溃。仅在您确定在您的上下文中初始化不可能失败时才使用init!(例如,在UIKit的storyboard中工作时)。

let value = Int("abc") // value将为nil

由于不了解主题细节而导致的实际错误示例。


故事

在手动解析JSON时使用了常规初始化器而不是可失败初始化器。这导致创建了"空"用户,因为验证未能生效,应用程序未能过滤无效数据。


故事

使用init!处理潜在的无效数据导致应用程序崩溃,在API更新后:输入数据格式发生变化,提取对象时出现运行时异常,因隐式解包nil。


故事

在自定义实现可失败初始化器时,忘记在某些场景下显式返回nil,最终结构初始化为"脏"字段,导致后续的业务逻辑错误。