我有一个表视图来显示从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
})
}
}
这有两个问题;
我正在使用 Swift , Alamofire ,核心数据
答案 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中。
我可以从您的代码中看到您使用的GlobalMainQueue
是dispatch_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
}
})
}
}
privateManagedObjectContext
是NSManagedObjectContext
的实例,其并发类型为.PrivateQueueConcurrencyType
,其父存储为.MainQueueConcurrencyType
。您可以使用privateManagedObjectContext
在后台插入并保存数据。这种方法是线程安全的,不会阻止你的UI。
Here是关于多上下文核心数据系统的好文章。
修改强>
如果您想在离开时取消,我建议您不要使用dispatch_after
。请改用NSTimer
。让它在5秒后在主线程上进行服务调用;当你离开控制器时,它会失效。