Last active
June 29, 2020 20:45
-
-
Save iby/49a46b785518fb72f0b2 to your computer and use it in GitHub Desktop.
Block / method / function comparison in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
// Some interesting observations on block comparing. Apparently swift nor objective c don't allow comparing closures | |
// due to the complexity of the process and because of compiler optimisations… bla bla. But it seems to be possible | |
// to do this using conventions blocks, aka the objective c ones that can be cast as objects. The interesting part | |
// is how swift freely casts SwfBlock to ObjBlock, yet in reality two casted SwfBlock blocks will always be different | |
// values, while ObjBlocks won't. When we cast ObjBlock to SwfBlock, the same thing happens to them, they become two | |
// different values. So, in order to preserve the reference, this sort of casting should be avoided. | |
typealias SwfBlock = () -> () | |
typealias ObjBlock = @convention(block) () -> () | |
func testSwfBlock(a: SwfBlock, _ b: SwfBlock) -> String { | |
let objA = unsafeBitCast(a as ObjBlock, AnyObject.self) | |
let objB = unsafeBitCast(b as ObjBlock, AnyObject.self) | |
return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)" | |
} | |
func testObjBlock(a: ObjBlock, _ b: ObjBlock) -> String { | |
let objA = unsafeBitCast(a, AnyObject.self) | |
let objB = unsafeBitCast(b, AnyObject.self) | |
return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)" | |
} | |
func testAnyBlock(a: Any?, _ b: Any?) -> String { | |
if !(a is ObjBlock) || !(b is ObjBlock) { | |
return "a nor b are ObjBlock, they are not equal" | |
} | |
let objA = unsafeBitCast(a as! ObjBlock, AnyObject.self) | |
let objB = unsafeBitCast(b as! ObjBlock, AnyObject.self) | |
return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)" | |
} | |
class Foo | |
{ | |
lazy var swfBlock: ObjBlock = self.swf | |
func swf() { print("swf") } | |
@objc func obj() { print("obj") } | |
} | |
let swfBlock: SwfBlock = { print("swf") } | |
let objBlock: ObjBlock = { print("obj") } | |
let foo: Foo = Foo() | |
print(testSwfBlock(swfBlock, swfBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false | |
print(testSwfBlock(objBlock, objBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false | |
print(testObjBlock(swfBlock, swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false | |
print(testObjBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true | |
print(testAnyBlock(swfBlock, swfBlock)) // a nor b are ObjBlock, they are not equal | |
print(testAnyBlock(objBlock, objBlock)) //a is ObjBlock: true, b is ObjBlock: true, objA === objB: true | |
print(testObjBlock(foo.swf, foo.swf)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false | |
print(testSwfBlock(foo.obj, foo.obj)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false | |
print(testAnyBlock(foo.swf, foo.swf)) // a nor b are ObjBlock, they are not equal | |
print(testAnyBlock(foo.swfBlock, foo.swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment