为什么我不能将隐式解包的可选项作为 UnsafeMutablePointer 传递?

Why can't I pass an implicitly unwrapped optional as an UnsafeMutablePointer?

似乎 Xcode 9.3 确实修复了 ,但在 Swift 4.1 中,此代码的后半部分仍然无法编译:

var obj: SomeClass!    ; class SomeClass {}

func inoutFunc(_: inout SomeClass?) {}
inoutFunc(&obj)     // works

func pointerFunc(_: UnsafeMutablePointer<SomeClass?>) {}
pointerFunc(&obj)  // <-- COMPILER ERROR

现在调用inoutFunc没问题了,但是调用pointerFunc还是报错:

Cannot invoke 'pointerFunc' with an argument list of type '(inout SomeClass!)'

或在原文中:

Cannot pass immutable value of type 'ActualClass?' as inout argument

类似于我的 Swift 4.0 问题(其中 inoutFunc 也没有编译)如果我将声明更改为 var obj: SomeClass? 那么第二个函数调用编译时没有投诉。

这是另一个与隐式展开可选相关的挥之不去的 Swift 错误,还是这种 UnsafeMutablePointer 情况不会像现在的 inout 版本那样工作?有没有相对干净的解决方法?


背景:

在实际代码中,pointerFunc 调用是一个 Apple 框架函数,它要么初始化实例,要么 returns 一个错误状态。

因为我已经 guard AppleFrameworkInitializer(&obj) == noErr else { /* … */ },所以我不想处理从临时可选的重新分配,或者不得不在后面的所有代码中不断解包 obj!

也就是说,这似乎是 Implicitly Unwrapped Optionals 的合法用例,我想知道为什么我仍然不能在这里使用它。

恐怕这是另一个围绕隐式解包选项 (IUO) 挥之不去的错误。

它已经被修复了(几乎可以肯定是 the recent-ish work to completely remove IUOs from the type system 的结果)——它在最新的开发快照中编译,因此将进入 4.2(master 的最终重新分支是 4 月 20 日) ).

在 4.2 推出之前,一种可能的解决方法是使用转发计算变量,以便将 IUO 视为强可选类型:

class SomeClass {}

var obj: SomeClass!
var _optionalObj: SomeClass? {
  get { return obj }
  set { obj = newValue }
}

func pointerFunc(_: UnsafeMutablePointer<SomeClass?>) {}
pointerFunc(&_optionalObj)

(也就是说,假设您可以让指针指向一个临时值 - 即您不依赖于指针值是稳定的或唯一的,例如如果要使用它,例如,作为关联的对象键)