iOS 8 NSInternalInconsistencyException
The bug was in the following callback:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
The crash occurs when you call the completionHandler
twice. This happens after iOS8.
NSInternalInconsistencyException: Couldn't update the Keychain Item
The solution was to setup logging of the keychain result, so I created a new method that - (void) createLogEntry:(OSStatus) result;
that transcribes the result code of the SecItemAdd
function into a readable message.
The full list of the Security Framework Result Codes it returns is here:
https://developer.apple.com/documentation/security/1542001-security_framework_result_codes?language=objc
- (void) writeToKeychain {
NSDictionary *attributes = NULL;
NSMutableDictionary *updateItem = NULL;
OSStatus result;
if (SecItemCopyMatching((__bridge CFDictionaryRef)genericPasswordQuery, (void *)&attributes) == noErr) {
// First we need the attributes from the Keychain.
updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes];
// Second we need to add the appropriate search key/values.
[updateItem setObject:[genericPasswordQuery objectForKey:(__bridge id)kSecClass] forKey:(__bridge id)kSecClass];
// Lastly, we need to set up the updated attribute list being careful to remove the class.
NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData];
[tempCheck removeObjectForKey:(__bridge id)kSecClass];
#if TARGET_IPHONE_SIMULATOR
// Remove the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
//
// The access group attribute will be included in items returned by SecItemCopyMatching,
// which is why we need to remove it before updating the item.
[tempCheck removeObjectForKey:(__bridge id)kSecAttrAccessGroup];
#endif
// An implicit assumption is that you can only update a single item at a time.
result = SecItemUpdate((__bridge CFDictionaryRef)updateItem, (__bridge CFDictionaryRef)tempCheck);
[self createLogEntry:result];
NSAssert(result == noErr, @"Couldn't update the Keychain Item.");
} else {
// No previous item found; add the new one.
result = SecItemAdd((__bridge CFDictionaryRef)[self dictionaryToSecItemFormat: keychainItemData], NULL);
[self createLogEntry:result];
NSAssert(result == noErr, @"Couldn't add the Keychain Item.");
}
}
- (void) createLogEntry:(OSStatus) result {
if (@available(iOS 11.3, *)) {
NSString *message = CFBridgingRelease(SecCopyErrorMessageString(result, nil));
DDLogDebug(@"writeToKeychain result={%d} message={%@}",(int)result, message);
} else {
// Fallback on earlier versions
}
}
With the logging set up I found out that the problem was that I was reinstantiating the KeychainItemWrapper
each time I needed the password to be stored/retrieved by calling:
[[KeychainItemWrapper alloc] initWithIdentifier:@"password" accessGroup:@"A123456789my.access.group"];
This caused inconsistencies between the wrapper and the keychain because it was trying to save an item that already existed. Specifically the error code errSecDuplicateItem = -25299
"The item already exists" was returned.
Core Data crash NSInternalInconsistencyException 'statement is still active'
I ended up changing around how I created the core data stack and this went away. Moving to a persistent store context, a child UI context, and a grandchild background context and persisting up the chain appropriately made this all better. I'm still not 100% sure why the original setup did not work with 8.
iOS - NSInternalInconsistencyException happens on iOS 9 and 10 but working fine on iOS 11
What's happening is that setting currentIndexPath = []
is not assigning any value to its item
or section
; it's creating an "empty" IndexPath (IndexPath objects are basically arbitrary-length tuples or arrays of values and can be created/manipulated as such). Any code attempting to use it in that way (such as passing it to a cellForItem
call) will have potentially undefined behavior. Looks like something is effectively interpreting the missing section
value as -1, and then something else is interpreting that -1 as an unsigned 64-bit integer.
Instead, if you want to use the same general logic that you have now, I'd suggest declaring indexPath
as an optional:
var currentIndexPath: IndexPath?
Then, use if-let syntax in your usages of currentIndexPath:
extension MainTileViewController: MainForecastsDelegate {
func mainForecasts(_ forecastVC: MainForecastsViewController!, didChangeWith object: Any!) {
if let currentIndexPath = currentIndexPath,
let cell = outletWeatherForecastCollectionView.cellForItem(at: currentIndexPath) as? MainTileCollectionViewCell {
// Some stuff...
}
}
This follows Swift idioms and makes clear the concept that you start with an "unknown" index path.
But - as @picciano's answer suggests, you may want to rethink your overall design to better fit the larger design patterns of iOS apps.
Related Topics
How to Represent Core Data Optional Scalars (Bool/Int/Double/Float) in Swift
How to Set the Tab Order in iOS
How to Programmatically Dismiss Uialertcontroller Without Any Buttons
How to Create a Bold Uifont from a Regular Uifont
How to Have a Fixed Uitableview Header While Using Sections
Programmatically Creating Uilabel
How to Change the Development Language in Xcode Before Internationalizing My App
How to Distribute Swift Library Without Exposing the Source Code
Uialertcontroller Handle Dismiss Upon Click Outside (Ipad)
Ios6 Simulator Mkmapkit "Couldn't Find Default.Styleproto in Framework"
Connecting to a Bluetooth Device from iOS, No Mfi
iOS 8 Nsinternalinconsistencyexception
Importing Swift Framework into a Objective-C Project
How to Migrate an Old Xcode Project to Use Swiftui
Firebase Create User with Email, Password, Display Name and Photo Url
Tab Bar Background Is Missing on iOS 7.1 After Presenting and Dismissing a View Controller