runloop 与autorelase对象、Autorelease Pool 在什么时候释放


转载自: http://blog.csdn.net/leikezhu1981/article/details/51246684
iOS 的运行时是由一个一个 runloop 组成的,每个 runloop 都会执行下图所示的一些步骤:

每个runloop中都创建一个Autorelease Pool,并在runloop的末尾进行释放,
所以,一般情况下,每个接受autorelease消息的对象,都会在下个runloop开始前被释放。也就是说,在一段同步的代码中执行过程中,生成的对象接受autorelease消息后,一般是不会在代码段执行完成前释放的。

当然也有让autorelease提前生效的办法:自己创建Pool并进行释放

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSArray * array = [[[NSArray alloc] init] autorelease];

[pool drain];

上面的array就会在[pool drain]执行时被释放。

所以对于你遇到的问题,可以在for循环外嵌套一个Autorelease Pool进行管理,例如

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

for (int i = 0; i < 10000; i++)

{

    // ... 

}

[pool drain];

但由于你提到了生成的每个实例可能会比较大。只在循环外嵌套,可能导致在pool释放前,内存里已经有10000个实例存在,造成瞬间占用内存过大的情况。

因此,如果你的每个实例仅需要在单次循环过程中用到,那么可以考虑可以在循环内创建pool并释放

for (int i = 0; i < 10000; i++)

{

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // ...

    [pool drain];

}


对于多线程来说, 每一个线程都有自己的 runloop,  主线程是默认开启的,创建的子线程要手动开启,因为 NSApplication 只启动 main applicaiton thread

线程中没有sourcerunloop会自动结束。 

事件由NSRunLoop 类处理。RunLoop监视操作系统的输入源,如果没有事件数据,不消耗任何CPU 资源。如果有事件数据,run loop 就发送消息,通知各个对象。

 currentRunLoop 获得 runloop reference,给 runloop 发送run 消息启动它。

 

下面介绍四种情况是使用runloop的场合:

 1.使用端口或自定义输入源和其他线程通信

 2.子线程中使用了定时器

 3.cocoa中使用任何performSelector到了线程中运行方法

 4.使线程履行周期性任务,(我把这个理解与2相同)

如果我们在子线程中用了NSURLConnection异步请求,那也需要用到runloop,不然线程退出了,相应的delegate方法就不能触发。


这里通过小示例简单介绍以下有关runloop方面的问题:

1.首先简单运行执行runlooprun函数并不会让系统停住等待事件,而是需要在运行runloop之前添加source,只有在有source的情况下线程才会停下来监听各种事件。

2.runloop的使用:

1)生成一个runloop source

    // add send source 

    CFRunLoopSourceContext  src_context ;  

    NSError * emsg = nil ; 

 

    // init send source context 

    src_context.version = 0;

    src_context.info = inst;

    src_context.retain = NULL;

    src_context.release = NULL;

    src_context.copyDescription = NULL;

    src_context.equal = NULL;

    src_context.hash = NULL;

    src_context.schedule = NULL;

    src_context.cancel = NULL;

    src_context.perform = &callback ;//设置唤醒是调用的回调函数

 

    // create send source from context 

 

   CFRunLoopSourceRef runloopSource ; 

    runloopSource = CFRunLoopSourceCreate (NULL, 0, &src_context) ;

2)将source加入线程所属的runloop中

 

    // add the send source into  run loop

    CFRunLoopRef       threadRunLoop ;

    threadRunLoop =  CFRunLoopGetCurrent() ; 

    CFRunLoopAddSource (threadRunLoop ,

                        runloopSource,

                        kCFRunLoopDefaultMode);  

3)运行runloop

   CFRunLoopRun() ; 


4)如何调用runloop(首先可以将各个线程的runloop和source保存起来)

 

   CFRunLoopSourceSignal(runloopSource) ;// 参数是你调用的runloop的source 

   CFRunLoopWakeUp(threadRunLoop) ;//这句话的作用时立即执行该runloop的事件,如果没有这句话系统会在空闲的时候执行刚才的runloopSource相关的事件

3.如何停掉runloop退出线程

    CFRunLoopStop(threadRunLoop) ;这个函数可以停掉runloop是线程正常退出

4.ios整个系统基本上是基于runloop这种架构的,ios程序的main线程整体上也是基于runloop的,各种事件的响应应该也是基于source这种思路。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值