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

Posted

技术标签:

【中文标题】在 iOS 中定期在后台线程中运行任务【英文标题】:Running a task in background thread periodically in iOS 【发布时间】:2014-09-19 17:08:14 【问题描述】:

我是 ios 新手。我正在开发应用程序,需要在后台线程中运行从服务器获取数据的任务,因为我不想将 UI 锁定在主线程中。这个任务需要很长时间,我尝试使用 NSTimer 但它仍然锁定 UI。我的任务是在聊天屏幕中查看新消息,我需要每 5 秒调用一次此任务。如果我使用 NSTimer,当输入 text 时,文本似乎在执行此任务时冻结了片刻。有什么方法可以在不锁定 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 秒做一次的想法? 我知道这篇文章已经过时了,但你设法解决了这个问题吗? 【参考方案1】:

使用 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
        );
    );

【讨论】:

谢谢,但我听说如果使用 NSTimer 不好,对吧?对不起,我是IOS新手,我只是想了解更多 你能添加一个你在哪里听过这个的参考吗? @Stavash 我说过 NSTimer 来激活任务是消耗资源的。我没说不好。但我完全同意你给 +1 的解决方案。 只要你使用得当,它就是适合工作的课程。请记住,它需要安排在主运行循环上,并且它保持对其目标(在本例中为 self)的强引用。 @Stavash:我能问个问题吗?如果我想在所有应用程序的后台线程中运行此任务。我的意思是即使任何 Viewcontroller 处于活动状态,此任务仍在运行【参考方案2】:
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void)
        //Run UI Updates
    );
);

试试这个

【讨论】:

感谢您的快速回复。我试过了,还是一样

以上是关于在 iOS 中定期在后台线程中运行任务的主要内容,如果未能解决你的问题,请参考以下文章

如何在ios中每n秒连续在后台线程中运行一个进程

如何运行一个后台线程来定期清理列表中的一些元素?

在后台线程执行硬任务,在主线程返回结果

iOS保持线程在后台运行

如何在后台线程中按顺序运行任务[重复]

如何让PhoneGap IOS插件在后台线程中运行