Swift&Objective-C春天来咯iOS

Objective-C之我所理解的Runloop

2019-01-18  本文已影响8人  Bestmer

前言

RunLoop是iOS和OSX开发中非常基础的一个概念,学习Runloop能够帮助我们更清楚的了解APP为何能够持续运行。虽然在平时的工作场景中使用Runloop的机会很少,但是理解RunLoop可以帮助开发者更好的利用多线程编程。网上关于Runloop的文章千篇一律,但"一千个读者,就有一千个哈姆雷特",每个人都有自己不同的理解。


Runloop

通俗概念

官方解释


如果没有Runloop

image

有了Runloop以后

image
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

RunLoop对象


Runloop与线程的关系


获得RunLoop对象


Runloop的相关类

image

CFRunLoopRef


CFRunLoopModeRef


CFRunLoopSourceRef


CFRunLoopTimerRef


CFRunLoopObserverRef

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),
    kCFRunLoopBeforeTimers = (1UL << 1),
    kCFRunLoopBeforeSources = (1UL << 2),
    kCFRunLoopBeforeWaiting = (1UL << 5),
    kCFRunLoopAfterWaiting = (1UL << 6),
    kCFRunLoopExit = (1UL << 7),
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

图解

image
image
// 1.要给runloop添加一个事件,让它先跑起来再说
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
 // 2.需要手动开启它
[[NSRunLoop currentRunLoop] run];

Runloop的应用

1.处理NSTimer滑动暂停的问题。
// 通过timerWithTimeInterval创建出来的timer,默认不会被添加到runloop,需要手动添加指定mode
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

// 通过timer的scheduledTimerWithTimeInterval创建出来的timer,默认被添加到runloop的NSDefaultRunLoopMode下
// 当滑动scrollView时,runloop会切换到UITrackingRunLoopMode
// 也就导致之前NSDefaultRunLoopMode下的timer暂停
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 解决方法,手动将timer添加到NSDefaultRunLoopMode下
// NSDefaultRunLoopMode表示timer既能响应UITrackingRunLoopMode,
// 也能响应NSDefaultRunLoopMode
// 相当于将timer拷贝了一份放在这两个mode下
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

2.在某个mode下调用方法。
// 只在NSDefaultRunLoopMode模式下显示图片
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"placeholder"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];

3.更好的理解自动释放池(@autoreleasepool)
// 创建observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
    NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);
});

// 添加观察者:监听RunLoop的状态
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

// 释放Observer
CFRelease(observer);

4. 创建一个常驻线程
#import "ViewController.h"

@interface ViewController ()
/** 线程对象 */
@property (nonatomic, strong) NSThread *thread;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [self.thread start];
}

- (void)run
{
// 让线程不死的一种取巧做法,
// 不停的开启runloop,
// 每次runloop发现如果没有任何的port就直接退出了,
// 当我们调用touchesBegan为runloop添加了一个source时,runloop才正在跑起来了
    while (1) {
        [[NSRunLoop currentRunLoop] run];
    }
}

- (void)run1
{
    // 推荐开启常驻线程的办法
    // 手动添加一个port,让它跑起来
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
}

- (void)test
{
    NSLog(@"----------test----%@", [NSThread currentThread]);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}


关于runloop的面试题

1.什么是Runloop?

2.自动释放池什么时候释放?

3.在开发中如何使用runloop?

4.ARC下是否还需要进行内存管理?

5.NSTimer受runloop的影响,精度上存在误差,如何解决?


写在最后

很久很久没有更新博客,一直忙于日常的工作,有时候学了新东西想写一写,可能发现网上早已经有了很多关于这方面的文章,于是便放弃了写下去的念头。其实,人都是有惰性的,总觉得看现成的比自己去写一写要来得快一些,但是整理知识点的过程,我们实际上也在加深一遍理解,而学习是一个不断重复的过程。对于已经掌握了相关知识的人,这种总结性文章可能毫无意义,但是对于想入门学习的人,文章能够做到浅显易懂,它就是有价值的。做了很久的开发,发现实际编码中我们真的很渺小,我们总是在搭建UI,创建model,网络请求,数据填充,搞点炫酷的动画,和产品经理撕逼。即便你会各种黑魔法,各种超能力,能够用到的机会其实并不多。所以越是基础的东西越需要打牢,有了基础才能举一反三,才能一步一步的去解决更多刁钻的需求。

上一篇 下一篇

猜你喜欢

热点阅读