转换非托管<AnyObject>!在 Swift 中使用布尔值
Posted
技术标签:
【中文标题】转换非托管<AnyObject>!在 Swift 中使用布尔值【英文标题】:Convert Unmanaged<AnyObject>! to Bool in Swift 【发布时间】:2015-10-08 13:56:03 【问题描述】:我正在尝试获取现有 Objective C 类的方法的结果,该方法使用 performSelector
调用let result = controlDelegate.performSelector("methodThatReturnsBOOL") as? Bool
我需要将此结果转换为 Swift 的 Bool 类型。
上面提到的代码,给出了一个警告
“从'Unmanaged!'到不相关的类型 'Bool' 总是失败”
结果总是“假”,即使方法返回 YES。
将结果转换为 Bool 有什么建议吗?
methodThatReturnsBOOL 的签名
- (BOOL)methodThatReturnsBOOL
return YES;
【问题讨论】:
可以发methodThatReturnsBOOL
的签名吗?
您不能将 performSelector() 与返回 BOOL 的方法一起使用。从文档中:“对于返回对象以外的任何方法,请使用 NSInvocation。” 但是 NSInvocation 在 Swift 中不可用(据我所知)。
@Alladinian : 问题已更新(它只是一个简单的 Objective C 方法,返回 YES/NO)
@MartinR :是的,我查看了 NSInvocation 并且它在 Swift 中不可用(还)。虽然 performSelector() 工作正常,但这只是如何捕获返回的 BOOL 值的问题。关于如何实现这一目标的任何其他建议?
我们在现有的 Objective C 类中有一个 id 类型的委托。我们需要通过一个 Swift 类在这个委托上 performSelector
,而后者又是现有 Objective C 类的子类。
【参考方案1】:
这个问题已经很久没有答案了,所以我正在添加我在此过程中学到的东西。
要转换由 Objective C 方法返回的 BOOL
值,您可以简单地使用它进行转换,
if let result = controlDelegate.performSelector("methodThatReturnsBOOL")
print("true")
else
print("false")
如果需要,您还可以在此处将值 true/false 分配给 Swift Bool
。
注意:我尝试使用takeRetainedValue()
将Unmanaged<AnyObject>
直接转换为Bool
,正如许多关于SO 的答案所建议的那样,但这似乎在这种情况下不起作用。
【讨论】:
在调用中缺少参数“withObject”、“afterDelay”的参数【参考方案2】:这是 Swift 3 中的解决方案,因为方法有点不同。此方法还检查 Objective-C 对象是否响应选择器,以避免崩溃。
import ObjectiveC
let selector = NSSelectorFromString("methodThatReturnsBOOL")
guard controlDelegate.responds(to: selector) else
return
if let result = controlDelegate.perform(selector)
print("true")
else
print("false")
【讨论】:
【参考方案3】:你不能在 Swift 中很好地做你想做的事。我对已接受的解决方案的问题是,它利用了 0x0 恰好 是 nil
的想法。 Swift 和 Objective-C 规范实际上并不能保证这一点。这同样适用于布尔值,因为 0x0 为假而 0x1 为真只是一个任意的实现决策。除了在技术上不正确之外,它也是很难理解的代码。无需考虑大多数平台上的 nil 指针是什么(32/64 位零),所建议的内容就是零意义。
在与 WWDC '19 的工程师交谈了一段时间后,他建议您实际上可以使用 valueFor(forKey:)
,键是函数名称/选择器描述。这是有效的,因为 Obj-C 运行时实际上将执行具有给定名称/键的任何函数以评估表达式。这仍然有点hacky,因为它需要Objective-C运行时的知识,但是它保证是平台和实现独立的,因为valueFor(forKey:)
返回一个Any?
,它可以转换成Int
或Bool
没有任何麻烦。通过使用内置转换而不是推测 0x0 或 0x1 的含义,我们避免了解释 nil 指针的整个问题。
例子:
@objc func doThing() -> Bool
return true
...
let target = someObjectWithDoThing
let selectorCallResult = target.value(forKey: "doThing")
let intResult = selectorCallResult as? Int //Optional<Int(1)>
let boolResult = selectorCallResult as? Bool //Optional<Bool(true)>
【讨论】:
【参考方案4】:与我的回答 here 类似,这可以用 @convention(c)
代替:
let selector: Selector = NSSelectorFromString("methodThatReturnsBOOL")
let methodIMP: IMP! = controlDelegate.method(for: selector)
let boolResult: Bool = unsafeBitCast(methodIMP,to:(@convention(c)(Any?,Selector)->Bool).self)(controlDelegate,selector)
这种^ 特定语法从 Swift 3.1 开始可用,也可以在 Swift 3 中使用一个额外的变量。
【讨论】:
以上是关于转换非托管<AnyObject>!在 Swift 中使用布尔值的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 中使用 JSON 的 Alamofire 请求后,如何在 AnyObject 中转换 <AnyObject> 响应?
从 'Result<AnyObject>' 转换为不相关类型 'NSArray' 总是失败
如何将 Array<AnyObject> 转换为空数组变量?
错误:无法将 [anyobject] 转换为强制类型数组<_>
Alamofire 库 Void 不能转换为 Response<AnyObject, NSError> -> Void
无法将 Promise (_,_) -> DataRequest 类型的返回表达式转换为返回类型 Promise<DataResponse,AnyObject>>