在程序當(dāng)中經(jīng)常需要延時(shí)執(zhí)行某些操作,而常用的延時(shí)方法有四種。
performSelector方法
聲明
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay ;
代碼舉例
[self performSelector:@selector(method:) withObject:nil afterDelay:2.0] ;
注意
異步執(zhí)行,不會(huì)阻塞當(dāng)前線程鸠真。
由于該方法是基于runloop的,因此必須在一個(gè)活躍的runloop中調(diào)用龄毡。主線程的runloop不會(huì)停止吠卷,因此在主線程中該方法可以正常調(diào)用;而子線程的runloop默認(rèn)是關(guān)閉的沦零,如果不手動(dòng)將其激活祭隔,該方法在子線程的調(diào)用將是無(wú)效的。
-
在主線程中調(diào)用方法
- (void)viewDidLoad { [super viewDidLoad] ; [self performSelector:@selector(method) withObject:nil afterDelay:2.0] ; } - (void)method { NSLog(@"%@",[NSThread currentThread]) ; }
打印結(jié)果為<NSThread: 0x60800007c440>{number = 1, name = main}
路操,方法調(diào)用成功疾渴。
- 在子線程中調(diào)用方法(不手動(dòng)激活)
- (void)viewDidLoad {
[super viewDidLoad] ;
dispatch_async(dispatch_queue_create("test", NULL), ^{
[self performSelector:@selector(method) withObject:nil afterDelay:2.0] ;
}) ;
}
- (void)method {
NSLog(@"%@",[NSThread currentThread]) ;
}
無(wú)打印結(jié)果露戒,方法調(diào)用失敗峭拘。
- 在子線程中調(diào)用方法(手動(dòng)激活)
- (void)viewDidLoad {
[super viewDidLoad] ;
dispatch_async(dispatch_queue_create("test", NULL), ^{
[self performSelector:@selector(method) withObject:nil afterDelay:2.0] ;
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode] ;
[[NSRunLoop currentRunLoop] run] ;
}) ;
}
- (void)method {
NSLog(@"%@",[NSThread currentThread]) ;
}
打印結(jié)果為<NSThread: 0x608000073e40>{number = 3, name = (null)}
灭抑,方法調(diào)用成功循榆。
- 可以通過(guò)類方法
cancelPreviousPerformRequestsWithTarget:
和cancelPreviousPerformRequestsWithTarget:selector:object:
來(lái)取消執(zhí)行,但是必須和其創(chuàng)建在同一個(gè)線程中剔氏。 - 可以通過(guò)方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
確保aSelector
方法會(huì)在主線程執(zhí)行。- 若
wait
為YES,則等待當(dāng)前線程執(zhí)行完以后主線程才會(huì)執(zhí)行aSelector
方法慌核。 - 若
wait
為NO,則不等當(dāng)前線程執(zhí)行完就在主線程中執(zhí)行aSelector
方法申尼。
- 若
- 通過(guò)該方法延時(shí)執(zhí)行
aSelector
方法時(shí)垮卓,最多只能傳入一個(gè)參數(shù)并且無(wú)法獲得方法的返回值。
NSTimer定時(shí)器
聲明
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo ;
代碼舉例
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(method:) userInfo:nil repeats:NO] ;
注意
- 異步執(zhí)行师幕,不阻塞線程粟按。
- 由于該方法是基于runloop的诬滩,因此必須在一個(gè)活躍的runloop中調(diào)用。主線程的runloop不會(huì)停止灭将,因此在主線程中該方法可以正常調(diào)用疼鸟;而子線程的runloop默認(rèn)是關(guān)閉的,如果不手動(dòng)將其激活庙曙,該方法在子線程的調(diào)用將是無(wú)效的空镜。
- 在主線程中調(diào)用方法
- (void)viewDidLoad {
[super viewDidLoad] ;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(method) userInfo:nil repeats:NO] ;
}
- (void)method {
NSLog(@"%@",[NSThread currentThread]) ;
}
打印結(jié)果為<NSThread: 0x600000261680>{number = 1, name = main}
,方法調(diào)用成功捌朴。
- 在子線程中調(diào)用方法(不手動(dòng)激活)
- (void)viewDidLoad {
[super viewDidLoad] ;
dispatch_async(dispatch_queue_create("test", NULL), ^{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(method) userInfo:nil repeats:NO] ;
}) ;
}
- (void)method {
NSLog(@"%@",[NSThread currentThread]) ;
}
無(wú)打印結(jié)果吴攒,方法調(diào)用失敗。
- 在子線程中調(diào)用方法(手動(dòng)激活)
- (void)viewDidLoad {
[super viewDidLoad] ;
dispatch_async(dispatch_queue_create("test", NULL), ^{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(method) userInfo:nil repeats:NO] ;
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode] ;
[[NSRunLoop currentRunLoop] run] ;
}) ;
}
- (void)method {
NSLog(@"%@",[NSThread currentThread]) ;
}
打印結(jié)果為<NSThread: 0x6000002615c0>{number = 3, name = (null)}
砂蔽,方法調(diào)用成功洼怔。
- 可以通過(guò)
-(void)invalidate:
方法取消執(zhí)行,但是必須和其創(chuàng)建在同一個(gè)線程中左驾。 - NSTimer定時(shí)器存在內(nèi)存泄漏的風(fēng)險(xiǎn)镣隶。通過(guò)NSTimer定時(shí)器生成的timer會(huì)被NSRunLoop對(duì)象一直持有,直到調(diào)用invalidate方法什荣。而timer又持有target對(duì)象矾缓,如果不調(diào)用
invalidate
方法,target對(duì)象將會(huì)一直無(wú)法被釋放稻爬,從而造成內(nèi)存泄漏嗜闻。
NSThread的sleep方法
聲明
+ (void)sleepForTimeInterval:(NSTimeInterval)ti ;
代碼舉例
[NSThread sleepForTimeInterval:2.0] ;
[self method] ;
注意
- 同步執(zhí)行,會(huì)阻塞線程桅锄。
- 在主線程和子線程都可以執(zhí)行琉雳。
GCD
聲明
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block) ;
代碼舉例
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self method] ;
});
注意
- 異步執(zhí)行,不會(huì)阻塞線程友瘤。
- 在主線程和子線程都可以執(zhí)行翠肘。
- 一旦執(zhí)行就無(wú)法撤銷。
- 系統(tǒng)會(huì)幫助處理線程級(jí)的邏輯辫秧,并且調(diào)用的對(duì)象也不會(huì)被強(qiáng)行持有束倍,這樣就不會(huì)存在內(nèi)存泄漏的問(wèn)題。