In ObjC you could simply invoke a class method using the class method from NSObject
.
[Machine performSelector:@selector(calculate:) withObject:num];
But how do you do this in Swift 2.2?
@objc(Machine) // put it here, so you can simply copy/paste into Playground
class Machine: NSObject {
static func calculate(param: NSNumber) -> String {
if param.integerValue > 5 {
return "42"
}
return "42" // there is only 1 answer to all the questions :D
}
}
if let aClass = NSClassFromString("Machine") {
let sel = #selector(Machine.calculate(_:))
let num = NSNumber(integer: 1337)
let answer = aClass.performSelector(sel, withObject: num) // compiler error
// let answer = aClass.calculate(num) // <-- this works
print(answer)
}
With this code I'm getting the following compiler error:
error: cannot invoke 'performSelector' with an argument list of type '(Selector, withObject: NSNumber)'
What am I missing here?
In this tutorial, we will learn about Swift Classes and we'll also learn to create objects with the help of examples. Swift is also an object-oriented programming language. And, like other oop languages, it also supports the concept of objects and classes. An object is simply a collection of data (variables) and methods (functions).
In Objective-C, classes are the only types that can define methods. In Swift, you can choose whether to define a class, structure, or enumeration, and still have the flexibility to define methods on the type you create.
Type methods are similar to class methods in Objective-C. The fact that structures and enumerations can define methods in Swift is a major difference from C and Objective-C. In Objective-C, classes are the only types that can define methods.
Unlike other programming languages, Swift doesn’t require you to create separate interface and implementation files for custom structures and classes. In Swift, you define a structure or class in a single file, and the external interface to that class or structure is automatically made available for other code to use.
AnyClass
does not conform to NSObjectProtocol
out of the box. I had to cast aClass
as NSObjectProtocol
to use performSelector
(performSelector:withObject:
is bridged to Swift as a method on NSObjectProtocol
):
Swift 3:
if let aClass = NSClassFromString("Machine") {
let sel = #selector(Machine.calculate(param:))
let num = NSNumber(value: 1337)
if let myClass = aClass as? NSObjectProtocol {
if myClass.responds(to: sel) {
let answer = myClass.perform(sel, with: num).takeRetainedValue() // this returns AnyObject, you may want to downcast to your desired type
print(answer) // "42\n"
}
}
}
Swift 2.x:
(aClass as! NSObjectProtocol).performSelector(sel, withObject: num) // Unmanaged<AnyObject>(_value: 42)
A little bit safer:
if let aClass = NSClassFromString("Machine") {
let sel = #selector(Machine.calculate(_:))
let num = NSNumber(integer: 1337)
if let myClass = aClass as? NSObjectProtocol {
if myClass.respondsToSelector(sel) {
let answer = myClass.performSelector(sel, withObject: num).takeUnretainedValue()
print(answer) // "42\n"
}
}
}
performSelector
returns an Unmanaged
object, that's why takeUnretainedValue()
(or optionally takeRetainedValue()
if you want to transfer memory ownership) are required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With