Я нашел так много решений для обновления строки выполнения в пределах одного потока и контроллера представления, однако они, казалось, были не похожими случаями, как мои.Проблема с параллелизмом многопроцессорных рядов за пределами главного контроллера представления
В моем приложении контроллер основного вида вызывает loadIntoCoreData()
(реализован в классе MyLoadingService
), который асинхронно загружает данные в данные ядра другим потоком. Эта функция должна постоянно обновлять процент загрузки (который записывается в NSUserDefaults.standardUserDefaults()
) в основной поток, чтобы он мог отображаться на панели выполнения в главном контроллере. Я никогда не использовал время цикла в MainViewController
непрерывно получать текущее процентное значение, как показано ниже:
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++
}
}
}
Приведенный выше код может успешно запустить прогресс бар, однако он часто сталкивается с BAD_ACCESS или некоторыми другими исключениями (например, «Не удается обновить объект, который никогда не был вставлен») из-за конфликтов в контексте основных данных (кажется, что managedObjectContext
не затрагивается основным потоком). Поэтому вместо того, чтобы использовать прослушивание во время цикла в основном потоке, я рассматриваю использование NSOperationQueue.performSelectorOnMainThread
для подтверждения основного потока после каждой записи. Поэтому я поставил свой контроллер представления в качестве аргумента 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
}
}
}
Спасибо за совет по использованию моего основного использования данных. Я ворвался во все контексты моего кода и повторно организовал контексты внутри, проблема конфликта больше не происходит. Что касается 'NSProgress', то очень жаль, что презентация WWDC фокусируется на функции на iOS 9 (в то время как мое приложение должно компактно работать на устройствах iOS 8). Однако, хотя я использую 'NSProgress', я все равно должен сказать основному потоку, сколько данных уже имеют данные ядра (в другом потоке), правильно? Как поток на «NSProgress» знает ход загрузки в моем основном потоке данных? – whitney13625