Alternative to performSelector in Swift?

Solution 1:

Using closures

class A {
    var selectorClosure: (() -> Void)?

    func invoke() {
        self.selectorClosure?()
    }
}

var a = A()
a.selectorClosure = { println("Selector called") }
a.invoke()

Note that this is nothing new, even in Obj-C the new APIs prefer using blocks over performSelector (compare UIAlertView which uses respondsToSelector: and performSelector: to call delegate methods, with the new UIAlertController).

Using performSelector: is always unsafe and doesn't play well with ARC (hence the ARC warnings for performSelector:).

Solution 2:

As of Xcode 7, the full family of performSelector methods are available in Swift, including performSelectorOnMainThread() and performSelectorInBackground(). Enjoy!

Solution 3:

Approach A

Use NSThread.detachNewThreadSelector, good thing about this approach is that we can attach object to the message. Example code in ViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let delay = 2.0 * Double(NSEC_PER_SEC)
    var time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
    dispatch_after(time, dispatch_get_main_queue(), {
        NSThread.detachNewThreadSelector(Selector("greetings:"), toTarget:self, withObject: "sunshine")
        })
}

func greetings(object: AnyObject?) {
    println("greetings world")
    println("attached object: \(object)")
}

Console log:

greetings world

attached object: sunshine

Approach B

This alternative was discovered earlier, I have also tested on device and simulator. The idea is to use following method of UIControl:

func sendAction(_ action: Selector, to target: AnyObject!, forEvent event: UIEvent!)

Example code in ViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    
    var control: UIControl = UIControl()
    control.sendAction(Selector("greetings"), to: self, forEvent: nil) // Use dispatch_after to invoke this line as block if delay is intended 
}

func greetings() {
    println("greetings world")
}

Console log:

greetings world

Approach C

NSTimer

class func scheduledTimerWithTimeInterval(_ seconds: NSTimeInterval,
                                      target target: AnyObject!,
                                 selector aSelector: Selector,
                                  userInfo userInfo: AnyObject!,
                                    repeats repeats: Bool) -> NSTimer!