Claypark
(Park Jeong Soo)
1
Hi, I am suffering from one problem.
In swift 4.2, I tried to perform below code.
class A: NSObject {
func performClosure(closure: @escaping () -> ()) {
perform(#selector(performClosureOnClientThread(_:)), with: closure)
}
@objc func performClosureOnClientThread(_ closure: () -> ()) {
closure()
}
}
and main
let a = A()
let closure = {
print(good)
}
a.performClosure(closure)
but, It occurred crash.
Ultimately, I want to execute the selector using execute perform(: on:with:waitUntilDone:modes) on the executed thread. Can't I use the method('perform') in swift?
mayoff
(Rob Mayoff)
2
This is a tricky problem. It's happening because perform(_:with:) and Selector use the Objective-C runtime. The Objective-C runtime does not check types strictly like Swift does.
The perform(_:with:) method of NSObject takes two arguments: a Selector and an Any!.
Swift will automatically convert an object of type () -> () (the type of closure) to Any! for you. All Selectors have the same type, so Swift accepts #selector(performClosureOnClientThread(_:)) for the Selector argument.
However, perform(_:with:) expects that the Selector selects a method of type (Any!) -> Unmanaged<AnyObject>!.
What is the type of your performClosureOnClientThread(_:) method? Its type is (() -> ()) -> () (takes a closure, returns Void).
Is type (() -> ()) -> () the same as type (Any!) -> Unmanaged<AnyObject>!? No, they are not the same. In particular, () -> () is passed in a different way than Any!. When your performClosureOnClientThread method tries to use the closure argument, it fails, because it wasn't passed a () -> ().
To fix the problem,, change your performClosureOnClientThread(_:) method to have the type that perform(_:with:) expects.
@objc func performClosureOnClientThread(_ closure: Any!) -> Unmanaged<AnyObject>! {
if let closure = closure as? () -> () {
closure()
}
return nil
}
2 Likes
mayoff
(Rob Mayoff)
3
Also, I think using perform(_:on:with:waitUntilDone:modes:) is suspicious. It only works for a thread that runs a Runloop, and usually only the main thread runs a RunLoop. You might be better off using a DispatchQueue or an OperationQueue.
If you describe your goal at a higher level, we might be able to give you better advice.
1 Like
Claypark
(Park Jeong Soo)
4
Thank you! you are savior for me.