【发布时间】:2015-10-29 10:02:20
【问题描述】:
我在同一个线程和视图控制器中找到了很多进度条更新解决方案,但它们似乎与我的情况不同。
在我的应用程序中,主视图控制器调用loadIntoCoreData()(在类MyLoadingService 中实现),它通过另一个线程将数据异步加载到核心数据中。这个函数必须不断更新加载百分比(写在NSUserDefaults.standardUserDefaults())到主线程,以便它可以显示在主视图控制器的进度条上。我曾经在MainViewController 中使用过while 循环来不断获取当前百分比值,如下所示:
class MainViewController {
override func viewDidLoad() {
MyLoadingService.loadIntoCoreData() { result in
NSUserDefaults.standardUserDefaults().setBool(false, forKey: "isLoading")
// do something to update the view
}
self.performSelectorInBackground("updateLoadingProgress", withObject: nil)
}
func updatingLoadingProgress() {
let prefs = NSUserDefaults.standardUserDefaults()
prefs.setBool(true, forKey: "isLoading")
// here I use a while loop to listen to the progress value
while(prefs.boolForKey("isLoading")) {
// update progress bar on main thread
self.performSelectorOnMainThread("showLoadingProcess", withObject: nil, waitUntilDone: true)
}
prefs.setValue(Float(0), forKey: "loadingProcess")
}
func showLoadingProcess() {
let prefs = NSUserDefaults.standardUserDefaults()
if let percentage = prefs.valueForKey("loadingProcess") {
self.progressView.setProgress(percentage.floatValue, animated: true)
}
}
}
并且在函数loadIntoCoreData的类中:
class MyLoadingService {
let context = (UIApplication.sharedApplication()delegate as! AppDelegate).managedObjectContext!
func loadIntoCoreData(source: [MyModel]) {
var counter = 0
for s in source {
//load into core data using the class context
NSOperationQueue.mainQueue.addOperationWithBlock({
// updating the value of "loadingProcess" in NSUserDefaults.standardUserDefaults()
// and synchronize it on main queue
})
counter++
}
}
}
上述代码可以成功运行进度条,但是由于核心数据上下文冲突(认为managedObjectContext没有被主线程触及)。因此,我考虑使用NSOperationQueue.performSelectorOnMainThread 在每次进入后确认主线程,而不是在主线程上使用while 循环。因此我将我的视图控制器作为参数sender 放入loadCoreData 并调用performSelectorOnMainThread("updateProgressBar", withObject: sender, waitUntilDone: true) 但失败并出现错误“无法识别的选择器发送到类'XXXXXXXX'”。所以我想问是否可以在线程之间更新 UI 对象?或者,如何修改我之前的解决方案,以便解决核心数据上下文冲突?任何解决方案都值得赞赏。
class MyLoadingService {
func loadIntoCoreData(sender: MainViewController, source: [MyModel]) {
var counter = 0
for s in source {
//load into core data using the class context
NSOperationQueue.mainQueue.addOperationWithBlock({
// updating the value of "loadingProcess" in NSUserDefaults.standardUserDefaults()
// and synchronize it on main queue
})
NSOperationQueue.performSelectorOnMainThread("updateProgressBar", withObject: sender, waitUntilDone: true)
counter++
}
}
func updateProgressBar(sender: MainViewController) {
sender.progressView.setProgress(percentage, animated: true)
}
}
class MainViewController {
override func viewDidLoad() {
MyLoadingService.loadIntoCoreData(self) { result in
// do something to update the view
}
}
}
【问题讨论】:
标签: ios multithreading core-data concurrency uiprogressview