NSRunloop的解析及autorelease的釋放時機

 

iOS的運行時是由一個一個runloop組成的,每一個runloop都會執行下圖所示的一些步驟:ios

每一個runloop中都建立一個Autorelease Pool,並在runloop的末尾進行釋放,
因此,通常狀況下,每一個接受autorelease消息的對象,都會在下個runloop開始前被釋放。也就是說,在一段同步的代碼中執行過程當中,生成的對象接受autorelease消息後,通常是不會在代碼段執行完成前釋放的。多線程

固然也有讓autorelease提早生效的辦法:本身建立Pool並進行釋放架構

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

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

[pool drain];函數

上面的array就會在[pool drain]執行時被釋放。oop

因此對於你遇到的問題,能夠在for循環外嵌套一個Autorelease Pool進行管理,例如spa

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

線程中沒有source的runloop會自動結束。

事件由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這種思路。

相關文章
相關標籤/搜索