Murad Sofiyev
Murad Sofiyev

Reputation: 791

How can I send parameter with "#selector"

class TimerFactory {
    var second: Int = 0;
    var timer: Timer = Timer();

    init(second: Int) {
        if(second > 0) {
            self.second = second;
        }
    }

    func runTimer(_ vc: ViewController) -> Void {

        self.timer = Timer.scheduledTimer(timeInterval: 1, target: vc,   selector: (#selector(vc.updateViewTimer)), userInfo: nil, repeats: true)
    }
}


class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

    }

    @objc func updateViewTimer() {
        print("Hello")
    }
}

extension ViewController {
    @IBAction func startCounter(_ sender: UIBarButtonItem) {
        let timer = TimerFactory(second: 60);
        timer.runTimer(self)
    }
}

Sory for my question I'm new in SWIFT But i want to create timer but timer selector call my ViewController updateViewTimer but this code return false but self.test work What is problem in here?

Upvotes: 0

Views: 730

Answers (2)

staticVoidMan
staticVoidMan

Reputation: 20234

Your target should be vc as that's where the timer will look for the method updateViewTimer.

func runTimer(_ vc: ViewController) -> Void {
    self.timer = Timer.scheduledTimer(timeInterval: 1,
                                      target: vc,
                                      selector: (#selector(vc.updateViewTimer)),
                                      userInfo: nil,
                                      repeats: true)
}

When target was self it referred to TimerFactory.


EDIT (based on comments):

func runTimer(_ vc: ViewController) -> Void {
    self.timer = Timer.scheduledTimer(timeInterval: 1,
                                      target: vc,
                                      selector: (#selector(vc.updateViewTimer(timer:))),
                                      userInfo: self,
                                      repeats: true)
}

@objc func updateViewTimer(_ timer: Timer) {
    if let factory = timer.userInfo as? TimerFactory {
        factory.second -= 1

        print(factory.second)

        if factory.second == 0 {
            print("completed")
            timer.invalidate()
        }
    }        
}

EDIT 2 (suggestion):

If you plan to reuse TimerFactory in another class then you'd need to ensure that updateViewTimer() method exists in this class or else the code will crash.

Instead... I would rather suggest a more robust approach that will use a closure and drop the dependency on the updateViewTimer(_:) method:

func runTimer(_ vc: ViewController, updateHandler: @escaping (_ second: Int)->Void) -> Void {
    self.timer = Timer.scheduledTimer(withTimeInterval: 1,
                                      repeats: true,
                                      block: { (timer) in
                                        self.second -= 1
                                        updateHandler(self.second)

                                        if self.second == 0 {
                                            timer.invalidate()
                                        }
    })
}

func startCounter() {
    let timer = TimerFactory(second: 10);
    timer.runTimer(self) { (second) in
        print(second)

        if second == 0 {
            print("completed")
        }
    }
}

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100503

The problem is that the target should contain the method to be invoked , in timer declaration you set it to self , so it will look for a method inside that class , can you try

 self.timer = Timer.scheduledTimer(timeInterval: 1, target: vc ,   selector: (#selector(vc.updateViewTimer)), userInfo: nil, repeats: true)

Upvotes: 0

Related Questions