I'm having an issue where our application is crashing when the user taps the profile picture to upload their photo to the app. The app sends an authorization request to the user, and this crash happens immediantly once the "allow" button is tapped.
Maybe relevant information is that this is not the root view controller. The registration process has a series of pages on the same Storyboard. This is occuring on any page where I need to request permissions that isn't the main root controller.
I have attempted to place the PhotoAuthorization block of code into a DispatchQueue.main.async, but that didn't seem to work. This is legacy code by a former developer, so I'm still working on fixing up some stuff.
Code block suspected of crashing the app:
func checkPermission() {
let photoAuthStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthStatus {
case .authorized:
self.showPhotoActionSheet()
case .notDetermined:
PHPhotoLibrary.requestAuthorization({ (newStatus) in
if newStatus == PHAuthorizationStatus.authorized {
self.showPhotoActionSheet()
}
})
case .restricted:
showPermissionRequestReason()
case .denied:
showPermissionRequestReason()
}
}
func showPhotoActionSheet() {
let actionSheet = YoutubeActionController()
actionSheet.addAction(Action(ActionData(title: "Take Photo", image: UIImage(named: "ic_photo_camera")!), style: .default, handler: { action in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
self.imagePicker.sourceType = .camera
self.imagePicker.allowsEditing = true
self.present(self.imagePicker, animated: true, completion: nil)
}
}))
actionSheet.addAction(Action(ActionData(title: "Choose from Camera Roll", image: UIImage(named: "ic_photo_album")!), style: .default, handler: { action in
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) {
self.imagePicker.sourceType = .savedPhotosAlbum
self.imagePicker.allowsEditing = true
self.present(self.imagePicker, animated: true, completion: nil)
}
}))
actionSheet.addAction(Action(ActionData(title: "Cancel", image: UIImage(named: "ic_cancel")!), style: .cancel, handler: nil))
present(actionSheet, animated: true, completion: nil)
}
Find the traceback below. Any help is greatly appreciated!
2020-01-23 13:39:23.878772+0000 ***[89799:17598462] *** Assertion failure in -[FBSSerialQueue assertOnQueue], /BuildRoot/Library/Caches/com.apple.xbs/Sources/FrontBoardServices_Sim/FrontBoard-626.2/FrontBoardServices/FBSSerialQueue.m:98
2020-01-23 13:39:23.990535+0000 ***[89799:17598462] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'threading violation: expected the main thread'
*** First throw call stack:
(
0 CoreFoundation 0x0000000115f7102e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x0000000115ddeb20 objc_exception_throw + 48
2 CoreFoundation 0x0000000115f70da8 +[NSException raise:format:arguments:] + 88
3 Foundation 0x000000010f613b61 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191
4 FrontBoardServices 0x000000011c344a8b -[FBSSerialQueue assertOnQueue] + 236
5 FrontBoardServices 0x000000011c2f77b9 -[FBSSceneImpl updateClientSettings:withTransitionContext:] + 70
6 FrontBoardServices 0x000000011c2f7a04 -[FBSSceneImpl updateClientSettingsWithTransitionBlock:] + 154
7 FrontBoardServices 0x000000011c2f7929 -[FBSSceneImpl updateClientSettingsWithBlock:] + 110
8 UIKitCore 0x00000001200c7aa0 -[FBSScene(UIApp) updateUIClientSettingsWithBlock:] + 160
9 UIKitCore 0x000000011fcbf5f6 -[_UISystemAppearanceManager updateScreenEdgesDeferringSystemGestures] + 374
10 UIKitCore 0x000000011ff229e2 __70-[UIViewController setNeedsUpdateOfScreenEdgesDeferringSystemGestures]_block_invoke_2 + 118
11 UIKitCore 0x000000011ff00cb5 -[UIViewController _updateSystemAppearanceWithRecursionBlock:action:] + 295
12 UIKitCore 0x000000011ff22629 -[UIViewController _setPresentedStatusBarViewController:] + 220
13 UIKitCore 0x000000011ff129c3 -[UIViewController _presentViewController:modalSourceViewController:presentationController:animationController:interactionController:completion:] + 1381
14 UIKitCore 0x000000011ff143c6 -[UIViewController _presentViewController:withAnimationController:completion:] + 4349
15 UIKitCore 0x000000011ff16c47 __63-[UIViewController _presentViewController:animated:completion:]_block_invoke + 98
16 UIKitCore 0x000000011ff1715f -[UIViewController _performCoordinatedPresentOrDismiss:animated:] + 511
17 UIKitCore 0x000000011ff16ba5 -[UIViewController _presentViewController:animated:completion:] + 187
18 UIKitCore 0x000000011ff16e0c -[UIViewController presentViewController:animated:completion:] + 150
19 *** 0x000000010dc472ca $s14***26RegistrationViewControllerC20showPhotoActionSheetyyF + 2522
20 *** 0x000000010dc462b9 $s14***26RegistrationViewControllerC15checkPermissionyyFySo21PHAuthorizationStatusVcfU_ + 201
21 *** 0x000000010dc46355 $sSo21PHAuthorizationStatusVIegy_ABIeyBy_TR + 53
22 Photos 0x0000000116a72643 __39+[PHPhotoLibrary requestAuthorization:]_block_invoke + 52
23 AssetsLibraryServices 0x000000013927ff7e __79-[PLPrivacy _isPhotosAccessAllowedWithScope:forceHandler:accessAllowedHandler:]_block_invoke.14 + 501
24 AssetsLibraryServices 0x000000013924b60c __pl_dispatch_async_block_invoke + 25
25 libdispatch.dylib 0x0000000117a02848 _dispatch_call_block_and_release + 12
26 libdispatch.dylib 0x0000000117a037b9 _dispatch_client_callout + 8
27 libdispatch.dylib 0x0000000117a09526 _dispatch_lane_serial_drain + 707
28 libdispatch.dylib 0x0000000117a09f5c _dispatch_lane_invoke + 388
29 libdispatch.dylib 0x0000000117a13ff9 _dispatch_workloop_worker_thread + 626
30 libsystem_pthread.dylib 0x00007fff51bfd611 _pthread_wqthread + 421
31 libsystem_pthread.dylib 0x00007fff51bfd3fd start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
The error tells you want to do:
reason: 'threading violation: expected the main thread'
Many times, when you pass a closure, you could be called back on a background thread. But, if you want to do anything with the UI, that must be done on the main thread. We use DispatchQueue.main.async
to pass a block to the main queue and have it run on the main thread asynchronously,
In
PHPhotoLibrary.requestAuthorization({ (newStatus) in
if newStatus == PHAuthorizationStatus.authorized {
self.showPhotoActionSheet()
}
})
You need to dispatch to the main thread
PHPhotoLibrary.requestAuthorization({ (newStatus) in
if newStatus == PHAuthorizationStatus.authorized {
DispatchQueue.main.async {
self.showPhotoActionSheet()
}
}
})
It looks like you might be calling checkPermission on the background. If so, you also need to wrap the call to:
self.showPhotoActionSheet()
From the call stack -- it looks like this might be the one you are having problems with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With