error : This application is modifying the autolayout engine from a background thread
此问题是由于在子的线程中更新了 UI 所导致的,
解决方法:找到在子线程中更新ui的代码,将他们在主线程更新即可;
但 Xcode 提示错误信息不太明确,在调用堆栈根本无法发现错误是由哪句代码导致的,当然要调试这个问题可以使用PSPDFUIKitMainThreadGuard.m 定位错误的代码,这个是 PSPDFKit 框架中用到的专门查找代码中哪些代码会在辅线程中更新 UI 的工具,PSPDFUIKitMainThreadGuard是通过在拦截所有 UIKit 中对 setNeedsDisplay 和 setNeedsLayout 的调用,判断当前线程如果是子线程则抛出异常
使用时将PSPDFUIKitMainThreadGuard手动拖入项目,并将其编译选项设置为 -fno-objc-arc
运行后,当有任何类似的错误发生时,Xcode 会在错误发生的代码停下
部分代码:
for (NSString *selStr in @[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) {
SEL selector = NSSelectorFromString(selStr);
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", selStr]);
if ([selStr hasSuffix:@":"]) {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self, CGRect r) {
// Check for window, since *some* UIKit methods are indeed thread safe.
// https://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html
/*
Drawing to a graphics context in UIKit is now thread-safe. Specifically:
The routines used to access and manipulate the graphics context can now correctly handle contexts residing on different threads.
String and image drawing is now thread-safe.
Using color and font objects in multiple threads is now safe to do.
*/
if (_self.window) PSPDFAssertIfNotMainThread();
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
});
}else {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self) {
if (_self.window) {
if (!NSThread.isMainThread) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
dispatch_queue_t queue = dispatch_get_current_queue();
#pragma clang diagnostic pop
// iOS 8 layouts the MFMailComposeController in a background thread on an UIKit queue.
// https://github.com/PSPDFKit/PSPDFKit/issues/1423
if (!queue || !strstr(dispatch_queue_get_label(queue), "UIKit")) {
PSPDFAssertIfNotMainThread();
}
}
}
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
});
}
}
}
}