views:

35

answers:

2

When executing the following code I receive a run time error when the code executes the second line of code. The error (which shows up in the debugger) says: [NSButton initWithContentsOfURL:]: unrecognized selector sent to instance 0x100418e10. I don't understand this message, because it looks to me (based on my source code) like the initWithContentsOfURL message is being sent to the myImage instance (of the CIImage class) ... not NSButton. Any idea what is going on?

If it matters ... this code is in the Application Controller class module of an Xcode project (a Cocoa application) -- within a method that is called when I click on a button on the application window. There is only the one button on the window ...

// Step1: Load the JPG file into CIImage
NSURL *myURL = [NSURL fileURLWithPath:@"/Users/Adam/Documents/Images/image7.jpg"];
CIImage *myImage = [myImage initWithContentsOfURL: myURL];
if (myImage = Nil) {
    NSLog(@"Creating myImage failed");
    return;
}
else {
    NSLog(@"Created myImage successfully");
}
A: 

This line

if (myImage = Nil) {...

Does assignment instead of comparison

Also, don't put a space before parameter for your method in question. And it should be something like this:

CIImage *myImage = [[CIImage alloc] initWithContentsOfURL:myURL];
Eimantas
When you say "don't put a space before parameter for your method in question" are you referring to the space between initWithContentsOfURL: and myURL? That's just a matter of formatting taste. Other than that, your answer is correct.
JWWalker
The addition of the alloc fixed the issue for me (though I still think it is strange that the error message that was presented mentioned NSButton). And my single equal sign was certainly a Doh! moment for me. I'm sure it would have bombed on that statement, too ... if it had made it that far. So thanks for pointing out both things!
Adam
Also (and this is pedantic), `Nil` is for classes, `nil` is for other objects (you should be using `nil` there).
Wevah
A: 
CIImage *myImage = [myImage initWithContentsOfURL: myURL];

You have not initialized the myImage variable, but you are sending its value an initWithContentsOfURL: message. When, by chance, it contains the pointer to an existing object (such as existing NSButton object), the exception in your question occurs.

If you are really unlucky, the object you end up sending the message to will respond to initWithContentsOfURL:, in which case this will re-initialize this object with a different URL. Depending on the URL, it may make the object have the wrong contents, or release itself. Either way, it will probably cause several leaks, and will cause a crash, either by sending later CIImage messages to an object that is still not a CIImage (simply a re-initialized other object), or by sending messages to an object that released itself and so is now dead.

The solution is, as Eimantas stated, to allocate a new CIImage object (by sending the CIImage class an alloc message), then send the initWithContentsOfURL: message to that object, then assign that result to the variable.

if (myImage = Nil) {

As Eimantas noted, this is an assignment, not a comparison. Yes, it is perfectly valid to assign to a variable within a condition in C (and so in Objective-C). The compiler offers a warning for this; you should turn it and a bunch of others on. The solution is to use the equality operator, ==.

Furthermore, as Wevah noted, Nil is the wrong constant to use here, since you are comparing an object's pointer to it, not a class's pointer. The correct constant is nil.

Peter Hosey