ios开发之runloop

runloop:运行循环。

1.开启一条线程,这条线程就是这个app的主线程。

2.这个主线程是常驻线程(一旦启动,就不再退出),这条线程上的runloop被开启。

程序启动入口函数:main()

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

现在在main函数中执行一个操作

int a = UIApplicationMain(argc, argv, nil, appDelegateClassName);
NSLog(@"执行");
return a;

此时可以发现,log是不会打印的。

由此可见,在app开启的时候,就开启了一个死循环,持续执行。

runloop就是一个死循环

runloop作用:

1.主线程runloop保证程序不退出,子线程runloop保证线程不退出。

2.监听事件:负责监听所有的事件。在iOS中:触摸、时钟、网络事件。

runloop有5种模式(用到的三种)

1.默认模式 NSDefaultRunLoopMode。---------------- 处理网络事件,timer

2.UI模式(runloop优先处理source:触摸事件)UITrackingRunLoopMode -------UI事件

3.NSRunLoopCommonModes 占位模式(并不是runloop真正的模式)

4.初始化模式,不开放给程序员

5.系统内核模式,不开放给程序员

UI模式优先级最高,但是只能被UI事件唤醒。timer加在UI模式下不会进行处理。

在主线程runloop添加timer,timer回调方法中执行耗时操作,会造成程序卡顿。因此:timer中不建议处理耗时的操作(耗时操作需要放在子线程中)

例:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    
}

- (void)timerMethod{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"%@",[NSThread currentThread]);
}

上边的写法就会造成主线程的卡顿现象发生。所以为了解决这个问题,放在考虑放在子线程中处理。例:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSThread *thread = [[NSThread alloc]initWithBlock:^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod:) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    }];
    [thread start]; 
}

- (void)timerMethod{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"%@",[NSThread currentThread]);
}

此时就会发现,在子线程中,执行完代码,子线程被销毁。因此需要考虑线程保活

思路一:用一个强引用的全局变量指向线程。会发现线程在执行完毕之后,依旧被销毁。不可用。

线程的生命:是由CPU调度的。只和线程的任务有关系,任务执行完成,线程自动销毁。

线程是CPU调度与执行,与OC对象没有关系。

在线程中添加一个死循环,会发现线程不会被销毁,而指向线程的对象也不会被释放。例:

NSThread *thread = [[NSThread alloc]initWithBlock:^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod:) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        while (true) {
            
        }
    }];

此时,定时器的方法依旧不会调用。因为线程上的runloop需要手动调用。只是添加一个死循环保住线程。此时没有死循环依然会正常执行,说明runloop run方法开启了一个死循环。

[[NSRunLoop currentRunLoop] run];

runlopprunlo取消:runloop开启后,无法取消。

因此可以考虑这样做,例:

 while (_Finished) {
            [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.000001]];
        }

也可以考虑退出线程

[NSThread exit];

提示:退出主线程,app不会挂掉,不响应任何操作,子线程会继续执行。

主线程是UI线程,更新UI。

UIKit不是线程安全。因此约定只在主线程访问UI。(多条线程对同一个对象进行操作,就会出现资源抢夺)。

1.主线程与子线程没有任何区别,主线程是系统开启的。

2.主线程启动的时候进行界面渲染等其他操作,主线程挂掉,不再处理界面山任何东西。

timer的方法是事件不是任务

事件和任务的区别:

在线程创建出来的时候执行的代码就是任务,runloop也是任务。runloop处理的任务就是事件。

runloop没有创建方法:runloop是一个懒加载的方法,在第一次调用的时候创建。

source

事件源、输入源

按照函数调用栈source分类:

source0 非系统内核事件

source1 系统内核事件

observer

CFRunloop :CoreFoundation

CoreFoundation内存不由ARC进行管理

create new copy 这类名称开头的函数会在堆区域开辟内存空间。需要进行内存管理。

malloc创建一个指针,申请内存区域。

free 将指针指向的内存置为空

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值