ios
ios copied to clipboard
UI API called on a background thread: -[UIView setNeedsLayout]
Describe the bug: We managed to update our app from NS6 to NS8 but we are getting this crash after we accessed a user's photos/videos from their device on iOS. I included our code we use to retrieve these items from the device as It could also be a factor. Please let me know if there is any other information required.
Environment:
{
"author": "www.firstview.co”,
"dependencies": {
"@nativescript-community/ui-lottie": "^4.1.2",
"@nativescript/background-http": "^5.0.2",
"@nativescript/core": "~8.1.0",
"@nativescript/firebase": "^11.1.3",
"@nativescript/local-notifications": "^5.0.3",
"@nativescript/theme": "3.0.1",
"@triniwiz/nativescript-socketio": "^5.0.1",
"@triniwiz/nativescript-toasty": "^4.1.3",
"@vue/devtools": "^5.3.4",
"moment": "^2.24.0",
"nativescript-android-utils": "^1.0.2",
"nativescript-calendar": "~3.0.0",
"nativescript-contacts": "^1.6.4",
"nativescript-dna-deviceinfo": "~3.7.1",
"nativescript-permissions": "~1.3.11",
"nativescript-sentry": "~2.0.1",
"nativescript-socketio": "~3.3.1",
"nativescript-ui-gauge": "~8.0.0",
"nativescript-ui-sidedrawer": "~10.0.1",
"nativescript-vue": "~2.9.0",
"nativescript-vue-devtools": "~1.5.1",
"nativescript-webview-interface": "~1.4.4",
"vuex": "~3.6.2"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@nativescript/android": "8.0.0",
"@nativescript/ios": "8.1.0",
"@nativescript/types": "~8.1.1",
"@nativescript/webpack": "~5.0.0",
"babel-loader": "^8.0.2",
"nativescript-vue-template-compiler": "^2.9.0",
"sass": "^1.39.2",
"typescript": "~4.0.0",
"vue-loader": "^15.4.0"
},
"main": "./app/main.js"
}
Console Log:
CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces, or set CA_ASSERT_MAIN_THREAD_TRANSACTIONS=1 to abort when an implicit transaction isn't created on a main thread.
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 CoreAutoLayout 0x000000019a4b8dfc 09D27E78-A4B2-32D4-AB19-31802F490355 + 19964
1 CoreAutoLayout 0x000000019a4bba58 09D27E78-A4B2-32D4-AB19-31802F490355 + 31320
2 UIKitCore 0x000000018560d088 3F83EF9A-7492-3FEC-A486-5FC2A1E1B092 + 1736840
3 UIKitCore 0x00000001855e2ae8 3F83EF9A-7492-3FEC-A486-5FC2A1E1B092 + 1563368
4 QuartzCore 0x0000000186c4cc4c 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 248908
5 QuartzCore 0x0000000186c3fd40 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 195904
6 QuartzCore 0x0000000186c534a4 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 275620
7 QuartzCore 0x0000000186c5c08c 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 311436
8 QuartzCore 0x0000000186caf348 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 652104
9 libsystem_pthread.dylib 0x00000001dcb20ec4
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
*** First throw call stack:
(0x183191cac 0x19a200758 0x19a4b8edc 0x19a4bba58 0x18560d088 0x1855e2ae8 0x186c4cc4c 0x186c3fd40 0x186c534a4 0x186c5c08c 0x186caf348 0x1dcb20ec4 0x1dcb23d3c 0x1dcb1f370 0x1dcb1efc0 0x1dcb1eaa4)
Xcode Log:
Main Thread Checker: UI API called on a background thread: -[UIView setNeedsLayout]
PID: 4461, TID: 1122759, Thread name: (none), Queue name: com.apple.photos.accessCallbacks, QoS: 0
Backtrace:
4 NativeScript 0x00000001025d0044 ffi_call_SYSV + 68
5 NativeScript 0x00000001025cf1d8 ffi_call_int + 968
6 NativeScript 0x0000000102571854 _ZN3tns7Interop20CallFunctionInternalERNS_10MethodCallE + 428
7 NativeScript 0x00000001024db32c _ZN3tns12ArgConverter6InvokeEN2v85LocalINS1_7ContextEEEP10objc_classNS2_INS1_6ObjectEEERNS_6V8ArgsEPKNS_10MethodMetaEb + 780
8 NativeScript 0x000000010252ebc8 _ZN3tns15MetadataBuilder12InvokeMethodEN2v85LocalINS1_7ContextEEEPKNS_10MethodMetaENS2_INS1_6ObjectEEERNS_6V8ArgsENSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEb + 88
9 NativeScript 0x000000010252e454 _ZN3tns15MetadataBuilder14MethodCallbackERKN2v820FunctionCallbackInfoINS1_5ValueEEE + 220
10 NativeScript 0x0000000102663e60 _ZN2v88internal25FunctionCallbackArguments4CallENS0_15CallHandlerInfoE + 544
11 NativeScript 0x0000000102663360 _ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0_11MaybeHandleINS0_6ObjectEEEPNS0_7IsolateENS0_6HandleINS0_10HeapObjectEEESA_NS8_INS0_20FunctionTemplateInfoEEENS8_IS4_EENS0_16BuiltinArgumentsE + 524
12 NativeScript 0x0000000102662af8 _ZN2v88internalL26Builtin_Impl_HandleApiCallENS0_16BuiltinArgumentsEPNS0_7IsolateE + 228
13 NativeScript 0x0000000102d3e3cc Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit + 108
14 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
15 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
16 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
17 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
18 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
19 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
20 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
21 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
22 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
23 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
24 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
25 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
26 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
27 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
28 NativeScript 0x0000000102cd536c Builtins_JSEntryTrampoline + 172
29 NativeScript 0x0000000102cd5004 Builtins_JSEntry + 164
30 NativeScript 0x00000001027afa70 _ZN2v88internal12_GLOBAL__N_16InvokeEPNS0_7IsolateERKNS1_12InvokeParamsE + 2532
31 NativeScript 0x00000001027af058 _ZN2v88internal9Execution4CallEPNS0_7IsolateENS0_6HandleINS0_6ObjectEEES6_iPS6_ + 216
32 NativeScript 0x000000010293ad14 _ZN2v88internal6Object23SetPropertyWithAccessorEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEE + 864
33 NativeScript 0x000000010293e804 _ZN2v88internal6Object19SetPropertyInternalEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEENS0_11StoreOriginEPb + 420
34 NativeScript 0x000000010293e584 _ZN2v88internal6Object11SetPropertyEPNS0_14LookupIt2021-10-13 10:27:21.810471+0200 mobilesafenative[4461:1122759] [reports] Main Thread Checker: UI API called on a background thread: -[UIView setNeedsLayout]
PID: 4461, TID: 1122759, Thread name: (none), Queue name: com.apple.photos.accessCallbacks, QoS: 0
Backtrace:
4 NativeScript 0x00000001025d0044 ffi_call_SYSV + 68
5 NativeScript 0x00000001025cf1d8 ffi_call_int + 968
6 NativeScript 0x0000000102571854 _ZN3tns7Interop20CallFunctionInternalERNS_10MethodCallE + 428
7 NativeScript 0x00000001024db32c _ZN3tns12ArgConverter6InvokeEN2v85LocalINS1_7ContextEEEP10objc_classNS2_INS1_6ObjectEEERNS_6V8ArgsEPKNS_10MethodMetaEb + 780
8 NativeScript 0x000000010252ebc8 _ZN3tns15MetadataBuilder12InvokeMethodEN2v85LocalINS1_7ContextEEEPKNS_10MethodMetaENS2_INS1_6ObjectEEERNS_6V8ArgsENSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEb + 88
9 NativeScript 0x000000010252e454 _ZN3tns15MetadataBuilder14MethodCallbackERKN2v820FunctionCallbackInfoINS1_5ValueEEE + 220
10 NativeScript 0x0000000102663e60 _ZN2v88internal25FunctionCallbackArguments4CallENS0_15CallHandlerInfoE + 544
11 NativeScript 0x0000000102663360 _ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0_11MaybeHandleINS0_6ObjectEEEPNS0_7IsolateENS0_6HandleINS0_10HeapObjectEEESA_NS8_INS0_20FunctionTemplateInfoEEENS8_IS4_EENS0_16BuiltinArgumentsE + 524
12 NativeScript 0x0000000102662af8 _ZN2v88internalL26Builtin_Impl_HandleApiCallENS0_16BuiltinArgumentsEPNS0_7IsolateE + 228
13 NativeScript 0x0000000102d3e3cc Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit + 108
14 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
15 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
16 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
17 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
18 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
19 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
20 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
21 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
22 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
23 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
24 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
25 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
26 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
27 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
28 NativeScript 0x0000000102cd536c Builtins_JSEntryTrampoline + 172
29 NativeScript 0x0000000102cd5004 Builtins_JSEntry + 164
30 NativeScript 0x00000001027afa70 _ZN2v88internal12_GLOBAL__N_16InvokeEPNS0_7IsolateERKNS1_12InvokeParamsE + 2532
31 NativeScript 0x00000001027af058 _ZN2v88internal9Execution4CallEPNS0_7IsolateENS0_6HandleINS0_6ObjectEEES6_iPS6_ + 216
32 NativeScript 0x000000010293ad14 _ZN2v88internal6Object23SetPropertyWithAccessorEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEE + 864
33 NativeScript 0x000000010293e804 _ZN2v88internal6Object19SetPropertyInternalEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEENS0_11StoreOriginEPb + 420
34 NativeScript 0x000000010293e584 _ZN2v88internal6Object11SetPropertyEPNS0_14LookupIt
Our Service Fetching Images/Photos From the Device:
import { Device } from '@nativescript/core'
import { Sentry } from 'nativescript-sentry';
let osVersion = Device.osVersion;
@NativeClass
export class IndexMediaService {
constructor() {
}
/**
* Fetch media from device
*
* @param mediaTypes
* @returns array
*/
fetchMedia(mediaTypes) {
let getPatternFromDes = function (des, pattern, ret=0) {
let patternUrlMatch = des.match(pattern);
return (patternUrlMatch !== null) ? patternUrlMatch[ret]: '';
}
let fetchOptions:PHFetchOptions = PHFetchOptions.alloc().init();
let sortDescriptors = NSArray.arrayWithObject(
NSSortDescriptor.sortDescriptorWithKeyAscending("creationDate", false)
);
fetchOptions.sortDescriptors = sortDescriptors;
fetchOptions.predicate = NSPredicate.predicateWithFormatArgumentArray(
"mediaType = %d", NSArray.arrayWithObject(mediaTypes)
);
let fetchResult:PHFetchResult<PHAsset> = PHAsset.fetchAssetsWithOptions(fetchOptions);
let mediaOnDevice = [];
let mediaNotOnDevice = [];
let mediaCnt = 0;
fetchResult.enumerateObjectsUsingBlock((asset:PHAsset, index, stop) => {
let media = {
type: '',
mimeType: '',
sourceType: this.getSourceType(asset.sourceType),
mediaSubTypes: this.getSubType(asset.mediaSubtypes),
playbackStyle: this.getPlaybackStyle(asset.playbackStyle),
uti: '',
displayName: '',
id: '',
locallyAvailable: 'NO',
imageUri: '',
videoUri: '',
width: 0,
height: 0,
size: 0,
analysisType: '',
cplResourceType: '',
isCurrent: 'NO',
dateTaken: asset.creationDate,
dateAdded: asset.creationDate,
dateModified: asset.modificationDate,
orientation: '',
backedUp: false
};
let assetResources = PHAssetResource.assetResourcesForAsset(asset);
assetResources.enumerateObjectsUsingBlock((assetResource, ind1, stp1) => {
let type = this.getMediaType(assetResource.type);
let des = assetResource.debugDescription;
try{
if (parseInt(osVersion) >= 13) {
media.type = getPatternFromDes(des, "type:.*").replace("type: ", "");
media.uti = getPatternFromDes(des, "uti:.*").replace("uti: ", "");
media.locallyAvailable = getPatternFromDes(des, "locallyAvailable:.*").replace("locallyAvailable: ", "");
media.imageUri = getPatternFromDes(des, "file:.*").replace("file://", "");
media.videoUri = getPatternFromDes(des, "file:.*").replace("file://", "");
media.width = getPatternFromDes(des, "width:.*").replace("width: ", "");
media.height = getPatternFromDes(des, "height:.*").replace("height: ", "");
media.analysisType = getPatternFromDes(des, "analysisType:.*").replace("analysisType: ", "");
media.cplResourceType = getPatternFromDes(des, "cplResourceType:.*").replace("cplResourceType: ", "");
media.isCurrent = getPatternFromDes(des, "isCurrent:.*").replace("isCurrent: ", "");
} else if (parseInt(osVersion) >= 12 && parseInt(osVersion) < 13) {
media.type = getPatternFromDes(des, "type=(.*) size", 1);
media.uti = getPatternFromDes(des, "uti=(.*) filename", 1);
} else if (parseInt(osVersion) >= 11 && parseInt(osVersion) < 12) {
media.type = getPatternFromDes(des, "type=(.*) size", 1);
media.uti = getPatternFromDes(des, "uti=(.*) filename", 1);
}
console.log("assetResource", des)
media.displayName = assetResource.originalFilename ? assetResource.originalFilename.toString() : getPatternFromDes(des, "filename:.*").replace("filename: ", "");
media.id = assetResource.assetLocalIdentifier ? assetResource.assetLocalIdentifier.toString() : getPatternFromDes(des, "asset:.*").replace("asset: ", "")
console.log("media.id", getPatternFromDes(des, "asset:.*").replace("asset: ", ""))
media.mimeType = this.getMimeType(media.displayName) ? this.getMimeType(media.displayName) : "noMimeType"
media.size = assetResource.valueForKey('fileSize') ? assetResource.valueForKey('fileSize') : "noFileSize"
}catch(err){
let errorObj = {
errorMessage: err,
mediaObj: media
}
Sentry.captureException(err, {});
Sentry.captureMessage(JSON.stringify(errorObj))
throw errorObj
}
});
if (media.type === 'photo' && media.imageUri === '' && media.locallyAvailable === 'YES') {
const opt = PHImageRequestOptions.new();
opt.version = PHImageRequestOptionsVersion.Current;
PHImageManager.defaultManager().requestImageDataForAssetOptionsResultHandler(
asset,
opt,
(imageData, dataUTI, orientation, info) => {
try{
media.imageUri = info.objectForKey("PHImageFileURLKey").toString().replace("file://", "");
}
catch(err){
let errorObj = {
errorMessage: err,
mediaObj: media
}
console.error(errorObj)
Sentry.captureException(err, {});
Sentry.captureMessage(JSON.stringify(errorObj))
throw errorObj
}
if (media.imageUri !== '' && media.mimeType !== '') {
mediaOnDevice.push(media);
} else {
mediaNotOnDevice.push(media);
}
mediaCnt++;
}
)
} else if (media.type === 'video' && media.videoUri === '' && media.locallyAvailable === 'YES') {
let opt: PHVideoRequestOptions;
opt = PHVideoRequestOptions.new();
opt.version = PHVideoRequestOptionsVersion.Original;
PHImageManager.defaultManager().requestAVAssetForVideoOptionsResultHandler(
asset,
opt,
(avasset, audioMix, info) => {
let avurlAsset = avasset as AVURLAsset;
media.videoUri = avurlAsset.URL.toString().replace("file://", "");
if (media.videoUri !== '' && media.mimeType !== '') {
mediaOnDevice.push(media);
} else {
mediaNotOnDevice.push(media);
}
mediaCnt++;
}
)
} else {
if (media.locallyAvailable === 'YES' && media.imageUri !== '' && media.mimeType !== '') {
mediaOnDevice.push(media);
} else {
mediaNotOnDevice.push(media);
}
mediaCnt++;
}
})
return mediaOnDevice;
}
/**
* Get mime type
* @param fileName
* @returns string
*/
getMimeType(fileName) {
let extToMimes = {
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'heic': "image/heic",
'mp4': "video/mp4",
'mov': "video/quicktime",
}
let ext = fileName.toLowerCase().split('.').pop();
if (extToMimes.hasOwnProperty(ext)) {
return extToMimes[ext];
}
return '';
}
/**
* Get media type
* @param mediaId
* @returns String
*/
getMediaType(mediaId) {
switch (mediaId) {
case PHAssetMediaType.Audio:
return 'Audio'
break;
case PHAssetMediaType.Image:
return 'Image';
break;
case PHAssetMediaType.Video:
return 'Video';
default:
return 'Unkown';
break;
}
}
/**
* Get source type
* @param sourceId
* @returns string
*/
getSourceType(sourceId) {
switch (sourceId) {
case PHAssetSourceType.UserLibrary:
return 'User Library';
break;
case PHAssetSourceType.iTunesSynced:
return 'iTunes Synced'
break;
case PHAssetSourceType.CloudShared:
return 'Cloud Shared'
break;
default:
return 'None'
break;
}
}
/**
* Get media sub types
* @param subTypeId
* @returns string
*/
getSubType(subTypeId) {
switch (subTypeId) {
case PHAssetMediaSubtype.PhotoPanorama:
return 'Photo Panorama';
break;
case PHAssetMediaSubtype.PhotoHDR:
return 'Photo HDR';
break;
case PHAssetMediaSubtype.PhotoScreenshot:
return 'Photo Screenshot';
break;
case PHAssetMediaSubtype.PhotoLive:
return 'Photo Live';
break;
case PHAssetMediaSubtype.PhotoDepthEffect:
return 'Photo Depth Effect';
break;
case PHAssetMediaSubtype.VideoStreamed:
return 'Video Streamed';
break;
case PHAssetMediaSubtype.VideoHighFrameRate:
return 'Video High Frame Rate';
break;
case PHAssetMediaSubtype.VideoTimelapse:
return 'Video Timelapse';
break;
default:
return 'None';
break;
}
}
/**
* Get playback style
* @param style
* @returns string
*/
getPlaybackStyle(style) {
switch (style) {
case PHAssetPlaybackStyle.Image:
return 'Image';
break;
case PHAssetPlaybackStyle.ImageAnimated:
return 'Image Animated';
break;
case PHAssetPlaybackStyle.LivePhoto:
return 'Live Photo';
break;
case PHAssetPlaybackStyle.Video:
return 'Video';
break;
case PHAssetPlaybackStyle.VideoLooping:
return 'Video Looping';
break;
default:
return 'Unsupported'
break;
}
}
/**
* Get all video
* @returns array
*/
fetchVideos() {
// console.log('Fetch Videos');
return this.fetchMedia(PHAssetMediaType.Video);
}
/**
* Get all photos
* @returns all photos
*/
fetchPhotos() {
// console.log('Fetch Photos');
return this.fetchMedia(PHAssetMediaType.Image);
}
}
Very old issue, using latest everything. I am making use of NFC but i don't know if its related.