iOS-NSRunLoop編程詳解



-------------------------iOS-NSRunLoop編程詳解1---------------------------------

一.簡介

NSRunloop在編程中扮演的是一個管理者角色,它管理的對象是輸入源,NSRunloop處理的對象包括鼠標和鍵盤的系統事件,此外還有NSPort,NSTimer,NSConnection類的對象。在應用程序中你不能顯示的調用NSRunloop來創建NSRunloop實例對象,每一個線程和主線程中都會默認的有一個NSRunloop的實例變量。如果你想得到每個線程的NSRunloop對象實例變量,可以通過它的類方法調用得到[NSRunloop currentRunLoop];它是不安全的類型所以多線程編程時要小心。

    
    NSLog(@"我是主線程的NSRunloop%@",[NSRunLoop currentRunLoop]);
    [NSThread detachNewThreadSelector:@selector(newThread:) toTarget:self withObject:nil];
    
}

-(void)newThread:(id)sender{
    [[NSRunLoop currentRunLoop] run];
    NSLog(@"我是子線程的NSRunloop%@",[NSRunLoop currentRunLoop]);
}

分別得到主線程和子線程中NSRunLoop對象,打印之後裏面包含了它的一些屬性信息和時間信息等有興趣可以自己打印出來看,可以在任何時候通過[NSRunloop mainRunLoop]得到主線程的NSRunLoop對象。

2015-01-11 14:45:58.839 GCDTest[716:31530]我是主線程的NSRunloop<CFRunLoop 0x7fd399d07280 [0x1074c89a0]>。。。。。。。

2015-01-11 14:45:58.861 GCDTest[716:31584]我是子線程的NSRunloop<CFRunLoop 0x7fd399e2e2a0 [0x1074c89a0]>。。。。。。。


函數介紹:

//添加一個定時器,當定時器的時間到時就會觸發定時器制定的函數

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

//添加一個NSPort,當NSPort對象有消息就會觸發NSPort的代理方法

- (void)addPort:(NSPort *)aPort forMode:(NSString *)mode;

//移除端口

- (void)removePort:(NSPort *)aPort forMode:(NSString *)mode;

//子線程的NSRunLoop是沒有啓動的,所以要通過該函數來啓動NSRunLoop

- (void)run;



二.時間源


1.在主線程中不用調用run函數,只有把timer加入到NSRunloop中才會觸發timerFire函數,間隔時間爲3秒
- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSTimer *timer = [[NSTimer alloc]initWithFireDate:[NSDate date] interval:3 target:self selector:@selector(timerFire:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    
}

-(void)timerFire:(id)sender{
    NSLog(@"i am fired");
}
運行結果:相差三秒左右

2015-01-11 15:10:06.770 GCDTest[812:39356] i am fired

2015-01-11 15:10:09.758 GCDTest[812:39356] i am fired

2015-01-11 15:10:12.758 GCDTest[812:39356] i am fired

2015-01-11 15:10:15.759 GCDTest[812:39356] i am fired

2015-01-11 15:10:18.759 GCDTest[812:39356] i am fired

2015-01-11 15:10:21.759 GCDTest[812:39356] i am fired

2015-01-11 15:10:24.758 GCDTest[812:39356] i am fired


2.在子線程中加入時間數據源

要手動的調用run函數否則沒有任何輸出
- (void)viewDidLoad {
    [super viewDidLoad];
    
   
    
    [NSThread detachNewThreadSelector:@selector(newThread:) toTarget:self withObject:nil];
    
}

-(void)newThread:(id)sender{
    NSTimer *timer = [[NSTimer alloc]initWithFireDate:[NSDate date] interval:3 target:self selector:@selector(timerFire:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
}

-(void)timerFire:(id)sender{
    NSLog(@"i am fired");
}


運行結果:輸出相差3秒

2015-01-11 15:12:53.509 GCDTest[854:40639] i am fired

2015-01-11 15:12:56.514 GCDTest[854:40639] i am fired

2015-01-11 15:12:59.514 GCDTest[854:40639] i am fired

2015-01-11 15:13:02.514 GCDTest[854:40639] i am fired

2015-01-11 15:13:05.513 GCDTest[854:40639] i am fired

2015-01-11 15:13:08.514 GCDTest[854:40639] i am fired

2015-01-11 15:13:11.514 GCDTest[854:40639] i am fired


三.端口數據源

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    NSMachPort *  port = [[NSMachPort alloc]init];    //#1
    [port setDelegate:self];                          //#2
    [[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];//#3
    [NSThread detachNewThreadSelector:@selector(newThread:) toTarget:self withObject:port]; //#4
    
}

- (void)handleMachMessage:(void *)msg{   //#5
    NSLog(@"hello wrod%s",msg);          //#6
}

-(void)newThread:(NSMachPort *)sender{
    NSMachPort *p = [[NSMachPort alloc]init];   //#7
    [sender sendBeforeDate:[NSDate distantFuture] components:nil from:p reserved:0];//#8
    NSLog(@"subthread=%@",[NSThread currentThread]);
}


運行結果:

2015-01-14 22:19:12.519 GCDTest[742:27354] subthread=<NSThread: 0x7ff700f21ed0>{number = 2, name = (null)}

2015-01-14 22:19:12.599 GCDTest[742:27249] hello wrod


代碼說明:

#1:新建一個port,相當於一個線程的耳朵,這時耳朵並沒有安裝上,

#2:給它設置一個代理,當這個耳朵聽到聲音時,代理要對msg做出相應。

#3:把port加入到當前線程的runloop上,相當於給這個線程的裝上了耳朵

#4:新建一個線程,並告訴這個線程如果你要向當前線程說話,你可以通過port傳遞消息

#6:當主線程的耳朵port得到消息時,做相應的處理

#7-#8:你也可以給該線程裝上一個port耳朵並安裝,你可以通過sender 傳給主線程信息




圖解:




小結:注意mianRunloop會自動的run,子線程要手動run,加入到runloop的源要選定代理回調,輸入源的類型。(1.runloop類型,2.回調的選擇,3,輸入源的類型)














發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章