2011-09-27 93 views
1

我有一個應用程序需要用莫爾斯電碼連續發信號。我通過創建一個NSThread並使用「while循環」在選擇器內運行一些代碼來實現這一點。下面是代碼:使用NSThread進行內存管理

@implementation MorseCode 


-(void)startContinuousMorseBroadcast:(NSString *)words{ 
    if (!(threadIsOn)) { 

    threadIsOn = YES; s 

    myThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadSelector:) object:words]; 

    [myThread start]; 

} 

if (morseIsOn) { 
    morseIsOn = NO; 
} 
else{ 
    morseIsOn = YES; 
} 


    } 

-(void)threadSelector:(NSString *)words{ 

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

while (![myThread isCancelled]) { 

// ///it Does some code here 


} //end While 


NSLog(@"Cleaning the pool"); 
    [pool drain]; 
} 


@end 

當退出該應用程序(用戶按下的按鈕),在applicationDidEnterBackground執行以下的選擇:

-(void)cleanUpMorseObject{ //this is defined in the MorseCode class, same as threadSelector 
    if (threadIsOn) { 

     NSLog(@"cleanUpMorseObject, threadIsOn"); 
     threadIsOn = NO; 
     morseIsOn = NO; 

     [myThread cancel]; 
     [myThread release]; 

    } 
} 

應用正確響應的情況下,I」已經檢查過nslog。 然後調用[MorseCode release]。 的代碼看起來是這樣的:

-(void)applicationDidEnterBackground{ //this happens in the ViewController 
[theMorse cleanUpMorseObject]; //theMorse is an instance of MorseCode 
[theMorse release]; 
} 

的問題:雖然我叫[MyThread的發佈]然後[theMorse發行]的theMorse的retainCount仍高於0(它不叫的dealloc)。

泄漏儀器並沒有說我有泄漏,但如果我打開和關閉應用程序,最終Iphone重置10次。同樣在調試器中,我最終看到「收到的內存警告。級= 2」 。

而且我從來沒有看到的NSLog池排水之前...

的應用程序不會在後臺運行。 任何想法?謝謝

回答

3

首先,retainCount永遠不會返回0.這是一種無用的方法。別叫它。

其次,泄漏只能檢測到不再被引用的對象。如果線程仍在運行,則不會泄露。

最後,當您撥打cancel時,線程不會停止。它只是設置一個標誌,你必須通過isCancelled檢查是否是時候停止在線程中的工作。你在做那個嗎?


好的 - 簡單的東西回答。下一個?嘗試構建和分析。然後使用分配儀器並打開參考計數跟蹤。然後看看什麼叫retain額外的時間。

+0

謝謝你的第一和第二個信息,這是很好的知道。我知道什麼是「取消」。我的代碼用while檢查![myThread isCancelled] –

4

你真的應該安排在RunLoop上發送消息,可能最簡單的方法就是安排一個定時器(重複無限次,並且重複週期很短,如FLT_EPSILON或類似)而不是使用線程。 (蘋果在其「併發編程指南」中指出,正如大多數文檔所述,「線程是邪惡的」;)),線程的工作很複雜,每個人都應該避免它。

這是因爲多線程是一個龐大而複雜的主題,需要同步,資源保護,意識到死鎖,關鍵部分等等,良好和適應性的內存管理,以及更多。一般來說,如果你需要做的東西在後臺:

  • 使用機制已經到位(如異步執行一些操作,並通過委託方法或通知被髮送信號)(如果可用)
  • 使用方法,如performInBackground:
  • 使用NSOperationQueues
  • 使用GCD
  • ,僅在最後的手段,如果沒有其他的選擇(或者真的特定情況下),使用NSThread

這樣可以避免很多問題,因爲所有其他更高級的API都會爲您處理很多事情。


此外,使用線程這個任務像你這樣很可能會使用更多的CPU(可能會達到100%的使用率迅速),因爲不會留給任務調度的任何時間(即也是爲什麼即使是GCD,照顧所有這些東西的方式比NSThreads更好,如果不需要強大的RT約束,在RunLoop中調度發送甚至更好)

0

我決定放棄NSThread並使用另一個aproach:

-(void)playSOSMorse{ 

    if ([myTimer isValid]) { 

     [myTimer invalidate]; 
     [myTimer release]; 
     myTimer = nil; 
    } 

     myTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001 
                target:self 
                selector:@selector(tymerSelector) 
                userInfo:nil 
                repeats:NO] retain]; 
    //the timer calls a selector that performs a selector in background 

} 

-(void)tymerSelector{ 

    [self performSelectorInBackground:@selector(threadSelector2) withObject:nil]; 
} 

-(void)threadSelector2 { 

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

//some code here 

[pool drain]; 

//calls another selector on the main thread to see if it needs to fire the timer again and restart the cycle 
[self performSelectorOnMainThread:@selector(selectorOnMainThread) withObject:nil waitUntilDone:NO]; 

} 

-(void)selectorOnMainThread{ 
     [myTimer invalidate]; 
     [myTimer release]; 


    myTimer = nil; 


    if (morseIsOn) { //this is a boolean that if it is true (YES) calls the timer again 

     [self playSOSMorse]; 

    } 

} 

我希望這可以幫助別人:) 謝謝

相關問題