Seeing A LOT of crashes for this code which has been around for quite a while (on iOS 15). After a viewController that user has been using is dismissed we check some values to determine if we should prompt for a rating and write some values into NSUserDefaults and which is when the crash happens.
This code gets called when the user clicks a Done Button to dismiss the viewController:
-(void)dismissChart
{
[self.navigationController dismissViewControllerAnimated:YES completion:^{
if([IphemerisUtil okToRequestRatingUsingCount:OK_TO_REQUEST_REVIEW_COUNT])
[IphemerisUtil requestAppRating];
}];
}
This is what is called and where the crash occurs:
+(BOOL)okToRequestRatingUsingCount:(int)count
{
int curVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] intValue];
NSNumber *lastVerRated = [userSettings objectForKey:RateLastVersionRated];
int lastVersionRated = (lastVerRated != nil) ? [lastVerRated intValue] : 0;
NSNumber *ratePromptCnt = [userSettings objectForKey:RatePromptCounter];
int rateCounter = (ratePromptCnt != nil) ? [ratePromptCnt intValue] : 1;
NSDate *dateLastCounterIncrement = [userSettings objectForKey:RatePromptCounterLastDateIncrement];
if(!dateLastCounterIncrement) {
dateLastCounterIncrement = [NSDate date];
[userSettings setObject:dateLastCounterIncrement forKey:RatePromptCounterLastDateIncrement];
}
if(curVersion > lastVersionRated) {
if(rateCounter > count)
return YES;
else {
// Increment the counter only once a day
if([[NSDate date] timeIntervalSinceDate:dateLastCounterIncrement] > (3600 * 24)) {
rateCounter++;
[userSettings setObject:[NSNumber numberWithInt:rateCounter] forKey:RatePromptCounter];
}
}
}
return NO;
}
One of the two userSettings:setObject is crashing. As indicated by this symbolicated crash log for the above code.
Isn't it likely that you're trying to access (set) a value in userSettings after it has been dealloc'd by the closure of the view?
What you've done is said, "Please dismiss this view, and when you've finished dismissing it, set something in a variable you've just got rid of."
I don't know what this code does: [IphemerisUtil requestAppRating] but if it's going to pop up a rating request view, where are you going to display it? You've just dismissed this view so there's nowhere to put an alert box.
I'd suggest you try one of two routes:
Option 1. Check whether you should ask for a rating before the view is dismissed, and do the dismissal from the [IphemerisUtil requestAppRating] method, i.e.:
// In viewDidLoad():
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeView) name:@"CloseViewAfterRating" object:nil];
- (void)dismissChart
{
if([IphemerisUtil okToRequestRatingUsingCount:OK_TO_REQUEST_REVIEW_COUNT]) {
[IphemerisUtil requestAppRating];
} else {
[self closeView];
}
}
- (void)closeView
{
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
// In IphemerisUtil:
- (void)requestAppRating
{
// Get rating
// ...
// When complete, post a notification to the previous view to close
[[NSNotificationCenter defaultCenter] postNotificationName:@"CloseViewAfterRating" object:nil];
}
Or, if the ratings method blocks the code until it's complete:
- (void)dismissChart
{
if([IphemerisUtil okToRequestRatingUsingCount:OK_TO_REQUEST_REVIEW_COUNT]) {
[IphemerisUtil requestAppRating];
}
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
Option 2. Alternatively, if you are always going to check for a rating after various views are closed, you could do it in the viewDidAppear method of your main view.