美文网首页
NSRunLoop,AutoRelease相关内容

NSRunLoop,AutoRelease相关内容

作者: _菩提本无树_ | 来源:发表于2020-06-08 13:43 被阅读0次

1.系统默认的5个mode

NSDefaultRunLoopMode

这个mode一般是主线程RunLoop的默认mode。创建线程之初RunLoop是以这种mode运行的。

UITrackingRunLoopMode

这个mode是保证滑动ScrollView滑动不受影响,比如滑动tableView的时候主线程就切到这个mode上了。

UITInitializationRunLoopMode

在刚启动App的时候第一次进入的mode,启动后就不进入此mode了,本人理解是为了防止App进入时选择了其他mode而运行错乱。

GSEventReceiveRunLoopMode

接受系统内部的mode,通常不用。

NSRunLoopCommonModes

这个mode是包括1和2的,因此解有个一个问题。定时器触发的时候滑动TableView定时器会停止。这是因为默认是在第一个mode上运行,在滑动的时候RunLoop切换到了第二个mode,所以第一个mode上的任务就被搁置了。
So,解决这个问题就直接把Timer加入到第五个mode中就完美解决了,滑动的时候也不影响定时器的触发。
2.什么时候会创建autoreleasepool?
线程启动runloop后自动生成NSAutoreleasePool接受对象,当当前runloop迭代结束时,释放该pool.
enumerateObjectUsingBlock:,系统在这类快速遍历方法中会自动添加autoreleasepool.
3.什么是自动释放池?
自动释放池是用来存储多个对象类型的指针变量
4.自动释放池对池内对象的作用?
被存入到自动释放池内的对象,当自动释放池被销毁时,会对池内的对象全部做一次release操作
5.自动释放池作用
将对象与自动释放池建立关系,池子内调用 autorelease 方法,在自动释放池销毁时销毁对象,延迟 release 销毁时间
6.对象如何放入到自动释放池中?
MRC当你确定要将对象放入到池中的时候,只需要调用对象的 autorelease 对象方法
就可以把对象放入到自动释放池中.ARC下如果手动的添加的话需要使用__autoreleasing修饰对象.
7.Autoreleasepool 与 Runloop 的关系
主线程默认为我们开启 Runloop,Runloop 会自动帮我们创建Autoreleasepool,
并进行Push、Pop 等操作来进行内存管理
8.ARC 下什么样的对象由 Autoreleasepool 管理
ARC 下什么样的对象由 Autoreleasepool 管理呢?大多数人的回答是:“都会由 pool 进行管理”。
其实并不是这样的,对于普通的对象是由编译器在合适的地方为我们 Realease 了。
可以使用_objc_autoreleasePoolPrint();这个函数打印注册在缓存中的对象
9.runloop和线程的关系
每个线程都会对应一个runloop.
10.autoreleasepool何时释放
当runloop结束的时候(即进入休眠或者销毁时)会释放autoreleasepool
11.线程安全
线程安全指进行线程操作的时候进行加锁操作(购买车票),NSRunLoop不安全,CFRunLoopRef安全
12.线程刚创建的时候不会有runloop,当主动获取时才会有runloop,线程结束时会销毁对应的runloop,示例代码
/// 全局的Dictionary,key 是 pthread_t, value 是 CFRunLoopRef
static CFMutableDictionaryRef loopsDic;
/// 访问 loopsDic 时的锁
static CFSpinLock_t loopsLock;
 
/// 获取一个 pthread 对应的 RunLoop。
CFRunLoopRef _CFRunLoopGet(pthread_t thread) {
    OSSpinLockLock(&loopsLock);
    
    if (!loopsDic) {
        // 第一次进入时,初始化全局Dic,并先为主线程创建一个 RunLoop。
        loopsDic = CFDictionaryCreateMutable();
        CFRunLoopRef mainLoop = _CFRunLoopCreate();
        CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);
    }
    
    /// 直接从 Dictionary 里获取。
    CFRunLoopRef loop = CFDictionaryGetValue(loopsDic, thread));
    
    if (!loop) {
        /// 取不到时,创建一个
        loop = _CFRunLoopCreate();
        CFDictionarySetValue(loopsDic, thread, loop);
        /// 注册一个回调,当线程销毁时,顺便也销毁其对应的 RunLoop。
        _CFSetTSD(..., thread, loop, __CFFinalizeRunLoop);
    }
    
    OSSpinLockUnLock(&loopsLock);
    return loop;
}
 
CFRunLoopRef CFRunLoopGetMain() {
    return _CFRunLoopGet(pthread_main_thread_np());
}
 
CFRunLoopRef CFRunLoopGetCurrent() {
    return _CFRunLoopGet(pthread_self());
}
13.App内runloop的个数
个人测试结果是,主线程肯定有一个,当开辟子线程的时候获取currentloop时会再次创建一个,子线程
结束时这个currentloop会销毁.
    dispatch_async(dispatch_queue_create("ces", DISPATCH_QUEUE_CONCURRENT), ^{
        NSLog(@"打印当前runloop%@",CFRunLoopGetCurrent());
    });
14.runloop中sources的分类
Source0 : 触摸事件,PerformSelectors,非基于Port的
Source1 : 基于Port的线程间通信,基于Port的
15.__autoreleasing将变量加入缓存池中,防止在autoreleasepool(缓存池)结束前被释放,延迟释放,不同于默认的__strong变量,没有引用时才会释放。
16.alloc/new/copy/mutableCopy和其他方法的返回值取得的对象,都将注册到autoreleasepool.
17. __autoreleasing加入缓存池,如果显式的使用__autoreleasing那么修饰的需是自动变量(包括局部变量,函数,方法参数)
-(void)test{
  NSError * error;
  [self testError:&error];
  //以上代码在编译时会改变为下面的形式
  //NSError __strong* error;
  //NSError __autoreleasing *tmp = error;
  //[self testError:&tmp];
}

- (void)testError:(NSError * __autoreleasing *)error{
    NSError * err = [[NSError alloc]init];
    *error = err;
}
18.如果变量被__weak修饰,为了保持其不被立刻销毁,会被加入到缓存池中,缓存池释放时被释放.

相关文章

网友评论

      本文标题:NSRunLoop,AutoRelease相关内容

      本文链接:https://www.haomeiwen.com/subject/tgbgzhtx.html