2012-08-06 27 views
1

我有一个同步过程,有时(甚至很少)需要20秒。我曾经在后台调用选择器。有其停止对同步完成的通知动画进度指示器,并与它下面的代码马上改变:iOS上的后台任务的UI更新

[self performSelectorInBackground:@selector(updateFunction) withObject:nil]; 

但为了让进度继续我决定使用后台任务:

UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance 

    __block UIBackgroundTaskIdentifier background_task; //Create a task object 

    background_task = [application beginBackgroundTaskWithExpirationHandler:^{ 
     [application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks 
     background_task = UIBackgroundTaskInvalid; //Set the task to be invalid 

     //System will be shutting down the app at any point in time now 
    }]; 

    //Background tasks require you to use asyncrous tasks 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     //Perform your tasks that your application requires 

     NSLog(@"\n\nRunning in the background!\n\n"); 
     [self updateFunction]; 

     [application endBackgroundTask: background_task]; //End the task so the system knows that you are done with what you need to perform 
     background_task = UIBackgroundTaskInvalid; //Invalidate the background_task 
     NSLog(@"Finished in the background!"); 
    }); 

但是现在,当任务完成后通知被发送(和执行),但在表中的单元格不更新,直到(有时)的时间显著量。所以在我看来,'需求显示'在后台任务等等时不会被触发,而只是在常规的刷新间隔内进行更新。

有没有办法让表格单元更新使用后台任务,或者我错过了什么?

编辑: 通知监听器是:

[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(refreshBttn) 
              name:@"finishedUpdate" 
              object:nil]; 

的代码是:

- (void) refreshBttn { 
    NSLog(@"Refresh Buttun action"); 
    iDomsAppDelegate *delegate = (iDomsAppDelegate *)[[UIApplication sharedApplication] delegate]; 
    if([delegate updating]){ 
     [_updateBttn setHidden:TRUE]; 
     [_activityIndicator startAnimating];   
    } else { 
     [_updateBttn setHidden:FALSE]; 
     [_activityIndicator stopAnimating];   
    } 
    [self setNeedsDisplay]; 
    [self setNeedsLayout]; 
} 

回答

0

您需要将背景和前景线程之间的逻辑分开。您发送的通知应该从主线程发送,以便您的UI对象在收听时可以安全地进行自我更新。所以,把updateFunction分成两块。也许是这样的:

NSLog(@"\n\nRunning in the background!\n\n"); 
[self updateFunctionBackground]; 
dispatch_async(dispatch_get_main_queue(), ^{ 
    // send your notification here instead of in updateFunction 
    [[NSNotificationCenter defaultCenter] post...]; 
}); 
+0

这似乎没有什么区别。在这两种情况下,我都可以看到更新单元格时创建的日志条目,但行为没有变化。 (但是说了这样的话,确实是更好,因为它现在在主线程中执行) – 2012-08-06 17:36:11

+0

@ LuukD.Jansen也许问题出在你的UI更新代码中?你在那里做什么?你可以发布该通知的接收者的代码吗? – 2012-08-06 18:28:59

+0

这似乎并不是问题,因为它只是在后台执行更新功能时,在第一个实例中完美工作。我将把代码,但它很简单。 – 2012-08-07 07:04:29

2

为了使UI更新,你必须从你的后台调用主线程功能像这样的线程:

[self performSelectorOnMainThread:@selector(updateFunction) withObject:nil waitUntilDone:NO]; 

如果你需要通过任何变量你可以去一个并将其添加到-withObject

+0

其实,使用[self performSelectorInBackground:@selector(updateFunction)withObject:nil];作品。我会做一些测试,看看它是否正确执行它在我测试的背景 – 2012-08-07 07:09:06

+0

,当应用程序关闭它不会继续在后台运行。这只适用于直接调用更新函数(不在主线程中的后台) – 2012-08-07 07:54:51

2

可以确保通知从你想与任何队列......收到

[[NSNotificationCenter defaultCenter] addObserverForName:SomeNotification 
                object:sender 
                queue:operationQueue 
               usingBlock:^(NSNotification *){ 
    // Your notification will be processed in this block, and it will be 
    // received on the notification queue you specify, regardless of what 
    // thread the sender was running when the notification was posted. 
}]; 

如果你想确保它接收到主线程,你可以使用

[NSOperationQueue mainQueue] 
+0

这是一个很好的观点,我仍然不习惯这些奇特的iOS 5 API :) – 2012-08-06 18:41:02

+0

我仍然试图让我的代码4.x兼容,至少在另一个时候,因为我确实有很多4.x用户 – 2012-08-07 07:59:45