隐式解包可选值复制后为何变为可选值?Swift代码相关疑问
关于Swift隐式解包可选值的常见问题解答
1. 隐式解包可选值复制后为何会变为可选值?
其实啊,隐式解包可选值(简称IUO)说白了还是个可选类型,只是Swift给了它个语法糖待遇:直接调用它的方法、属性时不用手动加!解包。但你要是把它赋值给另一个变量,编译器可不会自动帮你解包——因为它底层就是Optional<T>类型,所以复制后的变量自然就变成普通的可选值T?了。
举个直观的例子一看就懂:
let original: String! = "Hi there" let copied = original // copied的类型是String?,不是String // 要是想得到非可选值,就得显式解包 let unwrappedCopied = original! // 这下类型就是String了
总结下:IUO的“隐式解包”只在**直接使用它的成员(比如调用方法、访问属性)**时生效,一旦涉及赋值、传参这类操作,它就会暴露可选类型的本来面目。
2. 类中声明的隐式解包属性为何仍是可选值?如何实现非可选属性+init中方法初始化的需求?
为什么类里的IUO属性访问时还是可选值?
和第一个问题的核心原因一模一样:IUO只是Optional<T>的语法糖,实际类型还是可选类型。当你直接写test.implicitString时,编译器允许你直接调用它的方法(比如test.implicitString.count)不用加!,但你要是把它赋值给变量、或者作为参数传递,它就会显露出Optional<T>的真面目。
满足需求的简便方案:非可选属性+init中调用初始化方法
你想要属性是非可选类型,同时在init()里通过复用的方法初始化,后续更新也能复用这个方法——其实完全不需要用IUO,直接这么写就搞定了:
class Test { // 直接声明为非可选的String类型,从根源上避免可选值的麻烦 var implicitString: String init() { // 在init里直接调用初始化方法给属性赋值 self.implicitString = setupString() } // 这个方法既可以在init里初始化,后续更新也能复用 func setupString() -> String { return "Default Value" } // 更新属性时直接调用方法重新赋值就行 func updateValues() { self.implicitString = setupString() } }
这么做的好处一目了然:
- 属性是严格的非可选类型,再也不用操心解包、空值的问题
init()里明确通过方法完成初始化,完全符合Swift的初始化规则- 更新方法可以直接复用
setupString(),完美满足你的复用需求
如果你的setupString()方法需要依赖类中的其他属性,只要确保那些属性在调用setupString()之前已经完成初始化就好。比如:
class Test { var prefix: String var implicitString: String init() { // 先初始化依赖的属性 self.prefix = "Hello" // 再调用依赖该属性的初始化方法 self.implicitString = setupString() } func setupString() -> String { return "\(prefix), World!" } }
要是你的初始化逻辑确实需要在init完全完成后再执行(比如依赖某些只有初始化完成后才能访问的资源),那可以考虑用lazy属性,但这种场景其实很少见——大部分情况下,上面的方案就足够解决你的问题了。
内容的提问来源于stack exchange,提问作者othomas
相关产品推荐
相关产品推荐

