Я часто сталкивался с этой ошибкой в ​​моей OS X, используя swift:

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

У меня есть NSWindow , и я переключаю представления на contentView окна. Я получаю ошибку , когда пытаюсь выполнить NSApp.beginSheet в окне или когда добавляю в окно subview. Пытался отключить автоматическое изменение размера, и у меня ничего не используется автоматическая компоновка. есть идеи?

Иногда все в порядке и ничего не происходит, иногда это полностью ломает мой UI и ничего не загружается

315
Mark 3 Фев 2015 в 18:01

21 ответ

Лучший ответ

Его необходимо разместить в другом потоке, который позволяет обновлять пользовательский интерфейс, как только выполнение функции потока завершается:

Современный Свифт:

DispatchQueue.main.async {
    // Update UI
}

Более старые версии Swift, до Swift 3.

dispatch_async(dispatch_get_main_queue(){
    // code here
})

Цель-C:

dispatch_async(dispatch_get_main_queue(), ^{
    // code here
});
638
pkamb 5 Июн 2020 в 06:05

Я также столкнулся с этой проблемой, увидев тонну этих сообщений и трассировок стека, которые печатаются на выходе, когда я изменил размер окна до меньшего размера, чем его начальное значение. Долго разбираясь в проблеме, я подумал, что поделюсь довольно простым решением. Однажды я включил Can Draw Concurrently на NSTextView через IB. Это сообщает AppKit, что он может вызывать метод представления draw(_:) из другого потока. После его отключения я больше не получал сообщений об ошибках. Перед обновлением до macOS 10.14 Beta у меня не было никаких проблем, но в то же время я также начал изменять код для работы с текстовым представлением.

0
Andreas detests censorship 2 Авг 2018 в 22:28

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

Проверьте эту ссылку: https://forums.developer.apple.com/thread/7399

2
Kiran P Nair 23 Апр 2016 в 18:03

У меня была эта проблема, когда я использовал TouchID, если это помогает кому-то еще, оберните свою логику успеха, которая, вероятно, что-то делает с пользовательским интерфейсом в основной очереди.

2
Stuart P. 30 Окт 2015 в 21:59

У вас уже есть правильный ответ кода от @Mark, но просто чтобы поделиться своими выводами: проблема в том, что вы запрашиваете изменение в представлении и предполагаете, что это произойдет мгновенно. На самом деле загрузка представления зависит от доступных ресурсов. Если все загружается достаточно быстро и нет задержек, то вы ничего не замечаете. В сценариях, где есть какая-либо задержка из-за того, что поток процесса занят и т. Д., Приложение сталкивается с ситуацией, когда оно должно отображать что-то, даже если оно еще не готово. Следовательно, рекомендуется отправлять эти запросы в асинхронные очереди, чтобы они выполнялись в зависимости от нагрузки.

3
Mukund Agarwal 7 Авг 2016 в 20:27

У меня такая же проблема. Оказалось, что я использовал UIAlerts, которому нужна была основная очередь. Но они были устаревшими .
Когда я изменил UIAlerts на UIAlertController, у меня больше не было проблемы, и мне не пришлось использовать код dispatch_async. Урок - обратите внимание на предупреждения. Они помогают даже тогда, когда этого не ожидаешь.

3
ρяσѕρєя K 27 Янв 2016 в 18:04

Вот посмотрите эту строчку из логов

$S12AppName18ViewControllerC11Func()ySS_S2StF + 4420

Вы можете проверить, какая функция вызывается из фонового потока или из того места, где вы вызываете метод api, вам нужно вызвать вашу функцию из основного потока следующим образом.

DispatchQueue.main.async { func()}

func () - это функция, которую вы хотите вызвать в результате успешного вызова api или иначе.

Журналы здесь

This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
 Stack:(
    0   Foundation                          0x00000001c570ce50 <redacted> + 96
    1   Foundation                          0x00000001c5501868 <redacted> + 32
    2   Foundation                          0x00000001c5544370 <redacted> + 540
    3   Foundation                          0x00000001c5543840 <redacted> + 396
    4   Foundation                          0x00000001c554358c <redacted> + 272
    5   Foundation                          0x00000001c5542e10 <redacted> + 264
    6   UIKitCore                           0x00000001f20d62e4 <redacted> + 488
    7   UIKitCore                           0x00000001f20d67b0 <redacted> + 36
    8   UIKitCore                           0x00000001f20d6eb0 <redacted> + 84
    9   Foundation                          0x00000001c571d124 <redacted> + 76
    10  Foundation                          0x00000001c54ff30c <redacted> + 108
    11  Foundation                          0x00000001c54fe304 <redacted> + 328
    12  UIKitCore                           0x00000001f151dc0c <redacted> + 156
    13  UIKitCore                           0x00000001f151e0c0 <redacted> + 152
    14  UIKitCore                           0x00000001f1514834 <redacted> + 868
    15  UIKitCore                           0x00000001f1518760 <redacted> + 104
    16  UIKitCore                           0x00000001f1543370 <redacted> + 1772
    17  UIKitCore                           0x00000001f1546598 <redacted> + 120
    18  UIKitCore                           0x00000001f14fc850 <redacted> + 1452
    19  UIKitCore                           0x00000001f168f318 <redacted> + 196
    20  UIKitCore                           0x00000001f168d330 <redacted> + 144
    21  AppName                        0x0000000100b8ed00 $S12AppName18ViewControllerC11Func()ySS_S2StF + 4420
    22  AppName                        0x0000000100b8d9f4 $S12CcfU0_y10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 2384
    23  App NAme                        0x0000000100a98f3c $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 316
    24  CFNetwork                           0x00000001c513aa00 <redacted> + 32
    25  CFNetwork                           0x00000001c514f1a0 <redacted> + 176
    26  Foundation                          0x00000001c55ed8bc <redacted> + 16
    27  Foundation                          0x00000001c54f5ab8 <redacted> + 72
    28  Foundation                          0x00000001c54f4f8c <redacted> + 740
    29  Foundation                          0x00000001c55ef790 <redacted> + 272
    30  libdispatch.dylib                   0x000000010286f824 _dispatch_call_block_and_release + 24
    31  libdispatch.dylib                   0x0000000102870dc8 _dispatch_client_callout + 16
    32  libdispatch.dylib                   0x00000001028741c4 _dispatch_continuation_pop + 528
    33  libdispatch.dylib                   0x0000000102873604 _dispatch_async_redirect_invoke + 632
    34  libdispatch.dylib                   0x00000001028821dc _dispatch_root_queue_drain + 376
    35  libdispatch.dylib                   0x0000000102882bc8 _dispatch_worker_thread2 + 156
    36  libsystem_pthread.dylib             0x00000001c477917c _pthread_wqthread + 472
    37  libsystem_pthread.dylib             0x00000001c477bcec start_wqthread + 4
)
1
Govind Wadhwa 24 Сен 2019 в 07:23

Swift 4,

Предположим, если вы вызываете какой-то метод с использованием очереди операций

operationQueue.addOperation({
            self.searchFavourites()
        })

И предположим, что функция searchFavourites похожа на

func searchFavourites() {
     DispatchQueue.main.async {
                    //Your code
                }
}

Если вы вызовете весь код внутри метода searchFavourites в основном потоке, он все равно будет выдавать ошибку, если вы обновляете в нем какой-либо пользовательский интерфейс.

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

Так что используйте решение,

operationQueue.addOperation({
            DispatchQueue.main.async {
                self.searchFavourites()
            }
        })

Для такого сценария.

1
Pramod More 30 Май 2018 в 06:42

Для меня проблема заключалась в следующем. Убедитесь, что performSegueWithIdentifier: выполняется в основном потоке:

dispatch_async (dispatch_get_main_queue(), ^{
  [self performSegueWithIdentifier:@"ViewController" sender:nil];
});
1
Offek 25 Май 2018 в 12:09

Если вы хотите отследить эту ошибку, установите флажок «Пауза при проблемах» в основном потоке. В большинстве случаев исправить это несложно, отправив проблемную строку в основную очередь.

enter image description here

2
rockdaswift 14 Янв 2019 в 12:12

У меня была такая же проблема при попытке обновить сообщение об ошибке в UILabel в том же ViewController (требуется некоторое время для обновления данных при попытке сделать это с обычным кодированием). Я использовал DispatchQueue в Swift 3 Xcode 8, и он работает.

2
CrazyTN 15 Июн 2018 в 18:47

У меня возникла эта проблема при перезагрузке данных в UITableView. Простая отправка перезагрузки следующим образом устранила проблему для меня.

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.tableView.reloadData()
    })
4
ReshDev 15 Сен 2016 в 06:43

Основная проблема с «Это приложение изменяет механизм автоматического размещения из фонового потока» заключается в том, что кажется, что оно регистрируется в журнале спустя долгое время после возникновения реальной проблемы, что может затруднить устранение неполадок.

Мне удалось решить проблему, создав три символических точки останова.

Отладка> Точки останова> Создать символическую точку останова ...

Точка останова 1:

  • Символ: -[UIView setNeedsLayout]

  • Условие: !(BOOL)[NSThread isMainThread]

Точка останова 2:

  • Символ: -[UIView layoutIfNeeded]

  • Условие: !(BOOL)[NSThread isMainThread]

Точка останова 3:

  • Символ: -[UIView updateConstraintsIfNeeded]

  • Условие: !(BOOL)[NSThread isMainThread]

С этими точками останова вы можете легко получить разрыв в фактической строке, где вы неправильно вызываете методы пользовательского интерфейса в неосновном потоке.

5
www.jensolsson.se 4 Авг 2019 в 10:47

Очевидно, вы делаете какое-то обновление пользовательского интерфейса в фоновом потоке. Невозможно предсказать, где именно, не видя вашего кода.

Это может произойти в следующих ситуациях:

Вы можете что-то делать в фоновом потоке и не использовать. Находясь в той же функции, этот код легче обнаружить.

DispatchQueue.main.async { // do UI update here }

Вызов функции, выполняющей вызов веб-запроса в фоновом потоке, и ее обработчик завершения, вызывающий другую функцию, выполняющую обновление пользовательского интерфейса. чтобы решить эту проблему, попробуйте проверить код, в котором вы обновили пользовательский интерфейс после вызова веб-запроса.

// Do something on background thread
DispatchQueue.global(qos: .userInitiated).async {
   // update UI on main thread
   DispatchQueue.main.async {
                // Updating whole table view
                self.myTableview.reloadData()
            }
}
7
Ashish Pisey 27 Июн 2017 в 07:19

Вы не должны изменять пользовательский интерфейс вне основного потока! UIKit не является потокобезопасным, поэтому, если вы это сделаете, возникнут указанные выше проблемы, а также некоторые другие странные проблемы. Приложение может даже вылететь.

Итак, чтобы выполнять операции UIKit, вам нужно определить блок и позволить ему выполняться в основной очереди: например,

NSOperationQueue.mainQueue().addOperationWithBlock {

}
7
Chowdhury Md Rajib Sarwar 5 Фев 2016 в 03:40

Была та же проблема, потому что я использовал performSelectorInBackground.

10
Glen Selle 25 Ноя 2015 в 17:13

У меня возникла эта проблема с момента обновления до iOS 9 SDK, когда я вызывал блок, который обновлял пользовательский интерфейс в обработчике завершения асинхронного запроса NSURLConnection. Помещение вызова блока в dispatch_async с использованием dispatch_main_queue решило проблему.

В iOS 8 все работало нормально.

20
spongessuck 21 Сен 2015 в 18:33

Для меня это сообщение об ошибке возникло из баннера из Admob SDK.

Я смог отследить происхождение до «WebThread», установив условную точку останова.

conditional breakpoint to find who is updating ui from background thread

Затем я смог избавиться от проблемы, инкапсулируя создание баннера с помощью:

dispatch_async(dispatch_get_main_queue(), ^{
   _bannerForTableFooter = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
   ...
}

Я не знаю, почему это помогло, поскольку я не вижу, как этот код был вызван из неосновного потока.

Надеюсь, это поможет кому угодно.

22
markussvensson 24 Май 2016 в 18:47

Когда вы пытаетесь обновить значение текстового поля или добавить подпредставление внутри фонового потока, вы можете получить эту проблему. По этой причине вы должны поместить такой код в основной поток.

Вам необходимо обернуть методы, вызывающие обновления пользовательского интерфейса, с помощью dispatch_asynch, чтобы получить основную очередь. Например:

dispatch_async(dispatch_get_main_queue(), { () -> Void in
   self.friendLabel.text = "You are following \(friendCount) accounts"
})

ИЗМЕНИТЬ - SWIFT 3:

Теперь мы можем сделать это с помощью следующего кода:

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
   // Do long running task here
   // Bounce back to the main thread to update the UI
   DispatchQueue.main.async {
      self.friendLabel.text = "You are following \(friendCount) accounts"
   }
}
24
Varun Naharia 7 Апр 2017 в 20:41

Ошибка «это приложение изменяет механизм автоматического размещения из фонового потока» регистрируется в консоли спустя долгое время после того, как возникла реальная проблема, поэтому отладка может быть сложной без использования точки останова.

Я использовал ответ @ markussvensson, чтобы обнаружить свою проблему, и нашел ее с помощью этой символической точки останова (Отладка> Точки останова> Создать символическую точку останова):

  1. Символы: [UIView layoutIfNeeded] или [UIView updateConstraintsIfNeeded]
  2. Условие: !(BOOL)[NSThread isMainThread]

enter image description here

Создайте и запустите приложение на эмуляторе и повторите шаги, которые приводят к появлению сообщения об ошибке (приложение будет работать медленнее, чем обычно!). Затем Xcode остановит приложение и отметит строку кода (например, вызов функции), которая обращается к пользовательскому интерфейсу из фонового потока.

82
Neph 13 Июн 2019 в 05:34

Вы получаете аналогичное сообщение об ошибке при отладке с помощью операторов печати без использования dispatch_async Итак, когда вы получите это сообщение об ошибке, самое время использовать

Swift 4

DispatchQueue.main.async { //code }

Swift 3

DispatchQueue.main.async(){ //code }

Более ранние версии Swift

dispatch_async(dispatch_get_main_queue()){ //code }
146
Naishta 10 Авг 2018 в 04:43