How to debug an incorrect binding - objective-c

I got the error cannot create BOOL from object with CoreData. I read a lot of questions on this, all leading to the same conclusion: an incorrect binding in IB.
Is there a way I could for example list all bindings, or is there a utility app that checks the type of the bindings? Perhaps catch the error, or implement a method that gets called when this happens so I can retrieve the name of the bound object? I'd rather solve it myself than have someone nice analyse my .xib.

I've been pulling my hair out over this. In a XIB with dozens or potentially hundreds of bindings it's almost impossible to find out where this is coming from. But I finally found a way to narrow it down a bit.
I just set a symbolic break point on
-[NSValueBinder _observeValueForKeyPath:ofObject:context]
and configure it as follows
Action: Debugger Command, Enter po $rdi as the command to execute. This will print out self (i.e. the NSValueBinder description) every time the break point is hit. This ($rdi) is for x86_64, for other architectures see this article.
Check Automatically continue after evaluating
Now when I run the program I get a bunch of binding related logs in the console that should look something like this:
$7 = 4301564448 <NSTextValueBinder: 0x10064aa20>{object: <NSTextFieldCell: 0x10061eea0>, bindings: value=selection.myProperty}
The last one is obviously the one that throws the exception. I can usually figure out which view it is from the bindings value directly or from some of the other bindings that are established before the error occurs. Another thing that helps, is examining the superview or controlView of the offending object, e.g. with po [0x10061eea0 controlView] in the example above.

Related

How can I trace a variable which causes an exception with Xcode?

My program crashes after indicating the following. I know something bad occured with the NSArrays. How should I trace the array variable which causes the exception?
Tracing the array isn't going to help you here that much (but see below). You've overreleased something, probably the NSArray itself, and you're not finding out about it until the autorelease pool drains. These can be some of the hardest bugs to track down; hopefully it reproduces consistently.
The typical solutions are:
Make sure you're using ARC. This is precisely the kind of bug that ARC does an excellent job of avoiding. (And usually this kind of crash suggests you're not using it; but it is possible to get them under ARC in some cases.)
Work out which NSArray is having trouble. Audit its usage and make sure that (if you're not using ARC), you are following the memory management rules at each point. Regarding "work out which NSArray," this can be tricky in itself, but some common sense often is the best tool here. You probably have some sense of what object it is. A little trial and error can go a long way.
Avoid direct ivar access; always use accessors except in init and dealloc. This is the best way (besides ARC) to avoid these kinds of memory errors.
Instruments can add traces on retains and releases (use the Zombies instrument). And there is NSZombies, which can help as well. But I have found in the vast majority of cases, the best first step is to search for all the times you use the object, and then check your retains and releases by hand. (I'm not saying any of these approaches is easy; just that a quick by-hand audit is often more effective than the tools.)
And of course make sure to use ARC.
The BEST way to do this, which will help you on MANY occasions, is to set up XCode to automatically break when exceptions are thrown where they are thrown. You can do this as follows:
STEP 1: Go to the breakpoints navigator.
STEP 2: Go to the bottom left and hit '+' and add exception breakpoint.
STEP 3: Find the breakpoint you just added above, right-click, and edit.
STEP 4: Change it to break on all Objective-C exceptions, and the vast majority of crashes will break where the crash occurred.
When the exception occurs, you can act as if you're normally debugging - print values to the console, or hover over them to see what their values are.

cocoa - Subtle difference between -removeObserver:forKeyPath: and -removeObserver:forKeyPath:context:?

Short version:
What use is -removeObserver:forKeyPath:?
Why not always use -removeObserver:forKeyPath:context:?
Long version
While working on a Cocoa program, I discovered that using -removeObserver:forKeyPath: could (but would not always) lead to an error like:
Cannot remove an observer <ObservedClass 0x1001301d0> for the key path "exampleKeyPath" from <__NSCFConstantString 0x100009138> because it is not registered as an observer.
while using -removeObserver:forKeyPath:context: instead would work just fine.
Since it is required that a context be specified when setting up observation (with -observeValueForKeyPath:ofObject:change:context:), I'm puzzled at why the context:-less removal method exists.
Based on my reading of the NSKeyValueObserving Protocol, I supposed that the removal might apply to the specified observer and specified key path in all contexts, but the failure of -removeObserver:forKeyPath: (with no context) to work as a replacement for -removeObserver:forKeyPath:context: (with a context of NULL) seems to shoot down that idea.
So: why might I have that error? What does -removeObserver:forKeyPath: do with contexts? How's it differ from its context:-equipped younger sibling?
Code example
Problematic code:
-(void) invalidate {
[(id)observedObject removeObserver:self
forKeyPath:#"exampleKeyPath"];
}
Non-Problematic code:
-(void) invalidate {
[(id)observedObject removeObserver:self
forKeyPath:#"exampleKeyPath"
context:NULL];
}
Short version: -removeObserver:forKeyPath:context: was only introduced in 10.7, hence both.
Long version: Why might you have the error? Looks like a bug, either in your code or the system (I've never seen the error and use the shorter version a lot). The descriptions of the two methods do not suggest there should be any difference. If nobody else comes up with an explanation, and you can't find anything in your code, then report a bug to Apple.
The documentation has an excellent discussion as to the use of the new method:
Examining the value in context you are able to determine precisely which addObserver:forKeyPath:options:context: invocation was used to create the observation relationship. When the same observer is registered for the same key-path multiple times, but with different context pointers, an application can determine specifically which object to stop observing
It's just a way to be more specific about just which binding you want to remove from the object. For example, I might bind to a keypath twice, but with the memory locations of different static variables, a little like how dispatch_once() works. The context-free subscription method was the only way of binding to an object until 10.7 rolled around and filled in that gap.
As for your KVO troubles, the problem can occur in many different cases. The most common being that you've subscribed on one thread, then very soon after, removed a subscription from a different thread. Occasionally it can occur because the object you tried to observe was just about to deallocate, meaning you would subscribe to some bogus memory location that happened to fill what you needed to, then removing the subscription from this garbage pointer would be impossible. Either way, make sure to monitor the methods you're utilizing bindings in, as they can be a little unstable if used in the wrong way.

Argument values being corrupted through function calls in Objective-C

So I seem to have a sporadic problem, that no amount of Google-fu has thus far been able to solve. At seemingly random points functions will just break, and after some hunting it appears arguments will begin to get corrupted.
For example
Object * testObject = [[Object alloc] init];
NSLog(#"ID: %d", testObject);
[testFunction:testObject];
...
- (void) testFunction:(id)testObject
{
NSLog(#"ID: %d", testObject);
When this happens the Log statements in this case would fail to match up, giving me EXC_BAD_ACCESS warnings or other various issues when I go to use the reference I passed.
Sometimes I can fix the issue by tacking on a 'Dummy value' to the function like so:
- (void) testFunction:(id)testObject:(int)dummy
{
and then calling it like so:
[testFunction:testObject:1111];
My function declarations all match in the .h/.m files, the only thing I could guess is that potentially elsewhere in the project there might be missing corresponding function declarations in .h files. However the functions in question are always done correctly. (I have double, triple checked etc). I know it's not a retain/release issue, while I am relatively new to Objective-C I have that down pat and I have also ran it through Instruments looking for leaks and there appear to be none. Any thoughts as to what might cause this, and why issues pop up after changing seemingly completely unrelated code elsewhere in the project?
Your problem is probably that you are logging your objects in the wrong way.
When you log an Object you can't just format it like you did.
When you log any code you need to format it precisely right you will get bad access errors.
You should really read up on the apple documentation about the right formats.
And you can do this here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html

XCode Error, unable to see a difference

Alright, I'm reading the Aaron Hillegass book for Cocoa Programming, on the drag and drop chapter. I was following along with one of the lessons, and I typically change variable names as I find it keeps me a little more engaged and gives me a better understanding. I started getting this error, though:
2010-10-04 00:38:06.699 TypingTutor[421:a0f] -[BigLetterView dragImage:at:offset:event:pasteboard:source:slideback:]: unrecognized selector sent to instance 0x100424390
Now, I figured it was because I'd messed up some variable name so I went back and copied the variables directly from the book and still got the error. XCode was saying the following function might not get a response. Well, regardless I could not figure it out for the life of me, so I scrapped the function and redid it. What drives me crazy is that it worked the second time, but I did notice a difference in that XCode highlighted the syntax of the function that works, but didn't for the one that doesn't. I can see no physical difference and am stumped as to why one is different than the other. Both were typed in on a Mac keyboard, so I can't see it being some hidden character due to encoding, but yeah, I'm just hoping I'm missing something extremely obvious because it's 1 AM... has anyone ever run into this before?
Methods copied directly from .m file...
This one works
[self dragImage:anImage
at:p
offset:NSMakeSize(0,0)
event:mouseDownEvent
pasteboard:pb
source:self
slideBack:YES];
This one doesn't
[self dragImage:anImage
at:p
offset:NSMakeSize(0,0)
event:mouseDownEvent
pasteboard:pb
source:self
slideback:YES];
Objective-C is case sensitive, so method names with different cases in their letters are considered different methods. The one that works, "slideback" is written slideBack with a capital B, which is probably what you're calling. The one that doesn't has a lowercase 'b' and is written slideback. In Objective-C, those are different methods. The definition is obviously written with the uppercase 'B', which is why that one works and the other doesn't.

Crashes in Core Data's Inferred Mapping Model Creation (Lightweight Migration). Threading Issue?

I'm getting random crashes when creating an inferred mapping model (with Core Data's lightweight migration) within my application. By the way, I have to do it programmatically in my application while it is running.
This is how I create this model (after I have made proper currentModel and newModel objects, of course):
NSMappingModel *mappingModel = [NSMappingModel inferredMappingModelForSourceModel:currentModel destinationModel:newModel error:&error];
The problem is this: This method is crashing randomly. When it works, it works just fine without issues. But when it crashes, it crashes my application (instead of returning nil to signify that the method failed, as it should). By randomly, I mean that sometimes it happens and sometimes not. It is unpredictable.
Now, here is the deal: I'm running this method in another thread. More precisely, it is located inside a block that is passed via GCD to run on the global main queue. I need to do this for my UI to appear crisp to the user, i.e. so that I can display a progress indicator while the work is underway.
The strange thing seems to be that if I remove the GCD stuff and just let it run on the main thread, it seems to be working fine and never crashing. Thus, could it be because I'm running this on a different thread that this is crashing?
I somehow find that weird because I don't believe I'm breaking any Core Data rules regarding multi-threading. In particular, I'm not passing any managed objects around, and whenever I need access to the MOC, I create a new MOC, i.e. I'm not relying on any MOC (or for that matter: anything) that has been created earlier on the main thread. Besides the little MOC stuff that occurs, occurs after the mapping model creation method, i.e. after the point at which the app crashes, so it can't possibly be a cause of the crashes under consideration here.
All I'm doing is taking two MOMs and asking for a mapping model between them. That can't be wrong even under threading, now can it?
Any ideas on what could be going on?
First, what is the crash?
Second, Core Data generally is a single threaded API. There are things you can do in multiple threads but creating a NSMappingModel is most likely not one of them. Why must you create the mapping model dynamically? If the MOMs are a known quantity then the mapping can be a known quantity as well.
update
First, the threading issue. Core Data is meant to be single threaded. However, the NSManagedObjectContext knows how to lock the NSPersistentStoreCoordinator correctly therefore you can have one NSManagedObjectContext per thread because they know how to lock correctly. However this is not the case when you are working with and creating a mapping model.
However, the error you provided is not a Core Data error per se. That error indicates that somewhere in your code you are trying to stick a nil into a set. Without seeing the code that is generating the mapping model though it is difficult to guess as to exactly where.
Have you put a breakpoint at objc_throw_exception and see what line in your code is causing this crash? If it is in something non-obvious then I would suggest there is some point in your building of the mapping model that is giving Core Data an unexpected nil.
One thing you can try is locking the NSPersistentStore and/or the NSManagedObjectContext yourself to see if that resolves the crash. However I suspect when you do that you are going to again deal with performance issues.
I ended up giving up on this problem altogether and just created the damned mapping models myself.