如何在后台停止执行选择器?

时间:2011-02-14 13:06:26

标签: iphone objective-c xcode

我有一些A班。在这堂课我有一个方法, 它调用[self performSelectorInBackground:...]。它开始下载 来自互联网的一些信息。

点按“主页”按钮后,再次输入应用,此后台方法继续有效。 所以,如果我再次调用此方法,我有bad_access,因为后台方法已经工作,我调用了两次。

我可以停止在A级背景中执行选择器吗?例如在我的applicationDidEnterBackground中? 或者我可以检查,如果选择器正在执行或什么?

我发现了一些像

这样的东西
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:a];
[NSObject cancelPreviousPerformRequestsWithTarget:a selector:@selector(startDownload) object:nil];

但他们不适合我。 所以

我的objAppDelegate:

@inteface ObjAppDelegate
{
     A *a;
}
@implementation ObjAppDelegate
{
    -(void)applicationDidEnterBackground:(UIApplication *)application
    {
        //or it can be didBecomeActive..
        //here. check if background task of class A is running, or just stop it ??
    }
}

@implementation A
{
     //some timer, or event, etc.
     -(void)startDownload
     {
          [self performSelectorInBackground:@selector(runBackgroundTask)           withObject:nil];
      }
    -(void)runBackgroundTask
    {
         //some network stuff..
     }
}
我是这样做的:

threadForDownload = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain:) object:nil];
            [threadForDownload start];
            [self performSelector:@selector(startDownload) onThread:threadForDownload withObject:nil waitUntilDone:NO];

  • (void)threadMain:(id)data { NSAutoreleasePool *pool = [NSAutoreleasePool new];

    NSRunLoop *runloop = [NSRunLoop currentRunLoop]; [runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];

    while (YES) { [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; }

    [pool release]; }

在我的startDownload方法中,我查看活动指示器以检查是否 startDownload已经在运行..

-(void)startDownload
{
       if (![[UIApplication sharedApplication] isNetworkActivityIndicatorVisible])  // flag..
    {
            //....
         }
}

//每次开始下载时都会显示networkActivityIndi​​cator

4 个答案:

答案 0 :(得分:4)

您可以轻松创建BOOL实例变量,以确定后台任务是否处于活动状态。

BOOL isBackgroundTaskRunning;

然后在runBackgroundTask

if (isBackgroundTaskRunning) {
    // already running
    return;
}
isBackgroundTaskRunning = TRUE;

...

isBackgroundTaskRunning = FALSE;

答案 1 :(得分:4)

以下是该做什么:

  1. 后台任务使用NSThread currentThread
  2. 将其线程保存到某处的属性
  3. 后台任务定期检查线程的isCancelled属性。
  4. 主线程将cancel发送到步骤1中后台线程保存的线程对象。
  5. 退出时,后台线程将属性设置为nil。
  6. 用于存储线程的属性上的所有操作都必须受@synchronized或等效的保护,以防止主线程将cancel发送到解除分配的线程对象。

    后台线程无法执行阻塞超过一小段时间的IO操作。特别是,使用NSURLConnection同步下载URL已经完成。如果您正在使用NSURLConnection,那么您将需要转移到异步方法和运行循环(可以说,在这种情况下,您可以完全取消后台线程)。如果您使用的是POSIX级IO,请使用poll()并超时。

答案 2 :(得分:1)

我不认为强制中断方法会省钱。您可以做的是更改对象的状态,并检查方法实现中的状态,以便在取消时提前返回(但不要忘记释放已分配的对象)。

这就是NSOperationQueue的工作原理。来自文档:

  

取消操作不会立即强制它停止正在进行的操作。虽然所有操作都需要遵守isCancelled返回的值,但是您的代码必须显式检查此方法返回的值并根据需要中止。

答案 3 :(得分:1)

在后台线程中运行该方法,并保留NSThread的记录。然后,你可以结束线程。