report which method caused my NSException? - objective-c

I am using Flurry Analytics which reports my app crashes, works great except I don't know which method caused the crash.
I am catching the uncaught exceptions like this:
{
[FlurryAnalytics logError:#"Uncaught" message:[NSString stringWithFormat:#"Crash! %#", [[UIDevice currentDevice] uniqueIdentifier]] exception:exception];
}
If I could only see which method this would be absolutely perfect. Thoughts?

Use
NSlog(#"function that crashed %s",__FUNCTION__);
This is an extension to the compiler and works fine.
UPDATE
to get the complete call stack from the current thread use:
[NSThread callStackSymbols]
which gives you the call stack as NSString.

Related

Crash when trying to present UIActivityViewController

I see a crash in Crashlytics than happens to my users sometimes. The crash happens when presenting UIActivityViewController in the last line of the following code:
NSData* snapShot = ... ;
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:activityTextsProvider, snapShot ,nil] applicationActivities:[NSArray arrayWithObjects:customActivityA, customActivityB, customActivityC, nullptr]];
activityViewController.excludedActivityTypes = [NSArray arrayWithObjects:UIActivityTypePrint, UIActivityTypeAssignToContact, UIActivityTypeMail, UIActivityTypeCopyToPasteboard, nil];
activityViewController.popoverPresentationController.sourceView = self.myButton;
activityViewController.popoverPresentationController.sourceRect = self.myButton.bounds;
activityViewController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError)
{
...
};
[self presentViewController:activityViewController animated:YES completion:nil];
I perform this in the main thread and unable to reproduce this crash locally. What could be the reason of this crash?
Edit: I changed nullptr to nil and the issue still happened. I managed to reproduce the issue: the crash happens only if before opening the activity controller i showed a UIMenuController. When creating UIActivityViewController it is not nil, but when presenting the controller i see the crash in the presentViewController line and the activity controller there is shown as nil
József addressed the use of nullptr in comments, and Fogh is spot-on that the actual crash log is important (please edit your question and post the full crash log), but I'd like to point out something else.
You're assuming your call to initialize activityViewController is succeeding. You should code defensively (by assuming everything that can fail probably will fail and testing for this at runtime). Wrap the rest of the configuration and presentation inside an if (activityViewController != nil) {} condition (you should probably have an else with proper error handling/reporting too) so you're properly detecting an all-out initialization failure for multiple reasons (like a misplaced nib, missing resource, etc.).
In your case, I think it's likely the initialization is failing because your class is doing something with a faulty array, as József's nullptr catch suggests. Perhaps you're using one or more pre-C++11 c libraries / compiling with a non-C11/gnu11 "C Language Dialect" build setting and nullptr is not equivalent to nil, leading to strange results in a supposed-to-be-nil-terminated array?
Note: If that turns out to be the case, I'll happily take an upvote but would rather József post his comment as an answer so you can give him proper credit. (Feel free to edit this request out of my answer if/when that happens.)

iOS 8 CoreData Issue 'NSInternalInconsistencyException', reason: 'recordChangeSnapshot:forObjectID:: global ID may not be temporary when recording'

I am having real difficulties resolving this issue when migrating my App from iOS7 to iOS8, the app works perfect on iOS7.
It crashes when I am trying to save
NSError *error = nil;
if (![managedObjectContext save:&error]) { <---- crashes here
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
I've seen only 2 similar issues on stackoverflow but none of the responses were relevant to my problem.
iOS 8 CoreData Issue: recordChangeSnapshot:forObjectID:: global ID may not be temporary when recording
iOS 8 Core Data Issue: global ID may not be temporary when recording
Its not easy to post all the code. I don't know where to begin debugging !, some help please. Thanks
Is this call to [managedObjectContext save:&error] happening on a background thread? Is it usually called on the main thread?
The pattern recommended for concurrent programming with Core Data is thread confinement: each thread must have its own entirely private managed object context.
When working with your Core Data code, you can use isMainThread to determine if you're on a background thread and switch to the main thread prior to working with Core Data:
- (void)yourCoreDataTask {
if (![[NSThread currentThread] isMainThread]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self yourCoreDataTask];
});
return;
}
// Now on the Main Thread. Work with Core Data safely.
}

Cocoa app behaves diffirently with breakpoint on & off

Important update: I found out that most part of my question was based on a false premise (see my answer below). Notifications actually got to the receiver, they just got there too fast. (Although, it still doesn't explain why the behavior with breakpoint and without it was different.)
I'm developing the app that calculates the hashes of files given to it. The calculation takes place in SHHashComputer. It's an abstract class (well, intended to be abstract, as there are no abstract classes in Objective C) that takes the file path and creates an NSInvocationOperation. It, in turn, calls the method (void)computeAndSendHash, which uses the file path saved in the object to compute hash and sends it as notification. The actual computing takes place in (NSString*)computeHash method that child classes need to override.
Here's SHHashComputer.m:
- (NSString*)computeHash {
return [NSString stringWithFormat:#"unimplemented hash for file %#", self.path];
}
- (void)computeAndSendHash {
NSString *result = [self computeHash];
NSString *notificationName = [NSString stringWithFormat:#"%#%#",
gotResultNotification,
self.hashType];
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName
object:result];
self.operation = nil;
}
And here's SHMD5Computer.m (the child class of SHHashComputer):
- (NSString*)computeHash {
return #"MD5 test"; // it actually doesn't matter what it returns
}
I won't bother you with the receivers of notification. Let's just say that as long as I comment out the computeHash method in SHMD5Computer.m everything works just fine: the notification with text "unimplemented ..." is received & displayed in GUI. But if I don't — then it gets really interesting.
If I don't set up any breakpoints, the notification just never comes. However, if I set up a breakpoint at the declaration of computeHash in SHMD5Computer.h and then step over until the line 'self.operation = nil', and continue execution at that point, the notification gets to destination. If I don't stop there, the debugger suddenly switches to the state as if it isn't debugging anything, and the app freezes.
I don't think that 'WTF' is a good form for a question here, so let me put it this way: am I missing something? Are there errors in my code? What can cause this type of behavior in xcode? How can I fix this?
(If you'll want to get all my code to reproduce it, I'll gladly give it to you.)
More experiments:
If I continute execution exactly after stopping at breakpoint, the application encounters EXC_BAD_ACCESS error in the code that receives the notification, at the last line:
id newResult = [newResultNotification object];
if (newResult == nil)
[NSException raise:#"No object"
format:#"Expected object with notification!"];
else if (![newResult isKindOfClass:[NSString class]])
[NSException raise:#"Not NSString"
format:#"Expected NSString object!"];
else
self.result = (NSString*) newResult;
[self.textField setStringValue:self.result];
When I tried to reproduce the previous experiment, something even stranger happenned. In my debug setup, I have two hash computer objects: one SHMD5HashComputer (which we're talking about), and one SHHashComputer (which, of course, produces the "unimpemented" hash). In all previous experiments, as long as app didn't crash, the notification form SHHashComputer always successfully arrived. But in this case, both notifications didn't arrive, and the app didn't crash. (All the steps are exactly the same as in previous one).
As Josh Caswell pointer out in the comments, I wasn't using the notifications correctly. I should've sent the object itself as notification object, as described in documentation. I fixed that, and I'm getting exactly the same results. (Which means that I fixed it correctly, because sometimes the notifications work correctly, and also that it wasn't the problem).
More updates:
The notification that I'm sending should arrive at SHHashResultViewController. That's how I create it and register for notification:
- (id)initWithHashType:(NSString *)hashType {
self = [self initWithNibName:#"SHHashResultView" bundle:[NSBundle mainBundle]];
if (self) {
[self setHashType:hashType];
}
return self;
}
- (void)setHashType:(NSString *)hashType {
[self.label setStringValue:[NSString stringWithFormat:#"%#:", hashType]];
_hashType = hashType;
NSString *notificationName = [NSString stringWithFormat:#"%#%#",
gotResultNotification,
_hashType];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(gotResult:)
name:notificationName
object:nil];
}
Actually, the question was based on a false premise. I thought that notification never came through because I never saw the information displayed in the GUI; however, my error was in the code of controllers (not published there) which made possible the situation in which the GUI first got results of hash calculation and only after that got information about a new input — which resulted in deleting all the text and activating progress animation.

ios 5 AWS SDK S3PutObjectRequest

I just updated my app to ios5 and the code below (that was working in 4x) is now not working
I thought it was because of the UUID but i changed that and the error stayed the same. The error I am getting is below. Any help is greatly appreciated -- thx
I setup some breakpoints and isolated the error and i think the error is with localPutObjectRequest but after looking at what that line does the error message does not make sense to me.
- (void) updateLocation:(CLLocation*)loc
{
[progressView setProgress:5];
[[LocationManager sharedLocationManager] setDelegate:nil];
uploadPath = [NSString stringWithFormat:#"%#/%#-%f.png", [[UIDevice currentDevice] uniqueIdentifier], [[UIDevice currentDevice] uniqueIdentifier], [[NSDate date] timeIntervalSince1970]];
S3PutObjectRequest *localPutObjectRequest = [[[S3PutObjectRequest alloc] initWithKey:uploadPath inBucket:[NSString stringWithFormat:#"spotted-at"]] autorelease];
localPutObjectRequest.data = UIImagePNGRepresentation([UIImage imageWithData:imageData]);
[localPutObjectRequest setDelegate:self];
[[Constants s3] putObject:localPutObjectRequest];
}
2011-10-23 00:45:39.654 spotted.at[4131:707] -[UIButtonContent length]: unrecognized selector sent to instance 0x2c0130
2011-10-23 00:45:39.656 spotted.at[4131:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButtonContent length]: unrecognized selector sent to instance 0x2c0130'
*** First throw call stack:
(0x310868bf 0x3822b1e5 0x31089acb 0x31088945 0x30fe3680 0x330e42ef 0x330e4267 0x331d7e51 0x49041 0x4973d 0x352c05df 0x352bff81 0x352ba62f 0x3105ab31 0x3105a15f 0x31059381 0x30fdc4dd 0x30fdc3a5 0x33c0afed 0x3304e743 0x453b 0x3f74)
Judging from your post, the error lies in
[[UIDevice currentDevice] uniqueIdentifier]
The method UIDevice uniqueIdentifier is deprecated in iOS 5 and should not be called. From your code I cant really see what exactly you are trying to do but this post
UIDevice uniqueIdentifier Deprecated - What To Do Now?
should be helpful in overcoming the deprecated method. You should change the deprecated calls and also use the ones listed in the post above. That should do the trick.

Calling performSelectorOnMainThread => Multithreaded app?

I noticed that the following banal call from my main thread
[self performSelectorOnMainThread:#selector(rollBar:)
withObject:nil
waitUntilDone:false];
was causing [NSThread isMultiThreaded] to report that my app
had become multithreaded. I thought that was only supposed
to happen when you detach a thread, something that queueing
a message within one thread shouldn't need to do.
Any insights?
This question not the same as this one.
Stop the press
My fault, rollBar: called [m_progress_bar incrementBy: 0.5];.
The the pretty, lickable, animating NSProgressIndicator is responsible
for making my app become multithreaded. Which is surprising.
I didn't know that.
Surprisingly, [m_progress_bar usesThreadedAnimation] always
returns NO, even though the bar animates when my app is hung.
Are you sure about this? I put the following code in my appDelegate's init method:
NSLog(#"Multi-threaded before? %#", [NSThread isMultiThreaded] ? #"Yes" : #"No");
[self performSelectorOnMainThread: #selector(setDelegate:) withObject: self waitUntilDone: NO];
NSLog(#"Multi-threaded after? %#", [NSThread isMultiThreaded] ? #"Yes" : #"No");
and got this result in the console:
2008-10-21 07:26:28.296 MyApplication[82963:20b] Multi-threaded before? No
2008-10-21 07:26:28.297 MyApplication[82963:20b] Multi-threaded after? No
I also added the second NSLog(...) statement to my applicationWillTerminate: method and it also told me it was not multithreaded.