Я получаю этот журнал в консоли, когда запускаю свое приложение в симуляторе. Не видел этого в iOS 8. Я не совсем уверен, в чем причина. Кто-нибудь еще сталкивался с такой же проблемой, и если да, то как это было исправлено? или есть ли какая-либо помощь, которую кто-либо может предоставить в отношении этого?
Это приложение модифицирует движок автомакета из фонового потока, что может привести к повреждению движка и странным сбоям.
Ответы (6)
Не меняйте пользовательский интерфейс ни с чем, кроме основного потока. Хотя может показаться, что он работает на некоторых ОС или устройствах, но не на других, он обязательно сделает ваше приложение нестабильным и приведет к непредсказуемому сбою.
Если вы должны ответить на уведомление, которое может происходить в фоновом режиме, убедитесь, что UIKit
вызов происходит в основном потоке.
У вас есть как минимум эти 2 варианта:
Асинхронная отправка
Используйте GCD
(Grand Central Dispatch), если ваш наблюдатель может получать уведомления в любой ветке. Вы можете слушать и выполнять работу из любого потока и инкапсулировать изменения пользовательского интерфейса в dispatch_async
:
dispatch_async(dispatch_get_main_queue()) {
// Do UI stuff here
}
Когда использовать GCD
? Когда вы не контролируете, кто отправляет уведомление. Это может быть ОС, Cocoapod, встроенные библиотеки и т. д. Использование GCD
будет просыпаться в любое время, каждый раз. Недостаток: вы обнаружите, что перепланируете работу.
Слушайте в основной теме
Для удобства вы можете указать, в каком потоке вы хотите, чтобы наблюдатель был уведомлен во время регистрации для получения уведомлений, используя параметр queue
:
addObserverForName:@"notification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note){
// Do UI stuff here
}
Когда наблюдать за основным потоком? Когда вы одновременно регистрируетесь и регистрируетесь. Но когда вы отвечаете на уведомление, вы уже там, где должны быть.
Опубликовать уведомление в основной теме
[self performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
Гибридное решение, которое не гарантирует того, что наблюдатель вызывается только из указанного метода. Это позволяет использовать более легкого наблюдателя за счет менее надежной конструкции. Упоминается здесь только как решение, которого, вероятно, следует избегать.
Свифт 3.0
DispatchQueue.main.async {
}
Все обновления части пользовательского интерфейса необходимо перенести в ГЛАВНУЮ ветку приложения.
Я вызывал createMenuView() в фоновом режиме и получил ошибку ниже
"Это приложение модифицирует механизм автомакета из фонового потока, что может привести к повреждению механизма и странным сбоям"
Поэтому я вызвал вышеуказанный метод в основной поток, используя
DispatchQueue.main.async {
}
в SWIFT 3.0 и Xcode 8.0
Ниже написан правильный код:
RequestAPI.post(postString: postString, url: "https://www.someurl.com") { (succeeded: Bool, msg: String, responceData:AnyObject) -> () in
if(succeeded) {
print(items: "User logged in. Registration is done.")
// Move to the UI thread
DispatchQueue.main.async (execute: { () -> Void in
//Set User's logged in
Util.set_IsUserLoggedIn(state: true)
Util.set_UserData(userData: responceData)
self.appDelegate.createMenuView()
})
}
else {
// Move to the UI thread
DispatchQueue.main.async (execute: { () -> Void in
let alertcontroller = UIAlertController(title: JJS_MESSAGE, message: msg, preferredStyle: UIAlertControllerStyle.alert)
alertcontroller.title = "No Internet"
alertcontroller.message = FAILURE_MESSAGE
self.present(alertcontroller, animated: true, completion: nil)
})
}
}
Следует попробовать символическую точку останова, чтобы обнаружить проблему: -
Символ:
[UIView layoutIfNeeded]
Состояние:
!(BOOL)[NSThread isMainThread]
Затем поместите код обновления пользовательского интерфейса в основной поток.
DispatchQueue.main.async {}
У вас есть код, который обновляет макет пользовательского интерфейса из фонового потока. Изменение очереди операций, в которой вы запускаете свой код, не обязательно должно быть явным. Например, NSURLSession.shared() не использует основную очередь при создании новых запросов. Чтобы убедиться, что ваш код работает в основном потоке, я использую статический метод mainQueue() NSOperationQueue.
Быстрый:
NSOperationQueue.mainQueue().addOperationWithBlock(){
//Do UI stuff here
}
Объект-C:
[NSOperationQueue mainQueue] addOperationWithBlock:^{
//Do UI stuff here
}];
В моем случае возникла та же проблема, мне нужно изменить код следующим образом, после чего он работает нормально. В ViewDidLoad
вызовите этот метод, используя main thread
,
[self performSelectorOnMainThread:@selector(setUpTableRows) withObject:nil waitUntilDone:YES];