views:

43

answers:

4

I am fairly new to Objective-C. Currently porting my own library from C#/Java to objective C.

I now run into a very strange problem for me.

I have a NSArray with several Note objects. I want to transpose on of these notes:

 //Note.h
 - (Note *) transpose: (int) semitones; 

 //Main
 NSArray *notes = [get it from somewhere];
 Note *transposedNote = [[notes objectAtIndex:0]transpose:1]; //Doesn't compile
 Note *transposedNote = [(Note*)[notes objectAtIndex:0]transpose:1]//Does compile

Is this happening because there is already a transpose method available in the general libraries?

I thought due to the dynamic nature of objective-C at runtime it would be checked which class objectAtIndex returns and then sends the message to it?

+1  A: 

How about

Note *transposedNote = [notes objectAtIndex:0]; // first line
[transposedNote transpose:1]; // second line

? Notice in the reference that objectAtIndex: returns an id, you will see it is pretty obvious:

  • In the code above, because id can fit into any object, the first line doesn't need to cast it into Note. In the second line I'm just calling a method on a Note so the compiler is happy.
  • In your code you are calling methods on the returned id object, so the compiler doesn't understand what you are trying to do. Just assign it to a Note reference and it will be fine.
phunehehe
Now I get why I normally don't get any errors. I don't normally chain a lot of methods but use this way of coding.
Peterdk
+1  A: 

It is my understanding that there is no runtime type checking for the assignment operator in Objective C. Since an array can contain a mixture of types, there is no way for the system to know what objectAtIndex returns.

ennuikiller
A: 

It does compile unless you have -Werror set to treat warnings as errors.

It might produce a warning if the compiler doesn't already know about the selector or if the selector is declared in more than one class. In the former case, it should be necessary only to import the interface containing the selector. In the latter case, you'll need to do the cast to suppress the error.

JeremyP
A: 

Yes, the error is because there's already a transpose: method in AppKit. And you're also right that it normally doesn't cause an error when you have two unrelated classes implementing methods with the same name. The reason you get an error is because the two methods either return incompatible types or take incompatible types as arguments. In your particular case, you're seeing both problems:

  • -[NSResponder transpose:] takes an id and returns void
  • -[Note transpose:] takes an int and returns an id

These are totally incompatible types, and the compiler does need to know the types involved even if it doesn't know what exact method is going to be called.

Chuck