我有一个应用需要在莫尔斯电码中连续发出一个字。我这样做是通过创建一个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 ......
该应用不会在后台运行。 有任何想法吗?谢谢
答案 0 :(得分:4)
你真的应该安排在RunLoop上发送消息,这可能是最简单的方法来安排一个计时器(无限重复,短重复周期,如FLT_EPSILON
或类似),而不是使用线程。< / p>
使用线程很复杂,每个人都应该避免使用它(正如Apple在其“并发编程指南”中所述,并且正如大多数文档所说,“线程是邪恶的”;))。
这是因为多线程是一个庞大而复杂的主题,需要同步,资源保护,了解死锁,关键部分和等等,良好和适应的记忆管理,以及更多。一般来说,如果你需要在后台做一些事情:
performInBackground:
NSThread
。这将避免您遇到很多问题,因为所有其他更高级的API将为您处理很多事情。
此外,像你一样使用线程执行此任务可能会使用更多的CPU(可能会快速达到100%的使用率),因为任务调度程序将没有任何时间(这也是为什么即使是GCD也需要照顾这样的所有东西比NSThreads
更好,如果你不需要强RT限制,在RunLoop中安排发送对于CPU来说甚至更好)
答案 1 :(得分:3)
首先,retainCount
永远不会返回0.这是一种无用的方法。不要打电话。
其次,泄漏只检测不再引用的对象。如果某个线程仍在运行,则不会泄露。
最后,当您致电cancel
时,线程不会停止。它只是设置一个标记,您必须通过isCancelled
检查是否有时间停止在线程中工作。你在做吗?
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];
}
}
我希望这有助于某人:) 谢谢