Why do I need to cast before a method of an item of a NSArray can be called? - objective-c

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?

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.

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.

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.

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.

Related

Instance method not found warning, but working

In my implementation model, I need to have some differents files, with some similar methods. Also, I gather objects of differents types in a NSMutableArray, and try to call my similar method like this:
[[ArrayOfViews objectAtIndex:i] myMethodWithInt:'number' andExample:'char'];
But it gives me a warning:
Instance method '...' not found (return type defaults to 'id')
My code works, but should I fix this warning or not?
You should introduce the type:
MONType * obj = [ArrayOfViews objectAtIndex:i];
Then call the method using the typed variable:
[obj myMethodWithInt:<#number#> andExample:<#char#>];
It could be complaining for a number of reasons. Introducing the type will either fix those categories of issues, or at least give you a more useful warning. Specifically, the compiler does not see a declaration of the instance method -myMethodWithInt:andExample:.
You've likely either not imported a header, or declared the method so that it is visible in the translation.
My code works, but should I must fix this warning or not ?
Maybe. Sometimes it will 'work'. This is equivalent to C89's missing function prototypes, which were phased out because of all the issues they caused. So implicit parameters and return types can work if the parameters and return type is id compatible (including NSObject subclasses). But if it is not a match, then you should expect undefined behavior. You can avoid all this and introduce meaningful type checking by using the appropriate imports and declarations in your programs, and by introducing the type as illustrated above. This is useful because the compiler will save you from a ton of silly mistakes as you work and as your codebases evolve.
It's probably just a case of not having the method declared before the call. Try adding the method declaration to the interface section of the class.
Adding a typecast to your objectAtIndex call with get rid of the warning. This isn't a big issue, but it's good practice to typecast returns from an NSArray.
Basically:
YourObjectType *yourObject = (YourObjectType*)[ArrayOfViews objectAtIndex:i];
[yourObject myMethodWithInt:'number' andExample:'char'];
You need to add an #import statement for the header that declares the method or methods you want to call.

objective c class type checking

I use MagicalRecord (which is a category for NSManagedObject) to fetch my models. Then I display them using a generic table view controller which display my data based on the Class name.
The problem is that when I want to fetch these data I use something like this:
Class type = NSClassFromString(modelName);
NSArray *model = [type MR_findAll];
This compile and run perfectly, excepts that xcode displays a nasty error: "No know class method for MR_findALL".
Can I do something like a "Class cast" to NSManagedObject so the error will disappear? I want to keep it dynamic, I don't want to define a condition for all my models.
The problem is not static type checking. Class, like id, disables static type checking.
The problem is something else: in Objective-C, in order to send a message using the [... ...] syntax, the compiler must have first seen the declaration of such a method somewhere. The reason that the compiler needs a declaration is that the compiler must compile a message dispatch to either a objc_msgSend or a objc_msgSend_stret call behind the scenes. Which one depends on the return type of the method. Therefore, it must know the types of the method (from a declaration) in order to compile a call to it.
Note, I said "somewhere", because that "somewhere" can be completely unrelated to where you use it. You could declare a dummy protocol that contains a declaration of the same message, that is never used anywhere, and it will serve the purpose of having a declaration. Or you can declare a category that contains it. Whatever. This might seem rather incredible to you. But if you take #HotLicks's solution with the protocol, and remove the cast, it will still not have the warning, because whether the protocol is used does not matter -- it's the declaration that is relevant here.
Define a protocol that includes MR_findAll. Cast your object to that protocol before making the call.
[(id<FindAllProtocol>)type MR_findAll]
Try to cast your type variable to id, which is a dynamic typing.

What would setting a getter do?

First, some context: while answering questions on SO, I came across a post wherein the author had been trying to set a getter with syntax similar to [self.propertyGetter:newValue];. For some reason, this compiles, and I thought to myself, "this would constitute a call to nil, wouldn't it?". So, my question is, why in the heck does this 'work'? (to be perfectly clear, the poster was complaining that this had no effect, so by 'work', I mean compile).
The code you quoted is [self.propertyGetter:newValue]. Here's how the Objective-C compiler parses this.
The first thing after the left bracket has to be the receiver of the message. In that code, the receiver is the value of self.propertyGetter. The compiler transforms self.propertyGetter into [self propertyGetter]. So we can rewrite the code you quoted as [[self propertyGetter]:newValue].
Now the compiler needs to figure out the selector of the message. You usually see a keyword selector like setStatusBarHidden:animated:, which is a series of keywords followed by colons. But it turns out a keyword can be zero-length. So a colon by itself is a valid keyword selector. So the compiler sees it like this: [[self propertyGetter] :newValue]. (Using a zero-length keyword is almost always very bad style.)
You can declare an instance method using that selector. For example:
- (void):(NSObject *)newValue;
If [self propertyGetter] returns an object of a class that has that method, the code will compile and run.
If the compiler has seen any class with a method named like that, and [self propertyGetter] returns type id, then the code will compile (because id is a wildcard type and the compiler will not complain if you try to send it any known message selector). However, the app will crash at runtime if [self propertyGetter] doesn't actually understand the : message.
This compiles because all objective-C objects are dynamic entities by default. It would compile, but would crash at runtime.
Source.

Objective-C Selector pointer to be passed to a C function

I have a C struct that contains a function pointer. Now, I have used this setup within C with no problems, but now I'm using this C struct in Objective-C and I need to pass a function (or selector) pointer that is defined in the Objective-C class.
1. Here is what I have for the Objective-C selector that needs to be passed as a pointer to the C function:
- (void)myObjCSelector:(int*)myIntArray
{
// Do whatever I need with myIntArray
}
2. And here is where I run into a wall, Within Objective-C I'm trying to pass the selector as a pointer to the C function call: In place of "myObjCSelectorPointer" I need the proper syntax to pass the selector as a function pointer in this C function call:
passObjCSelectorPointerToCContext(cContextReference, myObjCSelectorPointer);
I did investigate this issue, but could mainly find several different ways of doing similar things, but I couldn't find anything specific for calling C functions and passing an Objective-C selector pointer.
In objc a selector is not a function pointer. A selector is a unique integer that is mapped to a string in a method lookup table stored by the objc runtime. In the above case your method name would be myObjCSelector: and to get the unique selector for it you would type #selector(myObjCSelector:). However this would be of no use to you because it doesnt represent a particular implementation of a function.
What youre looking for is IMP. Refer to this SO question.
EDIT 2:
IMP myObjCSelectorPointer = (void (*)(id,SEL,int*))[self methodForSelector:#selector(myObjCSelector:)];
Then you can call the method using
myObjCSelectorPointer(self,#selector(myObjCSelector:),myIntArray);
However, what this means you will need to make sure that you add the pointer to self in the c function call passObjCSelectorPointerToCContext.
So it should look like this
passObjCSelectorPointerToCContext(cContextReference, self, myObjCSelectorPointer);
when called from within the object that contains the method.
It is important to note though that using IMP is almost never the right technique. You should try to stick with pure Obj-C. Obj-C is quite efficient after the first call to a message because it uses temporal caching.
EDIT 1:
It's useful to understand why objc works in this way. The Apple documents explain it in depth. However a short explanation is as follows:
When you send a message to an object such as [myobject somemethod] the compiler won't immediately know which particular implementation of somemethod to call because there might be multiple classes with multiple overriden versions of somemethod. All of those methods have the same selector, irrespective of its arguments and return values and hence the decision about which implementation of somemethod is deffered to when the program is running. [myobject somemethod] gets converted by the compiler into a C function call:
objc_msgSend(myobject, #selector(somemethod))
This is a special function that searches each myobject class layout to see whether that class knows how to respond to a somemethod message. If not it then searches that class's parent and so on until the root. If none of the classes can respond to somemethod then NSObject defines a private method called forward where all unknown messages are sent.
Assuming that a class can respond to the somemethod message then it will also have a particular pointer of type IMP that points to the actual implementation of the method. At that point the method will be called.
There is considerably more to this procedure than I have described but the outline should be enough to help you understand what the goal of a selector is.
One final point is that the reason method names are mapped to unique integers via the #selector directive is so that the runtime doesn't have to waste time doing string comparisons.
Basically, the answer is: Objective-C selectors are different from function pointers. You need two pieces of data to perform a selector. That is an object and the selector itself. You will need some glue to accomplish your task.
Check this question.
Do you have to use a function pointer? In Objective-C, you can get the function pointer to an arbitrary method implementation (known as an IMP), but this is extremely uncommon, and usually not a good idea. Calling objc_msgSend() directly is also not the greatest idea, because there are several different variants of objc_msgSend(), and the compiler automatically chooses different ones to use based on the return type of the method. Methods that return an object go through objc_msgSend(), but objects that return structs might go through objc_msgSend() or they might go through objc_msgSend_stret(). And if the method returns a double, then it goes through objc_msgSend_fpret()...
Documentation: Objective-C Runtime Reference: Sending Messages
Instead, I might recommend using a target-action pair, or using a block. Then you might do something like:
myContextRef->target = anObjcObject;
myContextRef->action = #selector(invokeMe:);
And when you're done, do:
[myContextRef->target performSelector:myContextRef->action withObject:someReturnInformation];
Or maybe use a block:
myContextRef->completionHandler = [^(id returnInformation) {
[anObjcObject invokeMe:returnInformation];
} copy];
And then when you're done, do:
myContextRef->completionHandler(someReturnInformation);
(and don't forget to -release the block when you free the context)

Should I set up a protocol for Objective C array objects to avoid a compiler warning?

I have a class, let's call it ABC, with an NSArray *objects property, and the objects in the NSArray can be one of two different classes, X and Y. Both X and Y have a path property, but the compiler doesn't know this.
Therefore, even though ABC will always find the path property on my array objects, I get compiler warnings on my code -- "No 'path' method found". App runs fine but I'm getting annoyed by the warnings. How can I fix my code (with protocols?) so that the compiler stops complaining?
Thank you!
You need to import some header that declares a path method. When it's compiling your code, the compiler looks at the list of methods this file knows about and it sees that there is no path method. You just need to tell it that the method exists and its signature is whatever and the compiler will be satisfied. No protocol is necessary.
Do both X and Y derive from the same super class that contains "path"? If "path" is conceptually the same value AND X and Y are related by this value, then it should either be in a super class or protocol.
Additionally you can use NSKeyValueCoding protocol to directly access values by string via - (id)valueForKey:(NSString *)key. You do lose any type safety using this method, however.
valueForKey:#"path"