NSThread何时返回到已释放的对象?(iPhone)

NSThread何时返回到已释放的对象?(iPhone),iphone,memory-management,nsthread,Iphone,Memory Management,Nsthread,我有一个内存错误,它似乎可以归结为线程中发生的事情。我很难解决这个问题 我有一个UIViewController,当它处于活动状态时,即用户正在使用它的视图,从NSThread中的web服务检索更新 每3分钟进行一次,该延迟由以下控制: [self performSelector:@selector(timerDone) withObject:nil afterDelay:180.0]; TimerOne方法现在启动NSThread,该线程检索web服务数据,并再次发送PerformSelec

我有一个内存错误,它似乎可以归结为线程中发生的事情。我很难解决这个问题

我有一个UIViewController,当它处于活动状态时,即用户正在使用它的视图,从NSThread中的web服务检索更新

每3分钟进行一次,该延迟由以下控制:

[self performSelector:@selector(timerDone) withObject:nil afterDelay:180.0];
TimerOne方法现在启动NSThread,该线程检索web服务数据,并再次发送PerformSelect消息。这是一个小检查更新,填充视图,关闭一切,重复例行程序,工作正常

现在,用户当然可以突然点击一个按钮,加载第二个UIViewController。当这种情况发生时,我呼吁:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timerDone) object:nil];
然后用dealoc方法进行清理

我现在的问题是:如果在用户更改视图并启动此对象(NSThread的起点)的解构时,NSThread正在运行,会发生什么情况

我是否应该保留一个BOOL,告诉我NSThread是否仍然处于活动状态,如果仍然处于活动状态,那么在这种情况下如何处理NSThread

线程是这样完成的:

- (void) runTimer {

    [self performSelector:@selector(timerDone) withObject:nil afterDelay:180];
}

- (void) timerDone {

    [self performSelector:@selector(runTimer) withObject:nil afterDelay:2];
    [NSThread detachNewThreadSelector:@selector(updateAllVisibleElements) toTarget:self withObject:nil]; 

    }

- (void) updateAllVisibleElements  {

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //call approiate web service
    [pool release];
}
- (void)requestUpdate
{
    if ([NSThread currentThread] != self.thread)
    {
        [self performSelector:@selector(update) onThread:self.thread withObject:nil waitUntilDone:NO];
        return;
    }
    else
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        //call approiate web service
        [pool drain];
    }
}

这里有两个问题:首先,使用performSelector:withObject:afterDelay:执行NSTimer最擅长的定期回调。cancelPreviousPerformRequestsWithTarget:selector:object:可能非常昂贵,而且因为线程可能会造成竞争条件

第二个问题:每个线程都有自己的运行循环,这两种机制都执行选择器:。。。和NSTimer,并绑定到当前线程的运行循环

我的建议是:创建一个长寿命的NSThread,它有自己的显式运行循环来满足所有更新需求。请参阅,以获取这方面的一些好的示例代码。在该线程上,设置一个3分钟的重复NSTimer。每3分钟更新一次

如果需要在三分钟周期之外安排更新,则可以使用performSelector:onThread:withObject:waitUntilDone:调用updateAllVisibileElements。我通常这样做的方式是将所有线程逻辑封装到单个对象WebServiceController或其他任何东西中。它创建自己的NSThread并将其保存在ivar中。然后我使用如下代码:

- (void) runTimer {

    [self performSelector:@selector(timerDone) withObject:nil afterDelay:180];
}

- (void) timerDone {

    [self performSelector:@selector(runTimer) withObject:nil afterDelay:2];
    [NSThread detachNewThreadSelector:@selector(updateAllVisibleElements) toTarget:self withObject:nil]; 

    }

- (void) updateAllVisibleElements  {

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //call approiate web service
    [pool release];
}
- (void)requestUpdate
{
    if ([NSThread currentThread] != self.thread)
    {
        [self performSelector:@selector(update) onThread:self.thread withObject:nil waitUntilDone:NO];
        return;
    }
    else
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        //call approiate web service
        [pool drain];
    }
}

还有一个注意事项:您提到后台线程填充视图。后台线程不应调用UIKit。UIKit不是线程安全的,只能在主线程上调用。我通常通过在视图控制器观察的主线程上发布通知来实现这一点。更新对象不应该知道有关UI的任何信息。这打破了Cocoa的模型-视图-控制器范式。

这里有两个问题:首先,您使用performSelector:withObject:afterDelay:执行NSTimer最擅长的定期回调。cancelPreviousPerformRequestsWithTarget:selector:object:可能非常昂贵,而且因为线程可能会造成竞争条件

第二个问题:每个线程都有自己的运行循环,这两种机制都执行选择器:。。。和NSTimer,并绑定到当前线程的运行循环

我的建议是:创建一个长寿命的NSThread,它有自己的显式运行循环来满足所有更新需求。请参阅,以获取这方面的一些好的示例代码。在该线程上,设置一个3分钟的重复NSTimer。每3分钟更新一次

如果需要在三分钟周期之外安排更新,则可以使用performSelector:onThread:withObject:waitUntilDone:调用updateAllVisibileElements。我通常这样做的方式是将所有线程逻辑封装到单个对象WebServiceController或其他任何东西中。它创建自己的NSThread并将其保存在ivar中。然后我使用如下代码:

- (void) runTimer {

    [self performSelector:@selector(timerDone) withObject:nil afterDelay:180];
}

- (void) timerDone {

    [self performSelector:@selector(runTimer) withObject:nil afterDelay:2];
    [NSThread detachNewThreadSelector:@selector(updateAllVisibleElements) toTarget:self withObject:nil]; 

    }

- (void) updateAllVisibleElements  {

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //call approiate web service
    [pool release];
}
- (void)requestUpdate
{
    if ([NSThread currentThread] != self.thread)
    {
        [self performSelector:@selector(update) onThread:self.thread withObject:nil waitUntilDone:NO];
        return;
    }
    else
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        //call approiate web service
        [pool drain];
    }
}

还有一个注意事项:您提到后台线程填充视图。后台线程不应调用UIKit。UIKit不是线程安全的,只能在主线程上调用。我通常通过在视图控制器观察的主线程上发布通知来实现这一点。更新对象不应该知道有关UI的任何信息。这打破了Cocoa的模型-视图-控制器范式。

并且,重复最后一段:UIKit不是线程安全的,只能从主线程更新。有关从后台发送信息的方法,请参阅performSelectorOnMainThread:withObject:waitUntilDone:嗨,谢谢你们。我真的不希望我写的任何东西都能被解释为NSThread更新视图后台线程通过委托在模型上设置数据。然后,模型告诉所有控制器新数据可用。我需要正确理解这一点:我应该在appDelegate中设置一个NSThread,它贯穿于我的应用程序的整个运行过程。然后,该线程将每3分钟运行一次NSTimer并更新我的数据?现在,我对所有数据对象进行排序,那些超过3分钟的数据对象将被更新,但这种情况只发生在
当加载需要这些数据的视图时,我会使用一个通过应用程序运行的NSThread。如果只想在有人需要更新时进行更新,则让视图控制器在模型上调用类似setNeedsUpdate的内容,就像视图的setNeedsDisplay一样。或者,您可以在模型对象上创建addObserver和removeObserver,视图对象将以这种方式进行设置。每3分钟,如果观察者>0,则更新对象。只有当避免不必要的更新有真正的好处时,我才会这样做。通常它连接到一个昂贵的服务器。下载500字节或5000字节通常都差不多。谢谢你的详细说明,罗伯。它是一个按调用收费的web服务,因此选择正确的方法非常重要:我喜欢addObserver/removeObserver的想法。我可以运行一个线程,运行一个X分钟计时器。只有当观察者的数量>0时,我才需要进行更新。这似乎将我的ViewController与处理计时器和线程垃圾收集分离开来。作为奖励,这还为我提供了一种收集多个数据对象并批量更新它们的方法。再次感谢你!重复最后一段:UIKit不是线程安全的,只能从主线程更新。有关从后台发送信息的方法,请参阅performSelectorOnMainThread:withObject:waitUntilDone:嗨,谢谢你们。我真的不希望我写的任何东西都能被解释为NSThread更新视图后台线程通过委托在模型上设置数据。然后,模型告诉所有控制器新数据可用。我需要正确理解这一点:我应该在appDelegate中设置一个NSThread,它贯穿于我的应用程序的整个运行过程。然后,该线程将每3分钟运行一次NSTimer并更新我的数据?现在,我对所有数据对象进行排序,超过3分钟的数据对象将被更新,但这仅在加载需要这些数据的视图时发生。我将使用通过应用程序运行的NSThread。如果只想在有人需要更新时进行更新,则让视图控制器在模型上调用类似setNeedsUpdate的内容,就像视图的setNeedsDisplay一样。或者,您可以在模型对象上创建addObserver和removeObserver,视图对象将以这种方式进行设置。每3分钟,如果观察者>0,则更新对象。只有当避免不必要的更新有真正的好处时,我才会这样做。通常它连接到一个昂贵的服务器。下载500字节或5000字节通常都差不多。谢谢你的详细说明,罗伯。它是一个按调用收费的web服务,因此选择正确的方法非常重要:我喜欢addObserver/removeObserver的想法。我可以运行一个线程,运行一个X分钟计时器。只有当观察者的数量>0时,我才需要进行更新。这似乎将我的ViewController与处理计时器和线程垃圾收集分离开来。作为奖励,这还为我提供了一种收集多个数据对象并批量更新它们的方法。再次感谢你!