延迟后在后台线程中处理核心数据

时间:2015-07-28 07:29:25

标签: ios multithreading swift core-data alamofire

我有一个表视图来显示从API获取的列表。

首先,我将API数据存储到Core Data,然后在后续应用程序启动时,我将尝试更新列表。

我需要在后台线程中处理更新操作。应在启动特定ViewController

5秒后调用更新操作
func updateGlossary() {
    var GlobalMainQueue: dispatch_queue_t {
        return dispatch_get_main_queue()
    }
    let delayInSeconds = 5.0
    let popTime = dispatch_time(DISPATCH_TIME_NOW,
        Int64(delayInSeconds * Double(NSEC_PER_SEC)))
    dispatch_after(popTime, GlobalMainQueue) {
        self.showAlertMessage(message: "Updating Glossary")
        DataStore.GetToken({ (token, error) in
            //Got Token
           //Call the API for updated data and store it to core data
        })
    }
}

这有两个问题;

  1. 正在进行更新时,用户界面被阻止
  2. 当我在更新操作开始之前从Controller返回时,它仍将从其他控制器更新(我认为问题是因为排队)
  3. 我正在使用 Swift Alamofire 核心数据

3 个答案:

答案 0 :(得分:0)

第一个问题: -

  

在更新进行时,UI被阻止

你应该以异步方式调用updateGlossary操作,它不会阻塞主线程: -

dispatch_async( dispatch_get_global_queue(0, 0), ^{
    [self performSelector:@"updateGlossary" withObject:nil afterDelay:5.0]
});

对于您的第二个问题: -

  

当我在更新操作开始之前从Controller返回时,它仍会从其他控制器更新(我认为问题是因为排队)

只需在视图控制器的viewDidDisapper()方法中停止该线程

即可
-(void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:FALSE];
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(updateGlossary) object:nil];
}

答案 1 :(得分:0)

由于您正在mainQueue上进行API调用,因此UI被阻止。稍后在到达主队列后创建一个不同的队列并进行API调用,将API数据插入到Coredata中。

我可以从您的代码中看到您使用的GlobalMainQueuedispatch_get_main_queue的别名,因此您的用户界面会被卡住。

解决方案如下:

 var GlobalBackgroundQueue: dispatch_queue_t
{
  return dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0)
}

dispatch_after(popTime, GlobalBackgroundQueue) 
{ 
    //Make the API Call
    dispatch_async(dispatch_get_main_queue()) 
    {
        //Insert Into CoreData
    }
}

答案 2 :(得分:0)

不,不要使用dispatch_async进行CoreData操作。 NSManagedObjectContext本身不是线程安全的,会导致意外行为。您仍然可以使用dispatch_after来调用主线程上的块。

您的代码很好,除了您的getToken(:_)可能在主线程上发生和/或您的数据库操作正在主线程上发生,因此阻止了UI。

您可以像这样修改代码:

func updateGlossary() {
    var GlobalMainQueue: dispatch_queue_t {
        return dispatch_get_main_queue()
    }
    let delayInSeconds = 5.0
    let popTime = dispatch_time(DISPATCH_TIME_NOW,
        Int64(delayInSeconds * Double(NSEC_PER_SEC)))
    dispatch_after(popTime, GlobalMainQueue) {
        self.showAlertMessage(message: "Updating Glossary")
        DataStore.GetToken({ (token, error) in
            //Got Token
           //This will execute in the background
           self.callAPIWithToken(token, success: { (data) -> () in
              //Callback on the main thread
              self.privateManagedObjectContext.performBlock {
                //Will execute in its private thread
                //Insert to the database, save context
              }
           }) { (error) -> () in

           }
        })
    }
}

privateManagedObjectContextNSManagedObjectContext的实例,其并发类型为.PrivateQueueConcurrencyType,其父存储为.MainQueueConcurrencyType。您可以使用privateManagedObjectContext在后​​台插入并保存数据。这种方法是线程安全的,不会阻止你的UI。

Here是关于多上下文核心数据系统的好文章。

修改 如果您想在离开时取消,我建议您不要使用dispatch_after。请改用NSTimer。让它在5秒后在主线程上进行服务调用;当你离开控制器时,它会失效。