Post not yet marked as solved
Hello,
I'm investigating a crash where keyWindow is nil when I don't expect it to be nil.
I would like to understand when this can happen. Indeed,I could make a fix by guarding for nil values, but this would lead to an invalid state.
Context
We want to return quickly from application(didFinishLaunchingWithOptions:), so:
We set a view controller as a splash screen rootViewController => we mark the window with makeKeyAndVisible().
We queue initializations asynchronously on the main queue.
=> Basically, while the app is initializing starting, we're displaying a splash screen view controller.
When the app is done initializing, it needs to present the actual UI. A last asynchronous task on the main queue does this. We get keyWindow from UIApplication to set the new view controller with the actual UI. That's where we assume that it shouldn't be nil and force-unwrap it, but alas, in some instances it's nil.
Misc
This crash only happens when app built with Xcode 13.x, running on iOS 15.
I cannot reproduce this bug, and it has fairly little occurrence. (100s over 100000 of sessions)
I also attached a sample crash
Questions
Given that I made the window "key and visible" in step 1, what could cause the window to stop becoming "key".
What would be the correct way to get the window to set the new root view controller ?
I don't really want to guard against a nil value because then it means that I wouldn't be able to set my new rootViewController and the app would be stuck on the launch screen.
2021-12-01_18-16-29.7629_-0700-9b5855582b13262f154acae64dd3140ad49c84f3.crash
Thanks a lot!
Bruno
Post not yet marked as solved
Hello,
I'm trying to address the following crash from an old Objective-C code.
Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x88e8 object_isClass + 16
1 Foundation 0x1d748 KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED + 48
2 Foundation 0x2be10 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 284
3 Foundation 0x21c5c -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 72
4 Foundation 0x2daf8 _NSSetBoolValueAndNotify + 316
5 SDKCore 0x47854 __45-[CameraSession processPhoto:orientation:]_block_invoke_3 + 239 (CameraSession.m:239)
6 libdispatch.dylib 0x2914 _dispatch_call_block_and_release + 32
7 libdispatch.dylib 0x4660 _dispatch_client_callout + 20
8 libdispatch.dylib 0x12b60 _dispatch_main_queue_callback_4CF + 944
9 CoreFoundation 0x51cd4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
10 CoreFoundation 0xbeac __CFRunLoopRun + 2540
11 CoreFoundation 0x1f3b8 CFRunLoopRunSpecific + 600
12 GraphicsServices 0x138c GSEventRunModal + 164
13 UIKitCore 0x5196a8 -[UIApplication _run] + 1100
14 UIKitCore 0x2987f4 UIApplicationMain + 2092
15 MyApp 0x79bc main + 11 (main.swift:11)
16 ??? 0x102161a24 (Missing)
The crash is due to setting takingPhoto to NO in - (void)processPhoto:(AVCapturePhoto *)photo orientation:(UIDeviceOrientation)orientation.
From what I understand, the crash would be caused by a released observer receiving the notification, but I don't see how it's possible given the following code (this is an excerpt with relevant parts).
@implementation CameraSession
@synthesize takingPhoto = _takingPhoto;
- (void)dealloc {
[self _cleanupObservers];
}
- (instancetype)init {
self = [super init];
if (self) {
[self _setupObservers];
}
return self;
}
- (void)setTakingPhoto:(BOOL)takingPhoto {
if (!takingPhoto) {
[self.triggerDecider reset];
}
_takingPhoto = takingPhoto;
}
- (BOOL)isTakingPhoto {
return _takingPhoto;
}
- (void)takePhoto {
if (self.isTakingPhoto) {
return;
}
self.takingPhoto = YES;
// …
[self.capturePhotoOutput capturePhotoWithSettings:[self buildCapturePhotoSettings] delegate:self];
}
- (void)processPhoto:(AVCapturePhoto *)photo orientation:(UIDeviceOrientation)orientation {
dispatch_async(self.captureSessionQueue, ^{
[self.delegate cameraSessionDidSnapPhoto:self];
[self.cameraCaptureHandler processPhoto:photo orientation:orientation onSuccess:^(Scan *scan) {
dispatch_async(dispatch_get_main_queue(), ^{
self.takingPhoto = NO;
[self.delegate cameraSession:self didGenerateScan:scan];
});
} failure:^(NSError *error) {
self.takingPhoto = NO;
[self.delegate cameraSession:self didFailToSnapPhotoWithError:error];
}];
});
}
#pragma mark - KVO
- (void)_setupObservers {
[self addObserver:self forKeyPath:@"takingPhoto" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew context:CameraSessionKVOContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:self.captureSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionDidStartRunning:) name:AVCaptureSessionDidStartRunningNotification object:self.captureSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionDidStopRunning:) name:AVCaptureSessionDidStopRunningNotification object:self.captureSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionWasInterrupted:) name:AVCaptureSessionWasInterruptedNotification object:self.captureSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionInterruptionEnded:) name:AVCaptureSessionInterruptionEndedNotification object:self.captureSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)_cleanupObservers {
[self removeObserver:self forKeyPath:@"takingPhoto" context:CameraSessionKVOContext];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if (context == CameraSessionKVOContext) {
if (object == self && [keyPath isEqualToString:@"takingPhoto"]) {
// While taking the photo, stop processing video frames
// ...
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
Am I missing something here?
Thanks!
Bruno
Post not yet marked as solved
I'm fighting with the following error NSCocoaErrorDomain 513 reported by a very small number of users (~ 0.01%):Unable to create directory at path /var/mobile/Containers/Data/Application/EBE2C5D8-5AEC-4D62-9393-B19CAD598FE5/Documents/documents/FF2F88FB-2C07-4FA3-988E-58AD5C21F659/9A02F8A0-74EB-4ED6-81B6-4F40653856D3. Error: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “9A02F8A0-74EB-4ED6-81B6-4F40653856D3” in the folder “FF2F88FB-2C07-4FA3-988E-58AD5C21F659”." UserInfo={ NSFilePath=/var/mobile/Containers/Data/Application/EBE2C5D8-5AEC-4D62-9393-B19CAD598FE5/Documents/documents/FF2F88FB-2C07-4FA3-988E-58AD5C21F659/9A02F8A0-74EB-4ED6-81B6-4F40653856D3, NSUnderlyingError=0x15e09de00 { Error Domain=NSPOSIXErrorDomain Code=13 "Permission denied" } }This error means that the directory cannot be created because of a permission error. That's where I'm lost as the only reason I can see would be if I'm creating a file outside of my app's sandbox.The code generating this error:NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* documentsDirectory = [paths objectAtIndex:0]; NSString *directory = [documentsDirectory stringByAppendingPathComponent:documentsPathAndUUIDs]; NSError *error = nil; if (![[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:&error]) { NSError(@"Unable to create directory at path %@. Error: %@", directory, error); }A couple things worth noting:This path isn't saved, it's regenerated every time, so it's not as if the app container had changed between installs;The users seem to have available disk space;This affects at least iOS 9 (I don't have enough reports to know if it also affects iOS 10)Would anyone have a hint of why this could happen?
Post not yet marked as solved
Hello,We are having a systematic crash of the lldb-rpc-server when debugging our project, so we are unable to use the debugger. The crash is as follow:https://gist.github.com/bvirlet/89ecb0388c659932f5b572fa0d79e4f5I have submitted a crash report to Apple (FB7671116) but in the meantime I would be interested in a possible workaround.The problem is present for several developers, on different machines.Thanks!Bruno
Post not yet marked as solved
Hello,I have an issue with store and migrations and I cannot yet figure out what it is.I'm doing progressive manual migrations (not lightweight) and for some users, when I try to find a model compatible with the store, I'm unable to.This seems to happen for users with a brand new store. They install the app. They open it once and either face the issue immediately, or maybe they may have closed the app quickly after launch (eg. put in the background) and reopened it later. In some cases, there might have been an instance of a NSCocoaErrorDomain 134000 error on the first launch of the app when attempting to read the metadata from a store (that didn't exist yet).When the app opens, model.isConfiguration(withName:, compatibleWithStoreMetadata:) returns false, so I'm triggering the migration flow.I'm iterating on a list of models to try to find the one compatible with the user's store (it should be the most recent model anyways, since the app was just installed).None of my existing models seem to be compatible with the store. (Just to be clear, I haven't made incompatible changes to the model!)When I inspect the metadata of the store, I'm getting the following information:Store metadata: ["NSPersistenceFrameworkVersion": 851, "NSStoreType": SQLite, "NSStoreUUID": E968CF26-D6BB-494F-B48E-1CE0914818D2, "_NSAutoVacuumLevel": 2]Compared to a valid store:Store metadata: ["NSStoreUUID": 4A344B08-9C4C-4CC0-AF19-8D6717C7C691, "_NSAutoVacuumLevel": 2, "NSPersistenceFrameworkVersion": 320, "NSStoreType": SQLite, "NSStoreModelVersionHashes": { Document = <5634b6a0 65add26b 364c9074 a55f3ea2 b102452e d4db625b 3b2c70c9 a63d2c54>; DocumentPage = <812eeedf b5494a2a fe654167 0a6152cf 2f6879ea d29b6ac8 dc1ec6c1 2f5d5a12>; DocumentPageImage = <e86c0059 9a03c3ff 4d80be77 b32dc201 e197b18d 13999e64 7dfc0260 3bb4209e>;}, "NSStoreModelVersionIdentifiers": <__NSCFArray 0x604001e52150>(), "NSStoreModelVersionHashesVersion": 3]So somehow, the store seems incomplete without any information about the tables.Last, but not least, if I try to force the persistent store coordinator to add this store, I get the following, more detailed, error:CoreData: error: -addPersistentStoreWithType:SQLite configuration:(null) URL:file:///Users/bruno/Library/Developer/CoreSimulator/Devices/39731F7D-6743-4BF4-B4A8-DA626A69475B/data/Containers/Data/Application/AFB0359F-635C-498C-8954-3646E99B63B5/tmp/Archive-incompatible-model-7A8ADDF8-50D1-4808-94FA-DEA2F97F4480.sqlite options:{ NSInferMappingModelAutomaticallyOption = 1; NSMigratePersistentStoresAutomaticallyOption = 1;} ... returned error Error Domain=NSCocoaErrorDomain Code=134020 "(null)" UserInfo={NSUnderlyingException=Can't find table for entity Document in database at URL file:///Users/bruno/Library/Developer/CoreSimulator/Devices/39731F7D-6743-4BF4-B4A8-DA626A69475B/data/Containers/Data/Application/AFB0359F-635C-498C-8954-3646E99B63B5/tmp/Archive-incompatible-model-7A8ADDF8-50D1-4808-94FA-DEA2F97F4480.sqlite} with userInfo dictionary { NSUnderlyingException = "Can't find table for entity Document in database at URL file:///Users/bruno/Library/Developer/CoreSimulator/Devices/39731F7D-6743-4BF4-B4A8-DA626A69475B/data/Containers/Data/Application/AFB0359F-635C-498C-8954-3646E99B63B5/tmp/Archive-incompatible-model-7A8ADDF8-50D1-4808-94FA-DEA2F97F4480.sqlite";}CoreData: annotation: NSPersistentStoreCoordinator's current model hashes are { Document = <451d1fd1 bf1fce92 1ce85eee 82623853 f9d216ed 829f12c5 8867da4d 8332d897>; DocumentPage = <a572584a 2563ffe7 39f1accc 871e241a 6701a09a d2ca5691 450ca76b ccfd3c05>; Export = <88e6d866 8e1ce757 bf28a339 82fcc279 1c3d9d94 6be39254 39e9e332 f3a93bcc>; Tag = <0a096752 6f14a455 d05517d8 bbc2f36e bb0126a0 c05723b4 552efa6e eb954230>;}It seems as if the store wasn't created properly initially.My question: why did this happen and how can I avoid this in the future?For the users facing this problem: how can I detect this issue and work around it properly in the most generic way. I don't really like the idea of deleting and recreating the store if I cannot find any compatible model because it seems like I could delete the store when it's not desirable, and it looks like an ad hoc solution to me which I'd like to avoid.Happy to open a DTS if this isn't enough.
Post not yet marked as solved
Hello,I have the following error "Missing required primary zone" when trying to download a photo from iCloud.All the permissions are correctly set, and generally I get this error on the first try, but if I try another time, it succeeds without error.Could you help me with that? What is the root cause of this error message and what is the "primary zone" Code: PHImageRequestOptions *options = [PHImageRequestOptions new];
options.version = PHImageRequestOptionsVersionCurrent;
options.synchronous = YES;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.resizeMode = PHImageRequestOptionsResizeModeNone;
options.networkAccessAllowed = YES;
options.progressHandler = ^(double progress, NSError *__nullable error, BOOL *stop, NSDictionary *__nullable info) {
assetProgressBlock(progress);
if (error) {
DDLogError(@"Error while downloading asset from iCloud: %@", error);
*stop = YES;
}
};
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
if (!imageData) {
DDLogError(@"Error while downloading image: %@", info[PHImageErrorKey]);
return;
}
UIImage *image = [[UIImage alloc] initWithData:imageData];
[self processImage:image];
}];Error log:[Generic] Failed to load image data for asset <PHAsset: 0x109aacfd0> 93A9C44B-8B63-4B22-AAD0-7DC042843C4D/L0/001 mediaType=1/8, sourceType=1, (3024x4032), creationDate=2018-03-03 11:46:56 +0000, location=1, hidden=0, favorite=0 with format 9999
Error while downloading asset from iCloud: Error Domain=CloudPhotoLibraryErrorDomain Code=80 "Missing required primary zone" UserInfo={NSLocalizedDescription=Missing required primary zone}
Post not yet marked as solved
Hello,We use auto-renewing subscriptions. We are trying to properly refresh the receipts from our server to make sure the user's subscription is always taken in account even when they haven't opened the app in a while.We cache the latest receipt on our server and we use its fields to determine if we should refresh the receipt.We are running into some combination of fields that don't make sense to us:1.expiration date is in the past (9 days ago)expiration_intent is not presentautorenew_status is 0is_billing_retry_period is 0How can this be possible? If the autorenew_status is 0, this means that the user has switched it off. Why is expiration_intent not present then?2.expiration date is in the past (62 days ago)expiration_intent is 2 autorenew_status is 0is_billing_retry_period is 0How can this be possible? Expiration_intent means that there is a payment problem. But is_billing_retry_period is 0 which means that Apple isn't attempting to renew the purchase.Basically, in both cases we don't understand what scenario could lead to this combination of flags?More generally, what can we use out of the receipt to determine if we should or not attempt to refresh the receipt?Thanks!