天天看點

将NSTimer加入至RunLoop中的兩種方法差别

- (

BOOL

)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

//用NSObject的方法建立一個多線程

[self performSelectorInBackground:@selector(multiThread) withObject:nil];

self.window.backgroundColor = [UIColor whiteColor];

[self.window makeKeyAndVisible];

return

YES;

}

- (

void

)multiThread

{

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

if

(![NSThread isMainThread]) {

// 第1種方式

//此種方式建立的timer已經加入至runloop中

//        [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

//保持線程為活動狀态,才幹保證定時器運作

//        [[NSRunLoop currentRunLoop] run];//已經将nstimer加入到NSRunloop中了

//第2種方式

//此種方式建立的timer沒有加入至runloop中

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

//将定時器加入到runloop中

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

[[NSRunLoop currentRunLoop] run];

NSLog(@

"多線程結束"

);

}

[pool release];

}

- (

void

)timerAction

{

//定時器也是在子線程中運作的

if

(![NSThread isMainThread]) {

NSLog(@

"定時器"

);

}

}

了解run loop後,才幹徹底了解NSTimer的實作原理,也就是說NSTimer實際上依賴run loop實作的。

先看看NSTimer的兩個經常用法:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget

selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo; //生成timer但不運作

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget

selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo; //生成timer而且納入目前線程的run loop來運作

NSRunLoop與timer有關方法為:

- (void)addTimer:(NSTimer *)timer forMode:(NSString *)mode; //在run

loop上注冊timer

主線程已經有run loop,是以NSTimer一般在主線程上執行都不必再調用addTimer:。但在非主線程上執行必須配置run loop。該線程的main方法示範樣例代碼例如以下:

- (void)main

{

  NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timer:) userInfo:nil repeats:YES];

  NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

  [runLoop addTimer:myTimer forMode:NSDefaultRunLoopMode]; //實際上這步是不須要,scheduledTimerWithTimeInterval已經納入目前線程執行。

假設使用timerWithTimeInterval則須要

  while (condition)

    [runLoop run];

}

實際上這個線程無法退出,由于有timer事件須要處理。[runLoop run]會一直無法傳回。

解決的方法就是設定一個截止時間:

[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; //每隔10秒檢查下線程循環條件,當然時間值能夠依據實際情況來定。

我們通常在主線程中使用NSTimer。有個實際遇到的問題須要注意。當滑動界面時,系統為了更好地處理UI事件和滾動顯示,主線程runloop會臨時停止處理一些其他事件,這時主線程中執行的NSTimer就會被暫停。解決的方法就是改變NSTimer執行的mode(mode能夠看成事件類型)。不使用預設的NSDefaultRunLoopMode,而是改用NSRunLoopCommonModes,這樣主線程就會繼續處理NSTimer事件了。詳細代碼例如以下:

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timer:) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

大家能夠參看博文http://bluevt.org/?

p=209,加深了解NSTimer和NSRunLoop的關系。

曾經博文中提到延遲調用的方法,事實上就是在目前線程的run loop上注冊timer來實作定時執行的。是以假設是在非主線程上使用,一定要有一個run loop。

繼續閱讀