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,输入源的类型)














posted @ 2015-01-11 14:31  fineman  阅读(363)  评论(0编辑  收藏  举报