简体   繁体   English

当NSThread返回到释放的对象时? (苹果手机)

[英]When NSThread returns to a released object? (iPhone)

I have got a memory bug that seems to boil down to something happening in a thread. 我有一个内存错误,似乎可以归结为线程中发生的事情。 I am having difficulties troubleshooting this. 我在排除故障方面遇到困难。

I have a UIViewController, that when active , ie the user is using its view, retrieves updates from a web service in an NSThread. 我有一个UIViewController,当激活时 (即用户正在使用其视图),它从NSThread中的Web服务检索更新。

This is done every 3 minutes and this delay is controlled by a: 此操作每3分钟执行一次,并且此延迟受以下因素控制:

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

The timerDone method now starts the NSThread that retrieves the web service data and also it sends the performSelector message again. 现在, timerDone方法将启动NSThread,该NSThread检索Web服务数据,并且还会再次发送performSelector消息。 This is a little "check for updates, populate views, shut everything down, repeat" routine that works just fine. 这有点“正常工作”的“检查更新,填充视图,关闭所有内容,重复”例程。

Now, the user can of course suddenly tap a button an load up a second UIViewController. 现在,用户当然可以突然点击一个按钮并加载第二个UIViewController。 When this happens I call: 当发生这种情况时,我打电话给:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timerDone) object:nil];

And do my cleaning up in the dealloc method. 然后用dealloc方法清理一下。

My question is now: What happens if the NSThread was running while the user changed the view and set in motion the deconstruction of this object that is the starting point of the NSThread? 我的问题现在是:如果在用户更改视图并使运动中解构对象(即NSThread的起点)时NSThread正在运行,会发生什么情况?

Should I keep a BOOL around that tells me if the NSThread is still active, and if so, what to do with the NSThread if this is the case. 我是否应该在BOOL周围告诉我NSThread是否仍处于活动状态,如果是,在这种情况下如何处理NSThread。

The threading is done like this: 线程是这样完成的:

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

You have two problems here: first, you're using performSelector:withObject:afterDelay: to do what an NSTimer does best (periodic callback). 这里有两个问题:首先,您正在使用performSelector:withObject:afterDelay:来执行NSTimerperformSelector:withObject:afterDelay:事情(定期回调)。 cancelPreviousPerformRequestsWithTarget:selector:object: can be quite expensive, and because of your threading is likely creating race conditions. cancelPreviousPerformRequestsWithTarget:selector:object:可能会非常昂贵,并且由于线程化可能会导致竞争条件。

Second problem: each thread has its own run loop, and both mechanisms ( performSelector:... and NSTimer ) and are tied to the current thread's run loop. 第二个问题:每个线程都有自己的运行循环,并且两种机制( performSelector:...NSTimer )都与当前线程的运行循环绑定。

Here's what I recommend: Create a single, long-lived NSThread with its own explicit run loop for all your update needs. 我的建议是:创建一个长期存在的NSThread,并为其自己的显式运行循环满足所有更新需求。 Look at the Threading Programming Guide for some good example code of this. 请参阅《 线程编程指南》中的一些良好示例代码。 On that thread, set up a 3-minute repeating NSTimer . 在该线程上,设置3分钟的重复NSTimer Every 3 minutes, update. 每3分钟更新一次。

If you need to schedule an update outside the three-minute cycle, then you use performSelector:onThread:withObject:waitUntilDone: to call your updateAllVisibileElements . 如果需要在三分钟周期之外安排更新,则可以使用performSelector:onThread:withObject:waitUntilDone:调用updateAllVisibileElements The way I generally do this is to encapsulate all of the thread logic into a single object (WebServiceController or whatever). 我通常这样做的方法是将所有线程逻辑封装到单个对象(WebServiceController或其他对象)中。 It creates it own NSThread and saves it in an ivar. 它创建自己的NSThread并将其保存在ivar中。 Then I use code like this: 然后我使用如下代码:

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

One more note: you mention that the background thread "populates views." 还有一点需要注意:您提到后台线程“填充了视图”。 A background thread should never call into UIKit. 后台线程永远不应调用UIKit。 UIKit is not thread safe and should only be called on the main thread. UIKit不是线程安全的,只能在主线程上调用。 I typically achieve this by posting notifications onto the main thread which the view controllers observe. 我通常通过将通知发布到视图控制器观察到的主线程上来实现此目的。 The "updating" object should not know anything about the UI. “更新”对象应该对UI一无所知。 That breaks the Model-View-Controller paradigm of Cocoa. 这打破了可可的模型-视图-控制器范式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM