代码之家  ›  专栏  ›  技术社区  ›  Luuk D. Jansen

iOS上后台任务的UI更新

  •  1
  • Luuk D. Jansen  · 技术社区  · 13 年前

    我有一个同步过程,有时(甚至很少)需要20秒。我过去常常在后台调用选择器。有一个进度指示器,它会在同步完成的通知后停止动画制作,下面的代码会立即更改:

    [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];
    }
    
    3 回复  |  直到 13 年前
        1
  •  2
  •   shabbirv    13 年前

    为了更新UI,您必须从后台线程调用主线程上的函数,如下所示:

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

    如果您需要传递任何变量,可以继续将其添加到 -withObject

        2
  •  2
  •   Jody Hagins    13 年前

    您可以确保从您想要的任何队列接收到通知。。。

    [[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]
    
        3
  •  0
  •   Jesse Rusak    13 年前

    您需要在后台线程和前台线程之间划分逻辑。您发送的通知应该从主线程发送,这样监听它的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...];
    });