Использование NSTimer в Swift

в этом сценарии timerFunc () никогда не вызывается. Что я упускаю?

class AppDelegate: NSObject, NSApplicationDelegate {

    var myTimer: NSTimer? = nil

    func timerFunc() {
        println("timerFunc()")
    }

    func applicationDidFinishLaunching(aNotification: NSNotification?) {
        myTimer = NSTimer(timeInterval: 5.0, target: self, selector:"timerFunc", userInfo: nil, repeats: true)
    }
}

10 ответов


Вы можете создать запланированные таймер, который автоматически добавляет себя в runloop и начинает стрелять:

NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "timerDidFire:", userInfo: userInfo, repeats: true)

или вы можете сохранить свой текущий код и добавить таймер в runloop, когда будете готовы к нему:

let myTimer = NSTimer(timeInterval: 0.5, target: self, selector: "timerDidFire:", userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(myTimer, forMode: NSRunLoopCommonModes)

Я использую аналогичный подход к люку. Только предостережение для людей, которые являются "частными методами" пуристов:

Не делайте обратный вызов приватным в Swift.

Если вы пишете:

private func timerCallBack(timer: NSTimer){

..

вы получите:

timerCallBack:]: непризнанной селектор послал экземпляр... Прекращения приложения из-за необработанных исключений 'NSInvalidArgumentException'


NSTimer не запланированы автоматически, если вы не используете NSTimer.scheduledTimerWithTimeInterval:

myTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "timerFunc", userInfo: nil, repeats: true)

как указали Drewag и Ryan, вам нужно создать запланированный таймер (или запланировать его самостоятельно), проще всего создать его по расписанию уже с:

myTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "timerFunc:", userInfo: nil, repeats: true)

вам также нужно изменить свое определение timerFunc (и связанного селектора), чтобы принять аргумент и закончить":"

func timerFunc(timer:NSTimer!) {
    ...
}

Swift 3.0 синтаксис для выполнения цикла thingy:

RunLoop.current.add(myTimer, forMode: .commonModes)

Для Swift 3

var timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(ViewController.updateTimer), userInfo: nil, repeats: true);
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)

это немного кода, который демонстрирует, как вызвать функцию (с задержкой) с параметром и без него.

используйте это в новом проекте в xCode (singleViewApplication) и поместите код в стандартный viewController:

class ViewController: UIViewController {

    override func viewDidLoad() {

        super.viewDidLoad()

        NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: Selector("delayedFunctionWithoutParameter:"), userInfo: nil, repeats: false)

        let myParameter = "ParameterStringOrAnyOtherObject"

        NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: Selector("delayedFunctionWithParameter:"), userInfo: myParameter, repeats: false)
    }

    // SIMPLE TIMER - Delayed Function Call
    func delayedFunctionWithoutParameter(timer : NSTimer) {
        print("This is a simple function beeing called without a parameter passed")
        timer.invalidate()
    }

    // ADVANCED TIMER - Delayed Function Call with a Parameter
    func delayedFunctionWithParameter(timer : NSTimer) {

        // check, wether a valid Object did come over
        if let myUserInfo: AnyObject = timer.userInfo {
            // alternatively, assuming it is a String for sure coming over
            // if let myUserInfo: String = timer.userInfo as? String {
            // assuming it is a string comming over
            print("This is an advanced function beeing called with a parameter (in this case: \(myUserInfo)) passed")
        }

        timer.invalidate()
    }
}

обратите внимание, что в любом случае вы должны реализовать отложенную функцию с параметром (timer : NSTimer), чтобы иметь возможность аннулировать (завершить, завершить) таймер. И с passend "timer" у вас также есть доступ к userInfo (и там вы можете поместить любой объект, а не только строковые объекты, а также типы коллекций, такие как массивы и словари).

оригинальные документы Apple говорят "" - > таймер передает себя в качестве аргумента, таким образом, метод примет следующий шаблон: - (void)timerFireMethod: (NSTimer *)таймер Читайте полностью -> здесь


scheduledTimerWithTimeInterval ставил таймер на другой RunLoop во время запуска приложения. Если я просто инициализирую таймер, а затем использую NSRunLoop.mainRunLoop().addTimer(myTimer, forMode:NSDefaultRunLoopMode) вместо этого, он отлично работает.


С swift3, вы можете запустить его с,

var timer: Timer?
func startTimer() {

    if timer == nil {
        timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.loop), userInfo: nil, repeats: true)
    }
}

func stopTimer() {
    if timer != nil {
        timer?.invalidate()
        timer = nil
    }
}

func loop() {
    //do something
}

чтобы сделать это с помощью метода, предложенного OP, вам нужно добавить его в цикл выполнения:

myTimer = NSTimer(timeInterval: 5.0, target: self, selector:"timerFunc", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(myTimer, forMode:NSDefaultRunLoopMode)

в документации также говорится, что цель должна принять аргумент, но она работает без него.

func timerFireMethod(timer: NSTimer) { }