Im trying to use this method: class_addMethod()
which in Obj-c is used like this:
class_addMethod([self class], @selector(eventHandler), imp_implementationWithBlock(handler), "v@:");
And Im using it like this in Swift:
class_addMethod(NSClassFromString("UIBarButtonItem"), "handler", imp_implementationWithBlock(handler), "v@:")
It is an extension for UIBarButtonItem
as you might have figured out.
imp_implementationWithBlock
takes a parameter of type AnyObject!
How can I cast ()->()
into AnyObject
?
I've tried to cast it like this: handler as AnyObject
but it gives me an error saying: ()->() does not conform to protocol 'AnyObject'
How can I cast ()->()
into AnyObject
?
Warning: This answer includes undocumented and unsafe feature in Swift. I doubt this passes AppStore review.
let f: ()->() = {
println("test")
}
let imp = imp_implementationWithBlock(
unsafeBitCast(
f as @objc_block ()->(),
AnyObject.self
)
)
You could write a wrapper, then pass it to the function
class ObjectWrapper<T> {
let value :T
init(value:T) {
self.value = value
}
}
let action = ObjectWarpper(value: {()->() in
// something
})
In Swift 2, you should use @convention
instead of @objc_block
. See Type Attribute
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
}
You can't. You can only cast it to Any
.
AnyObject
can represent an instance of any class type.
Any
can represent an instance of any type at all, including function types.
Apple Inc. „The Swift Programming Language.“ iBooks. https://itun.es/de/jEUH0.l
This has worked for me:
let myBlock: @objc_block () -> Void = {
}
var mf : AnyObject = unsafeBitCast(myBlock, AnyObject.self)
Use Any
object (The protocol to which all types implicitly conform)
let aBlock: (view: View) -> Void = { view in /**/ }
let block:Any? = aBlock
In Swift 4.x (I think works in 3.x too), simply declaring the closure as @convention(block)
should be enough to address compatibility thing:
// 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@:")
Though, starting with Swift 3, AnyObject
was converted to Any
if the reference comes from Objective-C, so the code will compile even without the @convention(block)
part, however it will crash at runtime as the compiler will not convert the Swift closure to an Objective-C block.