使用NSThread进行内存管理

时间:2011-09-27 09:14:29

标签: iphone objective-c memory-management nsthread

我有一个应用需要在莫尔斯电码中连续发出一个字。我这样做是通过创建一个NSThread并在选择器中运行一些带有“while循环”的代码。这是代码:

@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];

    }
}

应用程序正确响应事件,我已经使用nslog进行了检查。 然后调用[MorseCode release]。 代码如下所示:

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

问题:虽然我打电话给 [myThread release] 然后 [theMorse release] ,但是theMorse的retainCount仍然高于0(它不会调用dealloc )。

泄漏仪器并没有说我有泄漏,但如果我打开并关闭应用程序10次,最终Iphone会重置。最后在调试器中我看到了“收到内存警告”。级= 2” 。

此外,我从未在游泳池排水管之前看到NSLog ......

该应用不会在后台运行。 有任何想法吗?谢谢

3 个答案:

答案 0 :(得分:4)

你真的应该安排在RunLoop上发送消息,这可能是最简单的方法来安排一个计时器(无限重复,短重复周期,如FLT_EPSILON或类似),而不是使用线程。< / p>

使用线程很复杂,每个人都应该避免使用它(正如Apple在其“并发编程指南”中所述,并且正如大多数文档所说,“线程是邪恶的”;))。

这是因为多线程是一个庞大而复杂的主题,需要同步,资源保护,了解死锁,关键部分和等等,良好和适应的记忆管理,以及更多。一般来说,如果你需要在后台做一些事情:

  • 使用已有的机制(如某些操作的异步实现,并通过委托方法或通知发出信号)(如果有)
  • 使用performInBackground:
  • 等方法
  • 使用NSOperationQueues
  • 使用GCD
  • 只有在不得已的情况下,如果没有其他选择(或针对特定情况),请使用NSThread

这将避免您遇到很多问题,因为所有其他更高级的API将为您处理很多事情。


此外,像你一样使用线程执行此任务可能会使用更多的CPU(可能会快速达到100%的使用率),因为任务调度程序将没有任何时间(这也是为什么即使是GCD也需要照顾这样的所有东西比NSThreads更好,如果你不需要强RT限制,在RunLoop中安排发送对于CPU来说甚至更好)

答案 1 :(得分:3)

首先,retainCount永远不会返回0.这是一种无用的方法。不要打电话。

其次,泄漏只检测不再引用的对象。如果某个线程仍在运行,则不会泄露。

最后,当您致电cancel时,线程不会停止。它只是设置一个标记,您必须通过isCancelled检查是否有时间停止在线程中工作。你在做吗?


好的 - 简单的东西回答了。下一个?尝试构建和分析。然后使用Allocations仪器并启用参考计数跟踪。然后看看什么叫retain额外的时间。

答案 2 :(得分:0)

我决定放弃NSThread类并使用另一个方法:

-(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];  

    }

}

我希望这有助于某人:) 谢谢