在iOS中定期在后台线程运行任务

18
我刚开始学iOS开发,正在开发一个需要在后台线程中运行任务从服务器获取数据的应用程序,因为我不想在主线程中锁定用户界面。这个任务将需要很长时间,我尝试使用NSTimer,但它仍然会锁定UI。我的任务是检查聊天界面中的新消息,我需要每5秒调用一次此任务。如果我使用NSTimer,当输入文本时,文本似乎会在执行此任务时停滞一会儿。有没有办法在不锁定UI的情况下处理此任务?请给我一些建议。非常感谢。

== 更新代码 ==

 - (void)performBackgroundTask
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //Do background work

        if([[NSUserDefaults standardUserDefaults] boolForKey:@"LoggedIn"]) {
            NSDictionary * userDictionary = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"SessionDictionary"];

            NSString *authenKey= [userDictionary valueForKey:@"authToken"];

            NSString* limit = @"1000";

            [[LSDataManager sharedDataManager] getLatestMessagesWithAuthKey:authenKey andLimit:limit withBlock:^ (NSDictionary* responseDict)
             {
                 if (responseDict) {
                     [self loadDataFromServer:responseDict];

                     NSArray* lastMessageArray= nil;

                     //filter message data
                     if (self.MessagesArray.count >0) {

                         if (!self.isSeller) {

                             lastMessageArray = [self filterMessageData:self.MessagesArray withProductID:self.productID withSellerID:self.receiverID withBuyerID:self.senderID];
                         }
                         else
                         {
                             lastMessageArray = [self filterMessageData:self.MessagesArray withProductID:self.productID withSellerID:self.senderID withBuyerID:self.receiverID];
                         }

                         NSLog(@"filter array %@",lastMessageArray);

                         if([lastMessageArray count] >0){
                             //[self loadMessages:lastMessageArray];
                             if (self.TempdataSource == nil) {
                                 self.TempdataSource = [NSMutableArray array];
                             }
                             else
                             {
                                 [self.TempdataSource removeAllObjects];
                             }

                             self.TempdataSource = [[[ContentManager sharedManager] generateConversation:lastMessageArray withSenderID:self.senderID] mutableCopy];

                         }
                     }
                 }
             }];
        }


        dispatch_async(dispatch_get_main_queue(), ^{
            //Update UI

            //compare 2 arrays
            if ([self.TempdataSource count] == [self.dataSource count]) {
                NSLog(@"both are same");
            }
            else{
                NSLog(@"both are different");
                self.dataSource = [self.TempdataSource mutableCopy];

                [self refreshMessages];
            }

        });
    });
}

很抱歉,我无法回答你的问题。但是我可以说,使用NSTimer每5秒调用一次任务会消耗资源,我不建议你这样做! - eliasah
@eliasah,我不确定你为什么认为NSTimer会占用大量资源。你有任何参考资料吗?还是你只是在指每5秒执行一次操作的想法? - David Berry
2个回答

33

使用NSTimer安排任务确实是正确的方法。您只需要确保在后台线程上运行重型的非UI代码。这是一个例子:

- (void)viewDidLoad {
    [super viewDidLoad];    
    [self startTimedTask];
}

- (void)startTimedTask
{
    NSTimer *fiveSecondTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(performBackgroundTask) userInfo:nil repeats:YES];
}

- (void)performBackgroundTask
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //Do background work
        dispatch_async(dispatch_get_main_queue(), ^{
            //Update UI
        });
    });
}

1
谢谢,但我听说使用NSTimer不好,是吗?抱歉,我是IOS的新手,我只是想更好地了解。 - NTNT
你能添加一下你听到这个的参考来源吗? - Stavash
1
@Stavash,我说使用NSTimer来激活任务会消耗资源。我并不是说它不好。但我完全同意你提供的解决方案+1。 - eliasah
2
只要使用得当,它就是适合工作的正确类。请记住,它需要在主运行循环上进行调度,并且它会对其目标(在本例中为self)保持强引用。 - Stavash
它会比NSTimer更直观。 NSTimer的资源消耗会更少,但是while循环在底部加上一个sleep比定期触发一些随机函数的NSTimer更具可读性。 - David Berry
显示剩余9条评论

17
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});

试一下


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接