Swift 闭包作为 AnyObject。

11

我正在尝试使用这个方法:class_addMethod(),在Obj-c中可以像这样使用:

class_addMethod([self class], @selector(eventHandler), imp_implementationWithBlock(handler), "v@:");

我在Swift中这样使用它:

class_addMethod(NSClassFromString("UIBarButtonItem"), "handler", imp_implementationWithBlock(handler), "v@:")

正如你可能已经发现的那样,它是UIBarButtonItem的扩展。

imp_implementationWithBlock接受类型为AnyObject!的参数。

我该如何将()->()强制转换为AnyObject

我尝试像这样进行强制转换:handler as AnyObject,但它给出了一个错误,说:()->()不遵循协议'AnyObject'


你尝试使用reinterpretCast()了吗? - Romain
7个回答

11

如何将 ()->() 转换为 AnyObject

警告:此答案包括 Swift 中未经记录和不安全的特性。我怀疑这可能无法通过 AppStore 的审核。

let f: ()->() = {
    println("test")
}

let imp = imp_implementationWithBlock(
    unsafeBitCast(
        f as @objc_block ()->(),
        AnyObject.self
    )
)

"f"是什么?它是闭包吗? - Arbitur
Obj-C 代码可以将 Blocks 传递给 Swift 的 AnyObject 类型参数。 - rintaro
如果您想将此内容作为扩展添加,可以自由使用它:extension UIBarButtonItem { convenience init(title: String?, style: UIBarButtonItemStyle, handler: ()->()) { let imp = imp_implementationWithBlock(unsafeBitCast(handler as @objc_block ()->(), AnyObject.self)) class_addMethod(UIBarButtonItem.self, "handler", imp, "v@:") self.init(title: title, style: style, target: nil, action: "handler") self.target = self } } - Arbitur
嗯,也许这个方法会被创建给每个人,但只有我添加处理程序的人才会尝试调用它。但我会进一步测试它。 - Arbitur
1
应该使用 @convention 而不是 @objc_block - onmyway133
显示剩余2条评论

8
您可以编写一个包装器,然后将其传递给函数。
class ObjectWrapper<T> {
    let value :T
    init(value:T) {
       self.value = value
    }
}

let action = ObjectWarpper(value: {()->() in    
    // something
})

6

在Swift 2中,您应该使用@convention而不是@objc_block。请参见类型属性

func swizzle(type: AnyClass, original: Selector, methodType: MethodType, block: () -> Void) {
    let originalMethod = method(type, original: original, methodType: methodType)

    let castedBlock: AnyObject = unsafeBitCast(block as @convention(block) () -> Void, AnyObject.self)

    let swizzledImplementation = imp_implementationWithBlock(castedBlock)
    // More code goes here
}

4
您不能这样做,只能将其转换为Any
  • AnyObject可以表示任何类类型的实例。
  • Any可以表示任何类型的实例,包括函数类型。

摘自Apple Inc.《The Swift Programming Language》。iBooks. https://itun.es/de/jEUH0.l


但是有没有其他任何方式可以做到这一点呢? - Arbitur
你尝试过传递 Selector("handler") 吗?你能展示一下 imp_implementationWithBlock 的签名吗? - qwerty_so
错误不在选择器部分,而是imp_implementationWithBlock()引起了混淆。 - Arbitur
imp_implementationWithBlock(block: AnyObject!) 函数接受一个 AnyObject 类型参数并返回一个 IMP。 - Arbitur
它可以在Objective-C运行时引用中找到。 - Arbitur

2
这对我有用:

这对我有用:

let myBlock: @objc_block () -> Void = { 
}
var mf : AnyObject = unsafeBitCast(myBlock, AnyObject.self)

1
在Swift 4.x中(我认为在3.x中也适用),仅将闭包声明为@convention(block)就足以解决兼容性问题:
// define the new implementation
let handler: @convention(block) (UIBarButtonItem) -> Void = { _ in }

// inject it into the class
class_addMethod(NSClassFromString("UIBarButtonItem"), sel_registerName("handler"), imp_implementationWithBlock(handler), "v@:")

尽管从Swift 3开始,如果引用来自Objective-C,则 AnyObject 已转换为 Any ,因此即使没有 @convention(block)部分,代码也会编译,但是在运行时它会崩溃,因为编译器不会将Swift闭包转换为Objective-C块。


0

使用 Any 对象 (所有类型隐式遵守的协议)

 let aBlock: (view: View) -> Void = { view in /**/ }

 let block:Any? = aBlock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接