First, what is Nsrunloop
Nsrunloop is the processing mode of the message mechanism
Nsrunloop's role is to have things done when the current Nsrunloop thread is working, nothing to do to make the current Nsrunloop thread hibernate
Nstimer is added by default to the current Nsrunloop, or you can manually create a new nsrunloop that you add to yourself
Nsrunloop is always in the loop detection, from the thread start to thread end, detect InputSource (such as click, double-click and so on) synchronization events, detect TimeSource synchronization events, detect the input source will execute the processing function, the first to generate a notification, Corefunction adds Runloop observers to the thread to listen for events that are intended to be handled when an event occurs.
In a single-threaded app, you don't need to pay attention to the run Loop, but it doesn't mean no. When the program starts, the system has added a run Loop to the main thread. It ensures that our main thread is in a "wait" state when it is running (rather than running it like some command-line programs), and if there is an event that is received (the timer is timed to or a message from another thread), the task is performed, or it is dormant.
Runloopmode is a collection that includes monitoring: event source, timer, and runloop to be notified observers
Patterns include:
Default mode: Almost all input sources (except Nsconnection) Nsdefaultrunloopmode mode
Mode: Handling Modal panels
Connection mode: Handling Nsconnection events, belonging to the system, the user basically do not
Event Tracking Mode: If the component drags the input source Uitrackingrunloopmodes does not handle timed events
Common modes Mode: Nsrunloopcommonmodes This is a set of generic patterns that can be configured. Associating input sources with this pattern also associates input sources with other patterns in the group.
Each time a run loop runs, you specify (either explicitly or implicitly) the run mode of the run loop. When the corresponding mode is passed to the run loop, only the input sources that corresponds to the pattern is monitored and the run loop is allowed to process the event (similar to this, only the observers corresponding to the pattern will be notified)
Cases:
1). At the same time as the timer and table, when the table is dragged, Runloop enters uitrackingrunloopmodes mode, does not handle timed events, the timer can not be processed at this time, So now add the timer to Nsrunloopcommonmodes mode (AddTimer formode)
2). When scroll a page to release, at this time connection will not receive the message, because scroll runloop uitrackingrunloopmodes mode, do not receive input source, at this time to modify the connection mode
[scheduleInRunLoop:[NSRunLoop currentRunLoop]forMode:NSRunLoopCommonModes];
About-(BOOL) RunMode: (nsstring ) mode beforedate: (nsdate ) date;
Specifies the Runloop mode to process the input source, the first input source, or the date end exit.
Pauses the current process of processing, instead processes the other input sources, and when date is set to [NSDate distantfuture]-(in the future, it will not arrive in time), the process of processing the paused current process is never exited unless the other input source is processed.
while(A){ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];}
At current A is yes, the current runloop will always receive processing other input sources, the current process does not continue processing, out of a is no, the current process continues
Performselector the execution principle of memory management is this execution [self performselector: @selector (method1:) WithObject:self.tableLayer Afterdelay:3 ]; , the system will add a reference count of Tablelayer to 1, the execution of this method, but also the Tablelayer reference count minus 1, because the delay at this time Tablelayer reference count is not reduced to 0, also caused the switching scene Dealloc method is not called, A memory leak has occurred.
Use the following functions:
[NSObject cancelPreviousPerformRequestsWithTarget:self]
Of course you can also use one of these:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil]
After this, the Dealloc method was successfully executed.
Inside the Touchbegan.
[self performSelector:@selector(longPressMethod:) withObject:nil afterDelay:longPressTime]
Then make a judgment in end or cancel if the time is long enough to press the call:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(longPressMethod:) object:nil]
How to cancel the began.
Second, Run loop and thread relationship:
The run loop of the main thread is started by default and is used to receive various input sources
For the second thread, the run loop is not started by default, and if you need more thread interaction you can configure and start it manually if the thread executes a task that has been determined for a long time.
Third, Run loop under what circumstances use:
Use ports or input sources to communicate with other threads//do not understand
Use timers in thread//if run is not started
The Loop,timer event is not responding.
Using Performselector in cocoa applications ... Method//should be performselector ... This method starts a thread and starts the run loop.
Let the thread perform a recurring task
Note: the creation and release of the timer must be in the same thread.
[[Nsrunloop Currentrunloop] Addtimer:timer formode:nsrunloopcommonmodes]; This method retain the reference count of the timer object.
Iv. about NSTimer1, Nstimer will be on-time trigger event?
The answer is no, and sometimes you will find that the actual trigger time is quite the same as the gap you imagined. 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.
The original text reads as follows:
A repeating timer reschedules itself based on the scheduled firing time, not the actual firing time. For example, if a timer is scheduled to fire at a particular time and every 5 seconds after that, the scheduled firing time will always fall on the original 5 second time intervals, even if the actual firing time gets delayed. If the firing time is delayed so far that it passes one or more of the scheduled firing times, the timer is fired only once for that time period; the timer is then rescheduled, after firing, for the next scheduled firing time in the future.
Let's take a look at a simple example:
- (void)applicationDidBecomeActive:(UIApplication *)application { SvTestObject *testObject2 = [[SvTestObject alloc] init]; [NSTimer scheduledTimerWithTimeInterval:1 target:testObject2 selector:@selector(timerAction:) userInfo:nil repeats:YES]; [testObject2 release]; NSLog(@"Simulate busy"); [self performSelector:@selector(simulateBusy) withObject:nil afterDelay:3]; } // 模拟当前线程正好繁忙的情况 - (void)simulateBusy { NSLog(@"start simulate busy!"); NSUInteger caculateCount = 0x0FFFFFFF; CGFloat uselessValue = 0; for (NSUInteger i = 0; i < caculateCount; ++i) { uselessValue = i / 0.3333; } NSLog(@"finish simulate busy!"); }
The example starts with a timer, which invokes the Timeraction method of the target every 1 seconds, followed by a method that simulates a busy thread (which is actually a large loop) after 3 seconds. After running the program, the output is as follows:
Observation results we can find that when the thread is idle when the timer message triggered or more accurate, but in 36 minutes 12 seconds to start the thread has been busy doing a lot of arithmetic, know 36 minutes 14 seconds the operation is over, this time the timer triggers the message, this thread busy process more than a cycle, But the timer did not trigger two messages in a row, but only triggered one time. After the thread is busy, the subsequent message firing time is still an integer multiplied with the time we specified at the beginning, which also proves from the side that the timer does not cause a delay in the subsequent triggering time due to the triggering delay.
Summary: The timer is not a real-time mechanism, there is a delay, and the degree of delay is related to the execution of the current thread.
2, Nstimer Why to add to Runloop will have a role
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.
Let's look at a small example:
- (void)applicationDidBecomeActive:(UIApplication *)application { [self testTimerWithOutShedule]; } - (void)testTimerWithOutShedule { NSLog(@"Test timer without shedult to runloop"); SvTestObject *testObject3 = [[SvTestObject alloc] init]; NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 target:testObject3 selector:@selector(timerAction:) userInfo:nil repeats:NO]; [testObject3 release]; NSLog(@"invoke release to testObject3"); } - (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"SvTimerSample Will resign Avtive!"); }
In this small example we create a new timer, specify a valid target and selector for it, and point out that the message is triggered after 1 seconds, and the result is as follows:
The observation found that this message will never be triggered for the simple reason that we did not add the timer to Runloop.
In summary: The timer must be added to the runloop before it takes effect.
3, Nstimer added to the runloop but the delay does not trigger the event
Why did you add it, but don't trigger the event according to the logic of the advance??? The main reasons are the following two:
1, 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, will it trigger on schedule as expected? Let's take a look at the following test procedure:
-(void) Applicationdidbecomeactive: (uiapplication *) application { [nsthread detachnewthreadselector:@ Selector (TESTTIMERSHEDULETORUNLOOP1) totarget:self Withobject:nil]; }//test the case of adding a timer to a non-running runloop-(void) TestTimerSheduleToRunloop1 { nsautoreleasepool *pool = [[Nsautorelea Sepool alloc] init]; nslog (@ "Test timer Shedult to a non-running runloop"); svtestobject *TESTOBJECT4 = [[Svtestobject alloc] init]; nstimer *timer = [[Nstimer alloc] initwithfiredate:[nsdate datewithtimeintervalsincenow:1] Interval:1 Target:testobject4 selector: @selector (timeraction:) Userinfo:nil Repeats:no]; [[nsrunloop Currentrunloop] Addtimer:timer Formode:nsdefaultrunloopmode]; //Open the following line of output Runloop to see that the timer has been added //nslog (@ "The thread ' s Runloop:%@", [Nsrunloop Currentrunloop]); //Open the following line, the thread's runloop will run, the timer will function //[[nsrunloop Currentrunloop] Rununtildate:[nsdate Datewithtimeintervalsincenow:3]]; &NBSP;[TESTOBJECT4 release]; nslog (@ "invoke release to TestObject4"); [pool release]; }-(void) Applicationwillresignactive: (uiapplication *) application { nslog (@ "Svtimersample would resign Avtive! ");}
In the above program, we create a new thread, then create a timer and add it to the thread's runloop, but the result is as follows:
Observing the running results, we find that this timer knows that execution exits and does not trigger the method we specify, if we put the above test program "//[[nsrunloop Currentrunloop" rununtildate:[nsdate Datewithtimeintervalsincenow:3]]; " The comment of this line is removed, then the timer will be correctly dropped using the method we specified.
2, 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 gave the old 21 barrels, but did not turn it, 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.
A deep understanding of Nsrunloop and Nstimer