Это приложение модифицирует движок автомакета из фонового потока, что может привести к повреждению движка и странным сбоям.

Я получаю этот журнал в консоли, когда запускаю свое приложение в симуляторе. Не видел этого в iOS 8. Я не совсем уверен, в чем причина. Кто-нибудь еще сталкивался с такой же проблемой, и если да, то как это было исправлено? или есть ли какая-либо помощь, которую кто-либо может предоставить в отношении этого?


person Shabarinath Pabba    schedule 11.08.2015    source источник
comment
так что .. github.com/nrbrook/NBUIKitMainThreadGuard   -  person Fattie    schedule 11.02.2017
comment
Обратитесь к этому сообщению.   -  person LF00    schedule 17.05.2017
comment
stackoverflow.com/a/58075072/8537648   -  person Govind Wadhwa    schedule 24.09.2019


Ответы (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];

Гибридное решение, которое не гарантирует того, что наблюдатель вызывается только из указанного метода. Это позволяет использовать более легкого наблюдателя за счет менее надежной конструкции. Упоминается здесь только как решение, которого, вероятно, следует избегать.

person SwiftArchitect    schedule 11.08.2015
comment
так что мы делаем пару обновлений в пользовательском интерфейсе, когда слышим уведомление, значит, вы говорите, что мне нужно сделать эти обновления внутри dispatch_async(dispatch_get_main_queue()? - person Shabarinath Pabba; 12.08.2015
comment
Точно. Я добавил примеры. - person SwiftArchitect; 12.08.2015
comment
хорошо, попробуйте это сейчас и выберете ваш ответ, если он это исправит: D - person Shabarinath Pabba; 12.08.2015
comment
почему этого не требовалось в iOS 8? Почему это происходит в iOS 9? - person Shabarinath Pabba; 12.08.2015
comment
Это было лучшей практикой задолго до iOS 8 — Apple только что выбрала iOS 9, чтобы начать предупреждать о неправильных обновлениях, и, как указано в ошибке, вскоре полностью запретит обновления пользовательского интерфейса в фоновом потоке. - person Scott Austin; 17.09.2015
comment
Вы знаете, как я могу найти, где проблема? Для меня изменения перед предупреждением заключались в том, чтобы сделать прокрутку и добавить к ней controller.view, а также еще несколько, чтобы поддержать изменение, но я все еще не могу его найти. - person Cristi Băluță; 24.10.2015
comment
@stackoverflow.com/users/149202/cristi-b%c4%83lu %c8%9b%c4%83: вы можете задать новый вопрос и опубликовать код - person SwiftArchitect; 25.10.2015
comment
Спасибо. Это отличный ответ! - person nspire; 20.01.2016
comment
Здорово. См. stackoverflow.com/a/34540787/218152 обсуждение размещения уведомлений в основном потоке. - person SwiftArchitect; 20.01.2016

Свифт 3.0

DispatchQueue.main.async {
}
person Eduardo Oliveros    schedule 11.10.2016

Все обновления части пользовательского интерфейса необходимо перенести в ГЛАВНУЮ ветку приложения.

Я вызывал 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)
            })
        }
    }
person Anil Gupta    schedule 25.10.2016

Следует попробовать символическую точку останова, чтобы обнаружить проблему: - введите здесь описание изображения

Символ:

[UIView layoutIfNeeded]

Состояние:

!(BOOL)[NSThread isMainThread]

Затем поместите код обновления пользовательского интерфейса в основной поток.

DispatchQueue.main.async {}
person Abdul Hameed    schedule 20.07.2017
comment
Отличный ответ, чтобы найти проблемный фрагмент кода. Спасибо! - person Sebastian Roth; 16.08.2017

У вас есть код, который обновляет макет пользовательского интерфейса из фонового потока. Изменение очереди операций, в которой вы запускаете свой код, не обязательно должно быть явным. Например, NSURLSession.shared() не использует основную очередь при создании новых запросов. Чтобы убедиться, что ваш код работает в основном потоке, я использую статический метод mainQueue() NSOperationQueue.

Быстрый:

NSOperationQueue.mainQueue().addOperationWithBlock(){
    //Do UI stuff here
}

Объект-C:

[NSOperationQueue mainQueue] addOperationWithBlock:^{
    //Do UI stuff here
}];
person Nikolay    schedule 26.05.2016

В моем случае возникла та же проблема, мне нужно изменить код следующим образом, после чего он работает нормально. В ViewDidLoad вызовите этот метод, используя main thread,

[self performSelectorOnMainThread:@selector(setUpTableRows) withObject:nil waitUntilDone:YES];
person Preetha    schedule 06.10.2016