Nstimer
A timer provides a to perform a delayed action or a periodic action. The timer waits until a certain time interval have elapsed and then fires, sending a specified message to a specified objec T (a timer is an object that can execute the method we specify at a certain point in the future from now on or periodically).
- Nstimer will retain you to add the object that invokes the method
- Nstimer is going to be added to Runloop to work.
- Nstimer will not be exactly the same as the time you specified.
- Nstimer even if it's added to Runloop, it doesn't have to be done the way you think.
What happened between Nstimer and the function object it called?
So the timer will execute one or more of the methods we specify at some point in the future, and this involves a question of how to ensure that the timer is valid when it triggers the specified event at some point in the future.
The workaround is simple, as long as the recipient of the method assigned to the timer is retain a copy, the system is actually doing the same. Whether it is a repetitive timer or a one-time timer will retain the receiver of its method, the difference between the two is that "a one-time timer will automatically invalidate itself after completion of the call, and the repetition of the timer will live forever, Until you show the invalidate it so far. "
On the one hand, Nstimer is often used as a member variable for a class, while Nstimer is initialized to specify self as target, which can easily cause circular references. On the other hand, if the timer is always in the validate state, its reference count will always be greater than 0.
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface tsetclass : nsobject - (void) Cleartimer;@end//TSETCLASS.M//Testruntime////Created by 15/6/1.//Copyright (c) 2015 58. All rights reserved.//#import "TsetClass.h" @interface tsetclass (){Nstimer *_mytimer;}@end @implementation tsetclass - (ID) Init {if( Self= [SuperInit]) {_mytimer = [Nstimer scheduledtimerwithtimeinterval:1Target SelfSelector@selector(Handletimer:) UserInfo:NilRepeatsYES]; }return Self; }- (void) Handletimer: (ID) sender{NSLog(@"%@ say:testtimer!", [ SelfClass]);} - (void) Cleartimer {[_mytimer invalidate]; _mytimer =Nil; }- (void) Dealloc {[ SelfCleartimer];NSLog(@"[Friend class] is dealloced"); }@end
Initializes a Tsetclass object outside the class and releases the friend after 5 seconds of delay (externally running in a non-arc environment)
TsetClass *f = [[Tset5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [f release]; });
我们所期待的结果是,初始化5秒后,f对象被release,f的dealloc方法被调用,在dealloc里面timer失效,对象被析构。但结果却是如此:
2015-06-0214: Geneva: Geneva. 229 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva: the. 231 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva: Ten. 227 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva: One. 228 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva:. 231 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva:. 227 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva:. 229 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva:. 231 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva:. 229 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva:. 231 Testruntime[8883:135129] Tsetclass say:Testtimer!2015-06-0214: Geneva:. the Te...
What is this for? Mainly because from the point of view of the timer, the timer thinks that the caller (Friend object) will enter the Dealloc when it is refactored, and in Dealloc can stop the timer's timing and release the memory, but from friend's point of view, he thinks that the timer does not stop the timing, Then I never got a chance to get into dealloc. Circular references, waiting for each other, the descendants of the endless also. The crux of the problem is that-(void) The invocation of the Cleantimer function is not opportune, and obviously cannot be placed in the caller's dealloc. A good solution is to open this function and let friend's caller explicitly invoke it to clean up the scene. As follows:
TsetClass *f = [[Tset5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [f clearTimer]; [f release];});
To this timer's circular reference is finished!!!
All in all: the timer will retain its target, and we need to be careful with the target's life cycle problem, especially the repetitive timer. (after Nstimer initialization, Self's retaincount plus 1.) Then we need to execute [timer invalidate] before releasing this class; otherwise, the Dealloc method of the class will not be executed. )
So you're going to use the timer?
Nstimer is not a real-time system, so the timing of the actual triggering events of the timer, whether it be a one-off or periodic, may be in and out of our expectation. The size of the gap is related to the current execution of our program, such as the possibility that the program is multi-threaded, and your timer is only added to a certain thread of the runloop of a specified Runloopmode, because multithreading is usually performed by ticks, And the mode of each execution may vary with the actual situation. Suppose you add a timer that triggers an event after 2 seconds, but when the current thread executes a continuous operation (such as the processing of big data blocks) at that time, the timer is deferred until the continuous operation is executed. A repetitive timer encounters this situation, and if the delay exceeds a period, it is merged with the subsequent trigger, which is triggered only once during a cycle. However, regardless of how far the timer's triggering time is delayed, the trigger time of the timer behind him is always multiples of the first time the timer is added.
When the thread is idle, the timer message is triggered or more accurate.
Why Nstimer is added to Runloop to be useful
In the previous example, we used a convenient method, which actually did two things: Create a timer first, and then add the timer to the default mode of the current runloop. It is this convenient method that gives us the illusion that the timer can take effect as long as it is created, we can of course create a timer ourselves and then manually add it to the specified mode of the specified runloop.
Nstimer is also a resource, if you have seen multithreading become a guideline document, we will find all of the source if it has to work, we have to add to the Runloop. The same kind of resource, if you want to work, it must be added to the runloop to be effective again. If a runloop does not contain any resources, it exits immediately when the Runloop is run. You might say that the main thread of our app Runloop we didn't add any resources to it and why it was running well. We do not add, does not mean that the framework is not added, if you are interested you can print the main thread of the Runloop, you will find a lot of resources.
Nstimer was added to the Runloop, but the delay did not trigger the event.
- Runloop is running
Every thread has its own runloop, the main thread of the program will automatically make Runloop effective, but for our own new thread, its runloop will not run itself, when we need to use its runloop, we have to start.
So if we add a timer to a non-mainline runloop, it won't trigger on schedule as expected.
- Mode is correct
In front of us to add runloop, we can see that there is a parameter runloopmode, this parameter is why?
As mentioned earlier, in order for the timer to take effect, we have to add it to the specified mode of the specified runloop, usually the Defalut mode of the main thread. But sometimes we do, but still find that the timer still does not trigger the event. What is this for?
This is because when the timer is added, we need to specify a mode, because the runloop of the same thread can only be in one mode at any time when it is running. So only when the program is in this mode can the timer get the chance to trigger the event.
To cite an inappropriate example, we say that the brothers are representative of the runloop of the Mode,timer on behalf of their own bucket, and then a group of people to the line to fetch water, only a faucet, then the same moment, there must be only one person in the state of access. In other words, although you give the old 21 barrels, but not the turn, then you have to wait, only when the turn of your bucket to come in handy
All in all: for the timer to take effect, you must ensure that the thread's runloop is started and that its running Runloopmode match.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Three scenarios in which iOS is prone to circular referencing nstimer and corresponding usage (i)