Я часто сталкивался с этой ошибкой в моей OS X, используя swift:
«Это приложение изменяет механизм автоматического раскладки из фонового потока, что может привести к повреждению механизма и странным сбоям. Это вызовет исключение в следующем выпуске».
У меня есть NSWindow , и я переключаю представления на contentView
окна. Я получаю ошибку , когда пытаюсь выполнить NSApp.beginSheet
в окне или когда добавляю в окно subview
. Пытался отключить автоматическое изменение размера, и у меня ничего не используется автоматическая компоновка. есть идеи?
Иногда все в порядке и ничего не происходит, иногда это полностью ломает мой UI
и ничего не загружается
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
});
Я также столкнулся с этой проблемой, увидев тонну этих сообщений и трассировок стека, которые печатаются на выходе, когда я изменил размер окна до меньшего размера, чем его начальное значение. Долго разбираясь в проблеме, я подумал, что поделюсь довольно простым решением. Однажды я включил Can Draw Concurrently
на NSTextView
через IB. Это сообщает AppKit, что он может вызывать метод представления draw(_:)
из другого потока. После его отключения я больше не получал сообщений об ошибках. Перед обновлением до macOS 10.14 Beta у меня не было никаких проблем, но в то же время я также начал изменять код для работы с текстовым представлением.
Это может быть что-то столь же простое, как установка значения текстового поля / метки или добавление подпредставления внутри фонового потока, что может привести к изменению макета поля. Убедитесь, что все, что вы делаете с интерфейсом, происходит только в основном потоке.
Проверьте эту ссылку: https://forums.developer.apple.com/thread/7399
У меня была эта проблема, когда я использовал TouchID, если это помогает кому-то еще, оберните свою логику успеха, которая, вероятно, что-то делает с пользовательским интерфейсом в основной очереди.
У вас уже есть правильный ответ кода от @Mark, но просто чтобы поделиться своими выводами: проблема в том, что вы запрашиваете изменение в представлении и предполагаете, что это произойдет мгновенно. На самом деле загрузка представления зависит от доступных ресурсов. Если все загружается достаточно быстро и нет задержек, то вы ничего не замечаете. В сценариях, где есть какая-либо задержка из-за того, что поток процесса занят и т. Д., Приложение сталкивается с ситуацией, когда оно должно отображать что-то, даже если оно еще не готово. Следовательно, рекомендуется отправлять эти запросы в асинхронные очереди, чтобы они выполнялись в зависимости от нагрузки.
У меня такая же проблема. Оказалось, что я использовал UIAlerts
, которому нужна была основная очередь. Но они были устаревшими .
Когда я изменил UIAlerts
на UIAlertController
, у меня больше не было проблемы, и мне не пришлось использовать код dispatch_async
. Урок - обратите внимание на предупреждения. Они помогают даже тогда, когда этого не ожидаешь.
Вот посмотрите эту строчку из логов
$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
)
Swift 4,
Предположим, если вы вызываете какой-то метод с использованием очереди операций
operationQueue.addOperation({
self.searchFavourites()
})
И предположим, что функция searchFavourites похожа на
func searchFavourites() {
DispatchQueue.main.async {
//Your code
}
}
Если вы вызовете весь код внутри метода searchFavourites в основном потоке, он все равно будет выдавать ошибку, если вы обновляете в нем какой-либо пользовательский интерфейс.
Это приложение модифицирует механизм автоматического раскладки из фонового потока после того, как к нему был осуществлен доступ из основного потока.
Так что используйте решение,
operationQueue.addOperation({
DispatchQueue.main.async {
self.searchFavourites()
}
})
Для такого сценария.
Для меня проблема заключалась в следующем. Убедитесь, что performSegueWithIdentifier:
выполняется в основном потоке:
dispatch_async (dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:@"ViewController" sender:nil];
});
Если вы хотите отследить эту ошибку, установите флажок «Пауза при проблемах» в основном потоке. В большинстве случаев исправить это несложно, отправив проблемную строку в основную очередь.
У меня была такая же проблема при попытке обновить сообщение об ошибке в UILabel в том же ViewController (требуется некоторое время для обновления данных при попытке сделать это с обычным кодированием). Я использовал DispatchQueue
в Swift 3 Xcode 8, и он работает.
У меня возникла эта проблема при перезагрузке данных в UITableView. Простая отправка перезагрузки следующим образом устранила проблему для меня.
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
Основная проблема с «Это приложение изменяет механизм автоматического размещения из фонового потока» заключается в том, что кажется, что оно регистрируется в журнале спустя долгое время после возникновения реальной проблемы, что может затруднить устранение неполадок.
Мне удалось решить проблему, создав три символических точки останова.
Отладка> Точки останова> Создать символическую точку останова ...
Точка останова 1:
Символ:
-[UIView setNeedsLayout]
Условие:
!(BOOL)[NSThread isMainThread]
Точка останова 2:
Символ:
-[UIView layoutIfNeeded]
Условие:
!(BOOL)[NSThread isMainThread]
Точка останова 3:
Символ:
-[UIView updateConstraintsIfNeeded]
Условие:
!(BOOL)[NSThread isMainThread]
С этими точками останова вы можете легко получить разрыв в фактической строке, где вы неправильно вызываете методы пользовательского интерфейса в неосновном потоке.
Очевидно, вы делаете какое-то обновление пользовательского интерфейса в фоновом потоке. Невозможно предсказать, где именно, не видя вашего кода.
Это может произойти в следующих ситуациях:
Вы можете что-то делать в фоновом потоке и не использовать. Находясь в той же функции, этот код легче обнаружить.
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()
}
}
Вы не должны изменять пользовательский интерфейс вне основного потока! UIKit не является потокобезопасным, поэтому, если вы это сделаете, возникнут указанные выше проблемы, а также некоторые другие странные проблемы. Приложение может даже вылететь.
Итак, чтобы выполнять операции UIKit, вам нужно определить блок и позволить ему выполняться в основной очереди: например,
NSOperationQueue.mainQueue().addOperationWithBlock {
}
Была та же проблема, потому что я использовал performSelectorInBackground
.
У меня возникла эта проблема с момента обновления до iOS 9 SDK, когда я вызывал блок, который обновлял пользовательский интерфейс в обработчике завершения асинхронного запроса NSURLConnection. Помещение вызова блока в dispatch_async с использованием dispatch_main_queue решило проблему.
В iOS 8 все работало нормально.
Для меня это сообщение об ошибке возникло из баннера из Admob SDK.
Я смог отследить происхождение до «WebThread», установив условную точку останова.
Затем я смог избавиться от проблемы, инкапсулируя создание баннера с помощью:
dispatch_async(dispatch_get_main_queue(), ^{
_bannerForTableFooter = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
...
}
Я не знаю, почему это помогло, поскольку я не вижу, как этот код был вызван из неосновного потока.
Надеюсь, это поможет кому угодно.
Когда вы пытаетесь обновить значение текстового поля или добавить подпредставление внутри фонового потока, вы можете получить эту проблему. По этой причине вы должны поместить такой код в основной поток.
Вам необходимо обернуть методы, вызывающие обновления пользовательского интерфейса, с помощью 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"
}
}
Ошибка «это приложение изменяет механизм автоматического размещения из фонового потока» регистрируется в консоли спустя долгое время после того, как возникла реальная проблема, поэтому отладка может быть сложной без использования точки останова.
Я использовал ответ @ markussvensson, чтобы обнаружить свою проблему, и нашел ее с помощью этой символической точки останова (Отладка> Точки останова> Создать символическую точку останова):
- Символы:
[UIView layoutIfNeeded]
или[UIView updateConstraintsIfNeeded]
- Условие:
!(BOOL)[NSThread isMainThread]
Создайте и запустите приложение на эмуляторе и повторите шаги, которые приводят к появлению сообщения об ошибке (приложение будет работать медленнее, чем обычно!). Затем Xcode остановит приложение и отметит строку кода (например, вызов функции), которая обращается к пользовательскому интерфейсу из фонового потока.
Вы получаете аналогичное сообщение об ошибке при отладке с помощью операторов печати без использования dispatch_async Итак, когда вы получите это сообщение об ошибке, самое время использовать
Swift 4
DispatchQueue.main.async { //code }
Swift 3
DispatchQueue.main.async(){ //code }
Более ранние версии Swift
dispatch_async(dispatch_get_main_queue()){ //code }
Похожие вопросы
Связанные вопросы
Новые вопросы
swift
Swift — это язык программирования общего назначения, разработанный Apple Inc., впервые выпущенный в 2014 году для своих платформ и Linux. Swift имеет открытый исходный код. Используйте тег только для вопросов о языковых функциях или необходимости кода в Swift. Используйте теги [ios], [ipados], [macos], [watch-os], [tvos], [swiftui], [cocoa-touch] и [cocoa] для (не зависящих от языка) вопросов о платформах или рамки.