IOS 創建並發線程的實例詳解
創建並發線程
主線程一般都是處理UI界面及用戶交互的事兒的。其他的事一般就要另外的線程去處理,如下載,計算等。。。
現在先簡單創建3個線程,分別打印出1-1000,,為了方便,線程3就放在主線程中執行。
- (void) firstCounter{
@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"First Counter = %lu", (unsigned long)counter);
}
}
}
- (void) secondCounter{
@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Second Counter = %lu", (unsigned long)counter);
}
}
}
- (void) thirdCounter{
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Third Counter = %lu", (unsigned long)counter);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:@selector(firstCounter)
toTarget:self
withObject:nil];
[NSThread detachNewThreadSelector:@selector(secondCounter)
toTarget:self
withObject:nil];
/* Run this on the main thread */
[self thirdCounter];
}
由於thirdCounter 函數沒有運行在單獨的線程中,所以不需要自動釋放池(autorelease pool)。這個方法將在應用程序的主線程中運行,每一個Cocoa Touch程序都會自
動的給該主線程創建一個自動釋放池。
在代碼的最後通過調用 detachNewThreadSelector,把將第一個計數器和第二個計數器運行在獨立的線程中。現在,如果你運行程序,將會在控制台窗口看到如下信息:
Second Counter = 921 Third Counter = 301 Second Counter = 922 Second Counter = 923 Second Counter = 924 First Counter = 956 Second Counter = 925 Counter = 957 Second Counter = 926 First Counter = 958 Third Counter = 302 Second Counter = 927 Third Counter = 303 Second Counter = 928
可以看出,這三個計時器是同時運行的,他們輸出的內容是隨機交替的。 每一個線程必須創建一個 autorelease pool。在 autorelease pool 被 release 之前,autorelease pool 會一直持有被 autoreleased 的對象的引用。在引用計數內存管理環境中這是一個非常重要的機制,例如Cocoa Touch中的對象就能夠被autoreleased。無論何時,在創建一個對象實例時,該對象的引用計數是1,但是當創建的autorelease pool對象被release了,那麼 autorelease 的對象同樣會發送一個 release 消息,如果此時,它的引用計數仍然是 1,那麼該對象將被銷毀。
每一個線程都需要創建一個 autorelease pool,當做是該線程第一個被創建的對象。如果不這樣做,如果不這樣做,當線程退出的時候,你分配在線程中的對象會發生內存洩露。為了更好的理解,我們來看看下面的代碼:
- (void) autoreleaseThread:(id)paramSender{
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:@"AnImage"
ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
/* Do something with the image */
NSLog(@"Image = %@", image);
}
- (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:@selector(autoreleaseThread:)
toTarget:self
withObject:self];
}
如果你運行這段代碼,,你就會在控制台窗口看到這樣的輸出信息:
*** __NSAutoreleaseNoPool(): Object 0x5b2c990 of
class NSCFString autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b2ca30 of
class NSPathStore2 autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b205c0 of
class NSPathStore2 autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b2d650 of
class UIImage autoreleased with no pool in place - just leaking
上面的信息顯示了我們創建的 autorelease 的 UIImage 實例產生了一個內存洩露,另外,FilePath 和其他的對象也產生了洩露。這是因為在我們的線程中,沒有在開始的時候創建和初始化一個autorelease pool。下面是正確的代碼,你可以測試一下,確保它沒有內存洩露:
- (void) autoreleaseThread:(id)paramSender{
@autoreleasepool {
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:@"AnImage"
ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
/* Do something with the image */
NSLog(@"Image = %@", image);
}
}
以上使用關於IOS 並發線程的實例,如有疑問大家可以留言討論,共同進步,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!