Why does this Objective C call appear to hang? - objective-c

A friend of mine discovered some strange behaviour with NSDictionary, and I'm curious as to why it happens. Consider the following code:
NSDictionary *dict = [[NSDictionary alloc] init];
// Oops, we can't mutate an NSDictionary
[dict setObject:[[NSNull alloc] init] forKey:#"test"];
NSLog(#"Set");
The code produces a warning upon compilation that "'NSDictionary' may not respond to 'setObject:forKey:'". That's all well and good, and if you run it anyway, you'll get this output in the console:
-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Again, exactly what you'd expect to happen. However, at this point the app does not crash or terminate due to an uncaught exception. The setObject:forKey: method simply never returns, and the app appears to hang; the following NSLog is never executed. If you try to step over or into the method using GDB, debugging just seems to end, but without any explicit error message. The app continues to run, but the debugger provides no clue as to where in the code the execution is "stuck."
What's going on here? What is the app actually doing in this case, and why doesn't it crash with an NSInternalInconsistencyException or something of the like?
Edit: For those who have asked, I'm running XCode 4.1 on OS X Lion (10.7.2), building with "Apple LLVM compiler 2.1." I'm using all of the default settings you get with a new Cocoa project in XCode 4. I experience the same non-crashing behaviour regardless of whether I debug the program or just "Run" it. Changing from Debug building to Release building makes no difference. I can even locate the .app file manually in Finder and double click on it to execute it outside of XCode, and it still does not crash.

Exceptions do not crash AppKit programs. NSApplication installs a default exception handler that catches exceptions that your code doesn't. Then you just go back into the runloop as normal.
Lots of apps exhibit this behaviour. It's a common cause of inexplicable blank views/windows. If an exception happens before a view manages to finish drawing, the view will be blank, but the app won't crash. Exceptions only cause a crash if you deliberately change the default exception handler to crash.

Related

Cannot inspect Self in method while debugging

I have a method on one of my ViewController's that is called by one of its view's and delivered some value. It then sends out a message to a manager object with some information about the VC's state.
- (void)elementXChangedWithValue:(float)value {
ParameterManager * pMan = [ParameterManager sharedInstance];
[pMan updateParameter:self.elementX.parameter value:value];
}
In debugging, it was important for me to inspect what the .SomeElement.parameter state was so I could know what was getting lost in translation by the time I get to my ParameterManager.
Unfortunately, although Self is definitely non-nil and accessible the debugger shows scant information about the class making quick and practical glancing of the value difficult. (i will sometimes invoke "po" command in the debugger command line, however).
Not sure if it helps but this project is running heavy with the Objective-C/Swift interoperability although the ViewController is a fully Objective-C class.
Here is an image of what I am getting in the debugger. The drop-down arrow shows nothing but empty.
The debugger isn't perfect and sometimes you just cant see what is in certain areas, such as self. What does always work is NSLog's placed in code though, so if all else fails, add one of those in at the right place to print out the object you wish to know about.
The debugger may show more info after you make it execute these commands:
expr #import UIKit;
expr #import Foundation;
This loads the whole UIKit and Foundation symbols in the debugger at runtime, you only need to execute it once per debug session.
You can automate this with a user-defined breakpoint that'll be triggered every time your application starts in the debugger.
Source : http://furbo.org/2015/05/11/an-import-ant-change-in-xcode/

Why am I getting NSFastEnumerationMutationHandler in code that doesn't modify source array/set?

In my crash logs for my latest app version, I got an NSFastEnumerationMutationHandler followed by a crash referencing HKAnchoredObjectQuery initWithType for my code, but I am not intentionally mutating the NSMutableSet sources over which I am fast enumerating.
Here's my code:
for(HKSource* source in sources){
NSPredicate *predicate = [HKQuery predicateForObjectsFromSources:[NSSet setWithObject:source]];
HKAnchoredObjectQuery *newQuery = [[HKAnchoredObjectQuery alloc] initWithType:quantityType predicate:predicate anchor:anchor limit:HKObjectQueryNoLimit completionHandler:^(HKAnchoredObjectQuery *query, NSArray *results, NSUInteger newAnchor, NSError *error) {
completion(results);
}];
[healthStore executeQuery:newQuery];
}
Any suggestions as to why I am triggering NSFastEnumerationMutationHandler? I am not explicitly touching sources nor have I made a copy of it...is there a way HealthKit could be modifying the source? Even if it were, I would think that modifying source shouldn't trigger this as I am not directly touching sources. Any trouble-shooting advice or error-spotting would be much appreciated.
Here's the exact text from the crash log:
Latest Exception Backtrace:
1. libobjc.A.dylib objc_exception_throw
2. CoreFoundation _NSFastEumerationMutationHandler
3. App name 0x1000d8000
4. App name 0x1000d8000
5. App name 0x1000d8000
6. HealthKit _79-[HKAnchoredObjectQuery initWithType:predicate:anchor:limit:completionHandler:]_block_invoke <---this must be referring to my code above, as it's the only call to initWithType inside a fast enumeration
7. HealthKit _81-[HKAnchoredObjectQuery deliverSampleObjects:deletedObjects:withAnchor:forQuery:]_block_invoke_2 <-- this is an internal HealthKit call. deliverSampleObjects is not a publicly listed method of the interface.
I have not had a crash in the sim or on my phone, so this is the only info I have to go on.
Some code that gets called by the block named completion() in your code snippet is iterating over another collection and is doing so while that array is being modified. Keep in mind that the completionHandler of HKAnchoredObjectQuery runs on a background thread, so your code may be performing unsafe concurrent operations on objects when completionHandler gets called.
It looks like this happens in a block somewhere in a method named
[HKAnchoredObjectQuery initWithType:predicate:anchor:limit:completionHandler:]
So my guess is that the block in question is the completion handler, and the completion handler gets called asynchronously - while someone else is iterating through the same array and maybe modifying it.
Unfortunately this error doesn't show who is causing the trouble, only who is finding the trouble. I'd set a breakpoint on your own callback, check if it is called from a fast enumeration, and try to figure out who else might be modifying the data. Good luck.

nsmanageobjectcontext.save stopped working in iOS7

The project I inherited was built and launched in April 2013, and it worked perfectly for ios 5.1, ios 6.0 and ios 6.1.
However i just installed the app to an iphone that has ios7.0 and it didn't work. I looked at the code and I see that the app downloads some JSON data from the web, and then when it tries to run the following 3 lines of code, "nothing happens" after the 2nd line.
NSError error = nil;
BOOL isSuccessful =[self.tempMoc save:&error]; // where tempMoc is a NSManagedObjectContext
NSLog(#"errrrrrr ----- %# --- errrrrrr", error);
When I say nothing happens, I mean that the code execution stops on the 2nd line, and no code after that line gets fired. I tried putting a breakpoint on the second line, then stepping into the function, but nothing happens...xcode doesn't show me anything new afterwards. The app in my simulator also hangs.
I tried changing the deployment target of my project from ios6 to ios7. Again, this yielded no effects.
What should I do next?
ADDITIONAL NOTES
I've been reading other stack overflow answers and some people say the a hanging [NSManagedObjectContext save] might be a threading issue. I'm not sure how to confirm if my issue is a threading issue. I know that there's only ONE place that calls the [NSManagedObjectContext save], and that's the one place where things are hanging. I tried putting a
[self.tempMoc.persistentStoreCoordinator lock];
right after instantiating self.tempMoc, but that had no effect.
I figured out the issue.
It was indeed multiple threads manipulating the NSManagedObjectContext that caused hte save function to hang.
My solution was to rewrite the code to get rid of all the extra threads. I was left with only the main thread and this fixed the issue.

NSArray: Why is SIGABRT sent instead of an 'index out of bounds' kind of error?

Ok. So I had this extremely weird SIGABRT error on a complex Objective-C iOS program that I'm working on, and after one day of tracking I found the culprit.
Let's say we have the following code:
NSArray *a = [NSArray arrayWithObjects:#"a", #"b", #"c", nil];
NSLog(#"tada: %#", [a objectAtIndex:-1]);
Why the hell will this terminate the program with Program received signal: SIGABRT and the debugger not even pointing to my code (but rather in some assembly part) instead of a nicer 'index out of bounds' and 'hey, this line of code here be wrong' error?
I thought I messed up the project config, so I reproduced this on a brand new project: same result.
Is there a way to configure XCode to be more nice and indicate this kind of errors in a more human understandable way ?
As the documentation says:
If index is beyond the end of the array (that is, if index is greater
than or equal to the value returned by count), an NSRangeException is
raised
And the default action, when no exception handler is defined, is to... well... you can see what the default behaviour is.
You can use #try/#catch to trap the exception, but that's not really Objective-C-ish. You know how many elements are in the array; there's no real need for you to be accessing elements that don't exist.
Exceptions like this normally have a stack trace, so you can go back to the line of code causing the error. (It might be worth switching between LLDB and GDB if it's not working correctly. LLDB is faster and smaller but not completely reliable.(
You should see something along the lines of "index of out range" if you look in the console log in Xcode. SIGABRT is the result of an assertion being fired. Sometimes you have to hit "Continue" after the crash in order to get the message to print.
The debugger tells you where the crash actually happened. It doesn't know what the original cause was. If the debugger leaves you looking at the assembler, just move up the stack until you reach your code.

getting an exception 4.3 on an NSSound object

I load a sound like so:
sound = [[NSSound alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"alert" ofType:#"mp3"] byReference:NO];
Also I have "all exceptions" break point turned on in xCode. The above line throws an exception twice in a row before the code continues and my sound plays. all i see is that the code stops with Thread1: "breakpoint 4.3"
Could someone explain to me what's going on here and what 4.3 means? is there any reference for these numbers?
I've tried to use just:
sound = [NSSound soundNamed:#"alert"];
with exactly the same result...
thank you.
You are the first who noticed this problem with the System Sound…. I have the same issue in Xcode with the System Sound of the iPhone (iOS). If I turn on the "all exceptions" break point I get the same message you have. I went crazy today with this…. but probably is an Apple's issue and anyway is not dangerous maybe…..
Is there any way to disable this exception from "all exceptions" in Xcode?
… well if you enable exceptions only for "Objective-C" in the options, you do not get this message anymore. It mean that it is a C++ exception (more apple / framework related).