56

私はNSTimerこのようなものを使用しています:

timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:self selector:@selector(tick) userInfo:nil repeats:YES];

もちろん、NSTimer保持サイクルを作成するターゲットを保持します。さらに、 UIViewController ではないので、タイマーを無効にしてサイクルを中断できるselfようなものはありません。viewDidUnloadしたがって、代わりに弱い参照を使用できるかどうか疑問に思っています。

__weak id weakSelf = self;
timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:weakSelf selector:@selector(tick) userInfo:nil repeats:YES];

タイマーを無効にする必要があると聞いたことがあります(実行ループから解放すると思います)。しかし、dealloc でそれを行うことができますよね?

- (void) dealloc {
    [timer invalidate];
}

これは実行可能なオプションですか?人々がこの問題に対処する多くの方法を見てきましたが、これは見たことがありません。

4

10 に答える 10

5

Swift では、WeakTimerヘルパー クラスを定義しました。

/// A factory for NSTimer instances that invoke closures, thereby allowing a weak reference to its context.
struct WeakTimerFactory {
  class WeakTimer: NSObject {
    private var timer: NSTimer!
    private let callback: () -> Void

    private init(timeInterval: NSTimeInterval, userInfo: AnyObject?, repeats: Bool, callback: () -> Void) {
      self.callback = callback
      super.init()
      self.timer = NSTimer(timeInterval: timeInterval, target: self, selector: "invokeCallback", userInfo: userInfo, repeats: repeats)
    }

    func invokeCallback() {
      callback()
    }
  }

  /// Returns a new timer that has not yet executed, and is not scheduled for execution.
  static func timerWithTimeInterval(timeInterval: NSTimeInterval, userInfo: AnyObject?, repeats: Bool, callback: () -> Void) -> NSTimer {
    return WeakTimer(timeInterval: timeInterval, userInfo: userInfo, repeats: repeats, callback: callback).timer
  }
}

そして、次のように使用できます。

let timer = WeakTimerFactory.timerWithTimeInterval(interval, userInfo: userInfo, repeats: repeats) { [weak self] in
  // Your code here...
}

返さNSTimerれる には への弱い参照があるため、 でそのメソッドをself呼び出すことができます。invalidatedeinit

于 2014-12-07T19:53:43.997 に答える
3

weakSelfが弱いことは問題ではありません。タイマーはオブジェクトを引き続き保持するため、保持サイクルがまだ存在します。タイマーは実行ループによって保持されるため、タイマーへの弱いポインターを保持することができます (私はお勧めします):

NSTimer* __weak timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target: self selector:@selector(tick) userInfo:nil repeats:YES];

あなたのやり方は正しいです。

于 2013-05-29T19:21:32.820 に答える
0

スイフト4版。無効化は、dealloc の前に呼び出す必要があります。

class TimerProxy {

    var timer: Timer!
    var timerHandler: (() -> Void)?

    init(withInterval interval: TimeInterval, repeats: Bool, timerHandler: (() -> Void)?) {
        self.timerHandler = timerHandler
        timer = Timer.scheduledTimer(timeInterval: interval,
                                     target: self,
                                     selector: #selector(timerDidFire(_:)),
                                     userInfo: nil,
                                     repeats: repeats)
    }

    @objc func timerDidFire(_ timer: Timer) {
        timerHandler?()
    }

    func invalidate() {
        timer.invalidate()
    }
}

使用法

func  startTimer() {
    timerProxy = TimerProxy(withInterval: 10,
                            repeats: false,
                            timerHandler: { [weak self] in
                                self?.fireTimer()
    })
}

@objc func fireTimer() {
    timerProxy?.invalidate()
    timerProxy = nil
}
于 2018-02-15T12:13:22.473 に答える
0

Swift を使用している場合は、自動キャンセル タイマーがあります。

https://gist.github.com/evgenyneu/516f7dcdb5f2f73d7923

タイマーは で自動的にキャンセルされdeinitます。

var timer: AutoCancellingTimer? // Strong reference

func startTimer() {
  timer = AutoCancellingTimer(interval: 1, repeats: true) {
    print("Timer fired")
  }
}
于 2015-07-04T05:11:07.640 に答える