[英]Odd Generics & Optional Behavior in Swift 4.2 after upgrading to iOS 12.2 (Xcode 10.2)
We have just updated Xcode to 10.2 (hence iOS 12.2 SDK) and started seeing odd behavior with respect to the behavior of Swift Generics
and Optionals
. 我们刚刚将Xcode更新为10.2(因此是iOS 12.2 SDK),并开始看到有关
Swift Generics
和Optionals
行为的奇怪行为。 We have kept the Swift version at 4.2, so no Swift 5 update. 我们将Swift版本保持在4.2,因此没有Swift 5更新。 The only change was updating to Xcode 10.2 from Xcode 10.1.
唯一的变化是从Xcode 10.1更新到Xcode 10.2。
Here is a sample code that illustrates the oddities. 这是一个示例代码,用于说明奇怪之处。 The comments show what has changed between versions.
评论显示版本之间发生了哪些变化。 Ideally, there shouldn't be any changes.
理想情况下,不应该有任何变化。
class Phone<T> {}
extension Phone {
class func create(initial: T? = nil) -> Phone<T> {
if let _ = initial { print("Regular: Unwrapping worked.") }
return Phone()
}
}
extension Phone where T == Void {
class func create(initial: T? = nil) -> Phone<T> {
if let _ = initial { print("T == Void: Unwrapping worked.") }
return Phone()
}
}
var phone: Phone<Int?> = Phone()
var phone2: Phone<Int?> = Phone()
var phone3: Phone<Int?> = Phone()
// unwrapping works iOS 12.1, doesn't work in 12.2
phone = Phone.create(initial: Optional(nil))
// unwrapping works iOS 12.1, doesn't work in 12.2
phone2 = Phone.create(initial: Optional<Int?>(nil))
// doesn't compile in iOS 12.1, unwrapping works in iOS 12.2
phone3 = Phone.create(initial: Optional<Int>(nil))
// doesn't compile in iOS 12.1, unwrapping doesn't work in 12.2 (uses the T == Void function)
let phone4 = Phone.create(initial: Optional(nil))
We have gone through the release notes of Xcode 10.2 but haven't spotted any changes around Optionals or Generics. 我们已经阅读了Xcode 10.2的发行说明,但没有发现Optionals或Generics的任何变化。 It is really hard to understand what is causing this change in behavior between versions.
很难理解导致版本之间行为发生这种变化的原因。
It is especially very interesting how phone2
and phone3
behave differently. phone2
和phone3
表现方式特别有趣。 There are few odd things happening in the code sample above, so the question is if anyone knows what might have caused the behavioral changes in this release? 上面的代码示例中发生了一些奇怪的事情,所以问题是,是否有人知道在此版本中可能导致行为更改的原因是什么?
This is due to SE-0213: Literal initialization via coercion which means that Optional(nil)
is now treated as nil as Optional
by the compiler. 这是由于SE-0213:通过强制进行文字初始化,这意味着编译器现在将
Optional(nil)
视为nil as Optional
。 Previously with Optional(nil)
, you'd get a wrapped nil
value eg Int??.some(nil)
, however now you get just nil
. 以前使用
Optional(nil)
,你会得到一个包裹的 nil
值,例如Int??.some(nil)
,但现在你得到的只是nil
。
So for the following: 所以对于以下内容:
let phone: Phone<Int?> = Phone.create(initial: Optional(nil))
the compiler is treating it as: 编译器将其视为:
let phone: Phone<Int?> = Phone.create(initial: nil as Optional)
which is equivalent to: 这相当于:
let phone: Phone<Int?> = Phone.create(initial: nil)
Because you've specified the generic parameter T
to be Int?
因为您已将通用参数
T
指定为Int?
, the initial:
parameter takes an Int??
,
initial:
参数需要一个Int??
. 。 Therefore by passing
nil
you're passing Int??.none
, and therefore the unwrapping fails. 因此,通过传递
nil
你传递Int??.none
,因此解包失败。
One way to restore the old behaviour is to specify .init
explicitly in order to force the compiler to call the initialiser: 恢复旧行为的一种方法是明确指定
.init
以强制编译器调用初始化器:
let phone: Phone<Int?> = Phone.create(initial: Optional.init(nil))
Now you're passing an Int??.some(nil)
to the parameter and the unwrapping succeeds. 现在你传递一个
Int??.some(nil)
到参数并且解包成功。
However I would question why you're dealing with doubly wrapped optionals in the first place – I would strongly encourage avoiding them unless absolutely necessary. 但是我会问你为什么要首先处理双重包装的选项 - 除非绝对必要,否则我强烈建议你避免使用它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.