Closed Arvin-J closed 5 years ago
[reports] Main Thread Checker: UI API called on a background thread: -[UIApplication applicationState]
PID: 850, TID: 218915, Thread name: com.apple.CoreMotion.MotionThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 0
Backtrace:
4 libobjc.A.dylib 0x0000000185eb3894
This only happens in iOS 12. Many libraries are affected by this. I believe Apple simply improved their Main Thread Checker and it surfaced a lot of UI activity on background threads.
I don't think MBProgressHUD
uses -[UIApplication applicationState]
and that backtrace is not really helpful (all system libraries, no symbols). How does this relate to MBProgressHUD
?
I don't have a better backtrace, but it only appears when using MBProgressHUD. Seems like it's only a problem on Xs and Xs Max.
You can see that others have the problem by searching on Github: https://github.com/search?q=background+thread%3A+-%5BUIApplication+applicationState%5D&type=Issues
MBProgressHUD
uses motion effects, but those are set up on the main thread and there are no delegates or block callbacks involved that could be pushing the execution on a secondary thread. See updateBezelMotionEffects
:
I'd assume this is a system issue when motion effects are used. If that assertion is annoying or you want to play it safe, you can disable them by setting defaultMotionEffectsEnabled
to NO
. Their effect is barely noticeable anyways.
Closing this, as I don't really see anything we could do about it in client-side code.
Thanks all @matej @ciffa
@matej
I already disable them by setting defaultMotionEffectsEnabled
to NO, But it don't work.
and i find defaultMotionEffectsEnabled
is YES when MBProgressHUD init.
It's YES after initialization, but you can set it to NO
afterwards. No idea what's up if that doesn't help.
Any solution for this? in the code: let hud = MBProgressHUD.showAdded(to: self.view.window!, animated: true) its happening.. so setting defaultMotionEffectsEnabled afterwards does not prevent the error. testing on iPhone XS Max
Can we initialize MBProgressHud without showing it?? maybe we can set defaultMotionEffectsEnabled = false before showing it.. i checked that im on the main thread..
Just initialize the hud, configure it and present it. You can check what that convenience initializer does and simply do the same in your code + disable motion effects.
The same as @xZeok testing on iPhone XS Max
Main Thread
Thread 1 Queue : com.apple.main-thread (serial)
0 __ulock_wait ()
7 -[UIView addMotionEffect:] ()
8 -[MBProgressHUD updateBezelMotionEffects]
9 -[MBProgressHUD setupViews]
10 -[MBProgressHUD commonInit]
11 -[MBProgressHUD initWithFrame:]
12 -[MBProgressHUD initWithView:]
13 +[MBProgressHUD showHUDAddedTo:animated:]
24 UIApplicationMain ()
25 main
com.apple.CoreMotion.MotionThread (8)
#0 0x000000010292d6d4 in __main_thread_checker_on_report ()
#1 0x000000010292da38 in __ASSERT_API_MUST_BE_CALLED_FROM_MAIN_THREAD_FAILED__ ()
#2 0x000000010292ddfc in checker_c ()
#3 0x000000010292d654 in trampoline_c ()
#4 0x00000001028ed3fc in handler_start ()
#5 0x00000001c474b894 in -[NSObject performSelector:] ()
#6 0x00000001cafc8760 in ___lldb_unnamed_symbol1517$$CoreMotion ()
#7 0x00000001cafc8c94 in ___lldb_unnamed_symbol1539$$CoreMotion ()
#8 0x00000001cafc8ba4 in ___lldb_unnamed_symbol1536$$CoreMotion ()
#9 0x00000001caffa384 in ___lldb_unnamed_symbol2712$$CoreMotion ()
#10 0x00000001caffa3e4 in ___lldb_unnamed_symbol2715$$CoreMotion ()
#11 0x00000001c54e14d8 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ ()
#12 0x00000001c54e0dbc in __CFRunLoopDoBlocks ()
#13 0x00000001c54dc0c0 in __CFRunLoopRun ()
#14 0x00000001c54db494 in CFRunLoopRunSpecific ()
#15 0x00000001c54dc1f8 in CFRunLoopRun ()
#16 0x00000001caff9d1c in ___lldb_unnamed_symbol2700$$CoreMotion ()
#17 0x00000001c51569c8 in _pthread_body ()
#18 0x00000001c5156924 in _pthread_start ()
#19 0x00000001c515eddc in thread_start ()
Hm.. ok. Looks like updateBezelMotionEffects
is called from initialization so disabling mention effects still triggers an update in this code path.
yeah, so, the updateBezelMotionEffects function should be optional in initialization
Any update here? :(
Problem fixed for me with new iOS update (12.1.4)
no update here?
Problem fixed for me with new iOS update (12.1.4)
Doesn't work for me yet. Still Crashes on iOS 12.1.4 iPhone XS Max. Created issue on the ResearchKit Repo.
I've filed a rdar on bugreport.apple.com and engineering has marked my bug as a duplicate. Lets hope they fix this soon.
It is not fixed yet on iOS 12.2.
Compiling our app with Xcode 10.2 blocks the entire UI for a couple of seconds when we add an MBProgressHUD because of this issue.
^
我的xs,直接build的时候就会出现这个问题,但是再点击运行,或者直接拔掉线不连接电脑就没事。
@muzizhu007 i test, it's Ok,but why?
I cannot wait at all, I temporarily fixed it in my project -- Create a subclass of MBProgressHUD
, implement the areDefaultMotionEffectsEnabled
method which return NO
if iOS 12 && iPhone X Series, return [super areDefaultMotionEffectsEnabled]
otherwise.
I removed This library entirely. 🤷🏻♂️
Problem fixed for me with new iOS update (12.1.4)
It's broken again on 12.2.
I have been using this library for more than 6 years, First time I ever faced issues with it :(
@iwill 's solution worked for me however the method you have to override is areDefaultMotionEffectsEnabled
because that is defined as the getter for the property defaultMotionEffectsEnabled
@dpanzer Oh, yes. I actually used areDefaultMotionEffectsEnabled
in my project, thank you!
I encountered the same issue. Interestingly, without XCode attached, the dev device has no issues. Try to run your code without being connected to the Debugger. Also you can solve this problem by setting defaultMotionEffectsEnabled to NO in [MBProgressHUD commonInit] method.
I encountered the same issue. Interestingly, without XCode attached, the dev device has no issues. Try to run your code without being connected to the Debugger. Also you can solve this problem by setting defaultMotionEffectsEnabled to NO in [MBProgressHUD commonInit] method.
You don't hit the issue when you're not attached as you're not running with the Main Thread Checker enabled then like when you hit run from Xcode. Main thread checker is causing the main thread freeze as it records the stack. Folks can also avoid this by disabling the Main Thread Checker by going to Edit Scheme -> Run -> Diagnostics, but then you run the risk that you commit that and don't get the benefits of Main Thread Checker when your code is the cause.
This won't affect your users either as they're not running your app with Main Thread Checker.
As you can see from the radar, this happens the first time a CMMotionManager gets created. I've solved this by initializing a throwaway CMCoreMotionManager in my AppDelegate. You get the delay cause by the OS threading bug while your splash screen is up. I think this is better than getting a UI freeze in the app. Just in case useful.
I solved the problem in this way for the time being.
- (void)updateBezelMotionEffects {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
MBBackgroundView *bezelView = self.bezelView;
if (![bezelView respondsToSelector:@selector(addMotionEffect:)]) return;
// if (self.defaultMotionEffectsEnabled) {
// CGFloat effectOffset = 10.f;
// UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
// effectX.maximumRelativeValue = @(effectOffset);
// effectX.minimumRelativeValue = @(-effectOffset);
//
// UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
// effectY.maximumRelativeValue = @(effectOffset);
// effectY.minimumRelativeValue = @(-effectOffset);
//
// UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
// group.motionEffects = @[effectX, effectY];
//
// [bezelView addMotionEffect:group];
// } else {
NSArray *effects = [bezelView motionEffects];
for (UIMotionEffect *effect in effects) {
[bezelView removeMotionEffect:effect];
}
// }
#endif
}
Just set _defaultMotionEffectsEnabled = NO
and no care other method
there is no api to set defaultMotionEffectsEnabled tofalse
before it is used.
It is used in the "init" flow, and couldn't be changed prior to that. The ability to set the variable to false
should be brought up to pre-init, or init.
You can try this to guarantee -[UIApplication applicationState]
called on a main thread.
Do you have a Swift 4 solution? @dklinzh
Do you have a Swift 4 solution? @dklinzh
@Boggartfly It is the Swift 4 version below and recommended ONLY be used on Debug configuration :
#if DEBUG
extension UIApplication {
private class ApplicationState {
static let shared = ApplicationState()
var current = UIApplication.State.inactive
private init() {
let center = NotificationCenter.default
let mainQueue = OperationQueue.main
center.addObserver(forName: NSNotification.Name.UIApplicationDidEnterBackground, object: nil, queue: mainQueue) { (notification) in
self.current = UIApplication.shared.applicationState
}
center.addObserver(forName: NSNotification.Name.UIApplicationWillEnterForeground, object: nil, queue: mainQueue) { (notification) in
self.current = UIApplication.shared.applicationState
}
center.addObserver(forName: NSNotification.Name.UIApplicationDidFinishLaunching, object: nil, queue: mainQueue) { (notification) in
self.current = UIApplication.shared.applicationState
}
center.addObserver(forName: NSNotification.Name.UIApplicationDidBecomeActive, object: nil, queue: mainQueue) { (notification) in
self.current = UIApplication.shared.applicationState
}
center.addObserver(forName: NSNotification.Name.UIApplicationWillResignActive, object: nil, queue: mainQueue) { (notification) in
self.current = UIApplication.shared.applicationState
}
}
}
@objc
private var __applicationState: UIApplication.State {
if Thread.isMainThread {
return self.__applicationState
} else {
return ApplicationState.shared.current
}
}
/// FIXME: -[UIApplication applicationState] called on a background thread.
public static func mainThreadApplicationState() {
if let originalMethod = class_getInstanceMethod(UIApplication.self, #selector(getter: applicationState)),
let swizzledMethod = class_getInstanceMethod(UIApplication.self, #selector(getter: __applicationState)) {
_ = ApplicationState.shared
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
}
#endif
Since https://github.com/jdg/MBProgressHUD/pull/578 motion effects will not longer be created if defaultMotionEffectsEnabled
is set to NO
/ false
BEFORE the HUD is displayed.
Let me reiterate. This is not an issue with MBProgressHUD. This is a system bug triggered by using motion effects on certain devices. What you're seeing is the Xcode main thread checker catching the bug (UIKit access on the main thread). This is a debug time helper and won't crash your app in production (at least not in this way).
While I don't believe this is actually causing any issues in production, I still decided to modify the default value of this property to NO
in https://github.com/jdg/MBProgressHUD/commit/9a0d8e288df21958be225418d5b7791d42d97b20. This means you don't need to do anything other than updating to resolve the assertions.
You will however need to set defaultMotionEffectsEnabled
to YES
/ true
fro now on if you want motion effects.
@matej will you pls do a new release so we can update via pods/Carthage? thanks!
For now, I forked your repo and made 1.1.1
release.
So the Cartfile
would be:
github "ph4r05/MBProgressHUD" ~> 1.1.1
A Quick Fix
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
@interface MKProgressHUD:MBProgressHUD {
}
@end
@implementation MKProgressHUD
-(BOOL) areDefaultMotionEffectsEnabled{
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"12.0")) {
return FALSE;
}
return TRUE;
}
- (id)init {
return self;
}
@end
Main Thread Checker: UI API called on a background thread: -[UIApplication applicationState]