The most commonly used timing method for daily development is NSTimer, and CADisplayLink and GCDTimer are still a bit cumbersome to write. But there’s an important problem with repetitive tasks: When to stop the task. Also, NSTimer often has problems with circular references, so consolidate records.

Case 1:

The Timer strongly holds the target, so if we write a VC that holds a Timer, and the Timer is initialized with VC as the target, then we’re circular referencing

Results:

Circular situation:

In this case, even if we pop TestVC, TestVC dealloc still won’t appear, and the console will print unlimited A

Solution:

Call timer.invalidate() when appropriate to manually stop the timer and break the loop:

Situation 2:

So if we don’t hold this timer, in some method the timer is just a local variable and vc is the target, so testVC doesn’t grab a reference to the timer, can we avoid circular references?

Results:



Still not released. If the invalidate method of the timer is not called, the timer cannot be released by Runloop, and the target held by the timer cannot be released. (The scheduledTimer method is equivalent to initTimer() + fire() + runloop.addTimer())

Solution:

Mark the timer and manually stop it when appropriate

Comprehensive solution: Stop the Timer when appropriate

Use the intermediate target:



We’re using an InnerTarget, when we initialize the Timer, the InnerTarget has a weak hold on testvc, it has a selector, the weak hold on testVC, the Timer has a strong reference to the InnerTarget, in the selector of the InnerTarget, Weak Target is used to call the selector method so that testVC can dealloc normally. When testVC is released, the InnerTarget is aware of it. Stopping the Timer automatically releases the Timer:

Try again:





Normal release


The new block initialization Timer method in iOS10 solves the problem that the Timer strongly references the target, but does not solve the problem that the Runloop holds the Timer. The Timer still needs to be manually released

Try to initialize the Timer with stopTarget+block, using the same idea as Target:

Use:



It can release normally

Disadvantages:

Since the block counts the inner object by one +1, if self is present in the block, use Weak self. Otherwise, circular references will still occur:

Reference:



Use weak/unowned self to break the citation problem:

Reference: