转换非托管<anyobject>!在斯威夫特的Bool

时间:2015-10-08 13:56:03

标签: ios swift

我正在尝试获取现有Objective C类的方法的结果,使用 performSelector

进行调用
let result = controlDelegate.performSelector("methodThatReturnsBOOL") as? Bool

我需要将此结果转换为Bool类型的Swift。

上面提到的代码会发出警告

  

“从'未经管理!'中投下'不相关的类型'Bool'总是失败“

并且结果始终为“false”,即使方法返回YES。

有关将结果转换为Bool的建议吗?

methodThatReturnsBOOL的签名

- (BOOL)methodThatReturnsBOOL
{
    return YES;
}

4 个答案:

答案 0 :(得分:8)

已经有很长一段时间了,因为这仍然没有答案,所以我在此过程中添加了我所学到的知识。

要转换Objective C方法返回的BOOL值,您只需使用

进行转换即可
if let result = controlDelegate.performSelector("methodThatReturnsBOOL") {
    print("true")
} else {
    print("false")
}

如果需要,您还可以在此处将值true / false分配给Swift Bool

注意:我尝试使用Unmanaged<AnyObject>直接将Bool投射到takeRetainedValue(),正如SO上的许多答案所建议的那样,但这似乎并不是在这种情况下工作。

答案 1 :(得分:1)

这是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")
}

答案 2 :(得分:0)

在Swift中,您无法做自己想做的事情。我接受的解决方案的问题在于,它利用了0x0 恰好发生nil的想法。 Swift和Objective-C规范实际上并不能保证这一点。布尔值也是如此,因为0x0为false,0x1为true只是一个任意的实现决策。除了在技术上不正确之外,它也是糟糕的代码。无需考虑大多数平台(零位的32/64位)上的nil指针是什么,建议的设置就没有意义了。

在与WWDC '19的工程师交谈了一段时间之后,他建议您实际上可以使用valueFor(forKey:),其键为函数名称/选择器描述。这是可行的,因为Obj-C运行时实际上将使用给定的名称/键执行任何函数,以便评估表达式。由于仍需要Objective-C运行时的知识,所以这仍然有点麻烦,但是由于valueFor(forKey:)返回了Any?并可以转换为{{1} }或Int完全没有问题。通过使用内置的强制转换而不是推测0x0或0x1的含义,我们避免了解释nil指针的整个问题。

示例:

Bool

...

@objc func doThing() -> Bool{
    return true
}

答案 3 :(得分:0)

类似于我的答案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中也可以使用一个额外的变量。