I'm trying to log crashes in my iPhone app by catching all unhandled exceptions and writing the details to the NSUserDefaults. I set it up by adding this to
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
}
and defined the function to handle it like this:
void uncaughtExceptionHandler(NSException *exception) {
NSMutableString *errorString = [NSMutableString new];
[errorString appendFormat:#"Exception Name : %#\n", exception.name];
[errorString appendFormat:#"Exception Reason : %#\n", exception.reason];
[errorString appendString:#"User Info : \n"];
for (NSString *key in [[exception userInfo] allKeys]) {
[errorString appendFormat:#"Key : %# Value : %#\n", key, [[exception userInfo] valueForKey: key]];
}
[errorString appendFormat:#"Call Stack : %#\n", [exception callStackSymbols]];
[[NSUserDefaults standardUserDefaults] setObject:errorString forKey:#"ErrorLog"];
NSLog(#"Exception : %#", errorString);
}
Everything works fine as far as the function being called when there's a crash and the NSLogs print out all the exception details, but nothing ever gets added to the NSUserDefaults, and I have no idea why.
Does anyone have any idea why this wouldn't set an object into the NSUserDefaults?
Thank you for any help...
Try adding this line after you set the object
[[NSUserDefaults standardUserDefaults] setObject:errorString forKey:#"ErrorLog"];
////add this line//////
[[NSUserDefaults standardUserDefaults] synchronize];
///////////////////////
You should call '[[NSUserDefaults standardUserDefaults] synchronize];'
By the way, how come do you want to use 'NSUserDefaults'?
While developing, you can see log in console.
However, if your App has been released once, crash log in user's device is unreachable so it's useless.
What about using logging service like Flurry or Google analytics?
Related
I am doing a project in objective-c and I have to store some values in userDefaults. I am already did the same thing in the same project. It was working fine but now I am trying to add some values in userDefaults it showing error while fetch any data from userDefaults. I am adding the datas as,
NSString * totalBitValue = [NSString stringWithFormat:#"%.6f Bit",
totalValue /
[[[NSUserDefaults standardUserDefaults] objectForKey:#"Bit"] floatValue]];
[[NSUserDefaults standardUserDefaults]setObject:totalBitValue forKey:#"totalBTCValue"];
[[NSUserDefaults standardUserDefaults]setFloat:totalUSDValue forKey:#"totalUsedValue"];
[[NSUserDefaults standardUserDefaults] synchronize];
and the error as ,
error: Trying to put the stack in unreadable memory at: 0x7ffeeafe2af0
I got the error in the following line,
if( [[NSUserDefaults standardUserDefaults] objectForKey:#"CoinValue"] != nil) {
[[self ValueLabel] setText: [NSString stringWithFormat:#"%#", [[NSUserDefaults standardUserDefaults] objectForKey:#"CoinValue"] ]];
}
Anyone can help me.Thanks in advance
The reason for your issue is because your code gets recursion.
As I understand, you used NSNotificationCenter to observer key NSUserDefaultsDidChangeNotification. So whenever NSUserDefaults is updated, it will trigger defaultsChanged method. But inside it, you continue to change NSUserDefaults, set new value for totalBTCValue and totalUSDValue (as I guess) which makes defaultsChanged be called again and leads to recursion.
To fix the issue, you shouldn't update NSUserDefaults inside defaultsChanged method
Some users of my app are unexpectedly quitting the app before they complete what they should do. I am suspecting if the app gets frozen. How to check which page user saw at last? I would like to save that data to firebase to analyze.
Simply I want to know where users are quitting the app.
There isn't any default method which you can use in this case. This is what you can do, in your every view controller's viewDidAppear save that screen's name in UserDefaults overwriting the previous value. Now on every app launch, check if the app was crashed last time it was opened, if it was crashed then get the screen name from UserDefaults and save it to firebase.
If you don't know how to detect an app crash, use this link.
https://stackoverflow.com/a/37220742/1811810
Apple offer that NSSetUncaughtExceptionHandler to listen whether the app is crash,
so ,you can when app launch use this listener to save the crash log,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//get crash report
[self installUncaughtExceptionHandler];
}
and the implementation is:
- (void)installUncaughtExceptionHandler {
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
}
void UncaughtExceptionHandler(NSException *exception) {
NSArray *arr = [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSString *currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
NSString *urlStr = [NSString stringWithFormat:#"mailto://developer#googlemail.com?subject=CrashReport&body=YourSuggest!<br><br><br>""errorInfo(%#):<br>%#<br>-----------------------<br>%#<br>---------------------<br>%#",currentVersion,name,reason,[arr componentsJoinedByString:#"<br>"]];
NSURL *url = [NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[[UIApplication sharedApplication]openURL:url];
}
And suggest that you can send email to tell developer,if the customer allow that.
I think this error info can contain the crash page's info,hope this can help you.
I am developing an app in which I have to track crashes. There is a restriction that I can't use any third party source like Twitter's Fabric framework to handle crash logging.
Currently I am only able to get the reason for crash. I am not able to get the exact point of crash.
What I am doing:
In my app delegate's didFinishLaunchingWithOptions method I had made my own exception handler:
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
uncaughtExceptionHandler ----
void uncaughtExceptionHandler(NSException *exception) {
NSLog(#"CRASH: %#", exception);
NSLog(#"callStackSymbols: %#", [exception callStackSymbols]);
NSLog(#"callStackReturnAddresses: %#", [exception callStackReturnAddresses]);
NSLog(#"reason: %#", [exception reason]);
NSLog(#"name: %#", [exception name]);
NSLog(#"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);
// Internal error reporting
}
I crashed my app in viewDidLoad method using this:
NSArray *myary;
myary = [NSArray arrayWithObjects:#"sad", nil];
NSString *str = [myary objectAtIndex:22];
Here is my Stack Trace.
Is their any way to achieve what I want?
I tried following these solutions from SO but they don't give me any lead:
Solution 1
Solution 2
I have 2 applications sharing data via the NSUserDefaults, initWithSuite ID. Using iOS Dev Center.
One in 2 attempts the following code block apparently fails to write my dictionary object to the shared UserDefault area, I use the BOOL response from Synchronise to check the success. eg, (4 NSData objects, one, or more, or all of the items might fail to write to storage).
I use [[NSUUID uuid] UUIDString] as a key [EDIT: Been told in comments that this changes value?, Tried a Static String same result, 25% fail rate]
Any help will be greatly received.
Writer - Application 1
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]
initWithSuiteName:FRGFileShareID];
NSString *uuid = [[NSUUID UUID] UUIDString];
[myDefaults setObject:**customObjectDict** forKey:uuid];
BOOL successSave = [myDefaults synchronize];
if (!successSave) {
DLog(#"Failed To Save To Defaults");
}
Reader - Application 2
NSUserDefaults *myDefaults = [[NSUserDefaults alloc] initWithSuiteName:FRGFileShareID];
if ([myDefaults objectForKey:uuid]) {
[mediaArray addObject:[myDefaults objectForKey:uuid]];
[myDefaults removeObjectForKey:uuid];
}
If i log out [[myDefaults dictionaryRepresentation] allKeys] im lucky if any of my keys are there.
Again with this working 75% of the time, im not sure whats causing the intermittency but its killing the usability of my feature.
You have not pass the value to NSUserDefault, change the code like this,
[myDefaults setObject:uuid forKey:"myDict Object"];
[myDefaults synchronize];
While dismissing the modalView I save the changes in NSUserDefaultsand synchronize them in the method "saveinUserDeaultsObjects".
Now, repeating this process twice crashes the with exc bad access.(i.e presenting and dismissing).
But, if I dismiss viewcontroller after 1 sec delay using perform selector the app works fine.
What can I infer from this ? - I think writing to NSUserdefaults taking some time while the passed object is released.
If it is the case how to handle such situations ?
- (void)dismissViewController {
[Utils saveinUserDeaultsObjects:self.sortVlaue Forkey:#"SortByValue"];
[Utils saveinUserDeaultsObjects:self.state Forkey:#"State"];
[Utils saveinUserDeaultsObjects:self.topic Forkey:#"AOPString"];
[self dismissViewControllerAnimated:YES completion:^{}];
}
Thank You.
Update
+ (void)saveinUserDeaultsObjects:(NSString )valueObject Forkey:(NSString)key {
//NSLog(#"SaveUseref for key: %# object: %#",key, valueObject);
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
[userPreferences setObject:valueObject forKey:key];
[userPreferences synchronize];
}
Update 2
+ (NSString )retriveFromUserDeaultsStringForkey:(NSString)key {
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
NSString *value = nil;
if (userPreferences) value = (NSString *)[userPreferences objectForKey:key];
return value;
}
the crash it ocassionally shows is at reading the "value" object above. Mostly it is EXC bad access and the malloc stack trace is:
12: 0x1c0b85f in -[CFXPreferencesPropertyListSourceSynchronizer createPlistFromDisk]
13: 0x1bdfc56 in -[CFXPreferencesPropertyListSourceSynchronizer synchronizeAlready]