Objective C beginner - method calls without casting - objective-c

I'm new to objective C and there's something odd that I don't understand.
How can I even call a NSString method on a NSDate object? For example:
NSString* ptr = [[NSString alloc] init];
[ptr uppercaseString];
NSDate* dPtr = [[NSDate alloc] init];
[dPtr uppercaseString];
id temp;
[temp uppercaseString];
Well, I do get that id can point to anything but how does it even know of the existence of the uppercaseString method without casting or something?
I'm have a C++ and Java background where I didn't notice anything like this before.
I'd love to get an explanation.

Unlike Java and C++, Objective-C has weak typing and late binding, which explains that you don't have to do a cast.
This is one of big dividing lines in object-oriented programming: Whether the language uses strong typing, so a variable can only hold references (or pointers) to objects of a given class and its subclasses, or if it can hold anything. If a variable can hold any object, the exact method implementation then has to be resolved at runtime when a message is received.
Objective-C got the philosophy of late binding from Smalltalk (see smalltalk), but is moving towards a more and more strictly typed language (formal protocols, use of the id type discouraged, etc.). The basics remain the same, however.
This is also one of the reasons, contrary to C++, Objective-C needs a runtime in order to run on your machine. Something has to take care of those method lookups.

Because the check for the existence of the method is not made right before the call but while trying to find the method. What actually happens (simplified a lot is)
[obj methodCall];
=> replaced => objc_send(obj, #"methodCall")
Inside the C function objc_send The call itself is resolved and made
If(obj.respondsTo(methodCall) Then obj.methodCall();

Objective-C methods are not the same as Java or C++ methods. They are messages, and they exist independently of any class or object. When you write (taken from CocoaDevCentral) in Photo.h:
#import <Cocoa/Cocoa.h>
#interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
- caption;
- photographer;
#end
you are saying that the Photo class has a caption and a photographer object, and that it will respond to the messages caption and photographer. That was the old pre-properties way of writing code for those two items.
You will write code in Photo.m giving the implementation of the two messages, so that a Photo can respond to them. But nothing stops you from sending caption to any object. It's like the old Far Side cartoon about what we say to dogs and what they hear. Any errors occur at runtime.
So, what happens when you send a message to an object that it does not know how to respond to? If you have not done anything special,
The runtime system packages the message into a thing of type SEL.
It sends the doesNotRecognizeSelector: message to the object with that selector.
The object inherits from NSObject an implementation that raises a NSInvalidArgumentException.
However, there are a few opportunities before that to intervene by overriding a method:
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
This lets you install an implementation at runtime.
- (id)forwardingTargetForSelector:(SEL)aSelector
This lets you nominate another object to accept the message.
- (void)forwardInvocation:(NSInvocation *)anInvocation
This lets you handle the message any way you want.
Before Objective-C gained blocks, there were a number of libraries that used forwarding for functional programming. Suppose you have an NSArray of Accounts that all understand the balance message. Suppose then you want to collect the balances of all the accounts in another NSArray. Instead of looping, the library provided a category for NSArray with a collect message, and you would write:
NSArray *accounts = ...;
NSArray *balances = [[accounts collect] balance];
The result of [accounts collect] does not have an implementation for the balance message; how could it? collect is provided by the library. Instead, it has a forwardInvocation: implementation that sends the balance message to all the members of accounts, and creates a new NSArray from them. One might use blocks and enumerateObjectsUsingBlock: these days, but that was a quite succinct and powerful technique.

Others have provided the answer - late binding, the method is looked up on the object at runtime without concern for the type of the object - if it has an appropriate method it is called.
However your call above [dPtr uppercaseString] should produce an error from Xcode. While the compiler will perform a lot of checks and refuse to compiler some programs (such as the above) that is really all the type-checking you get and it can be easily by-passed (e.g. [(id)dPtr uppercaseString] will remove the error and let you code run - when it will promptly fault due to no such method on NSDate).
Essentially the types are comments, if you use them properly you code should be type-correct, but there is no requirement for type-correctness for your code to compile.

Related

In Objective C, why am I allowed to assign an NSArray to an NSMutableArray without error or warning?

I'm disturbed by a weird behavior, illustrated by the following example:
NSMutableArray *a1 = [[NSMutableArray alloc] init]; // fine
NSMutableArray *a2 = [NSMutableArray array]; // fine, too
// compiler reports incompatible pointer types; good:
NSMutableArray *a3 = [[NSArray alloc] init];
// compiler says nothing and is happy to assign this!
NSMutableArray *a4 = [NSArray array];
Both init and array method of both the NSArray and NSMutableArray classes return id. However, the behavior when I call these methods is simply not the same, and clang lets me happily assign an empty NSArray to an NSMutableArray variable!
It turns out that clang will automatically change the return type of some methods, including the init family, to instancetype, and thus be able to determine at compile time that [[NSArray alloc] init] returns an NSArray * and not an NSMutableArray *. But this check simply doesn't work with the array method.
Why? Shouldn't lines like my last example generate at least a warning? Why aren't all these methods declared as returning instancetype? Will it change in the future?
Update
Good news: as of iOS 7, [NSArray array] returns instancetype, so the assignment to a4 above also yields a warning. Other methods like arrayWithContentsOfFile: or arrayWithContentsOfURL still return id, though…
But this check simply doesn't work with the array method. Why?
As the document you have linked describes, it is because -array does not yield a recognized Related Result Type. ObjC is very dynamic -- the compiler cannot guarantee the result type of +array. It does make that assumption with some methods because the naming conventions are well defined (e.g. +alloc, -init, +new, -self, etc.). So this implementation simply resorts to naming conventions.
The compiler also validates some naming conventions in areas you may not expect:
#implementation NSArray (DEMO)
- (id)initStr
{
return [NSString new]; // << warning. RE: init prefix
}
#end
Shouldn't lines like my last example generate at least a warning? Why aren't all these methods declared as returning instancetype? Will it change in the future?
instancetype was introduced about one year ago (from the looks of it). Some of the APIs were written decades ago. I suspect it will happen -- in time -- because (if used correctly) it can point out a lot of issues in existing code. Of course, those changes would break existing builds (again, typically good corrections if declared in the right places).
So file bugs and give the tools and libraries a few years to update. Assuming the changes are made, it will probably happen at a major OS update.
It would probably be best if it were enabled as an optional warning for some time (in the case of the system headers). Of course, they could still employ it with backwards compatibility for older compilers for new APIs.
Also, this change could be retrofitted quite easily (not that earlier compilers would make sense of the semantic difference between id and instancetype) by a simple typedef. One problem with a typedef is that it is a global declaration -- a compiler could restrict a word/modifier/attribute to a given scope, without causing all the pain of simulating a keyword by adding a global typedef. Apple's GCC may never support instancetype, so the logical way to introduce it for Apple's GCC may be a global typedef of id, which could cause problems for some people (with no semantic benefit, if that route were taken). Note that similar breaking changes have been made by Apple in the past.
As it turns out, you're not just allowed to use the wrong array type, you're allowed to use the wrong type of any object with a convenience initializer that returns id. For example, this compiles without a warning in sight:
NSMutableArray *a4 = [NSDictionary dictionary];
This is a side effect of using id to opt out of type safety, and as you note, it should be deprecated behavior and replaced with instancetype (which does throw an incompatible type warning when used in the manner above).
Unfortunately, it's not a bug. instancetype being a fairly new keyword, it's adoption is not widespread yet, and it would be a bold move to start using it throughout Apple's frameworks. You never know, there's always hope for the next SDK!

Dynamically bind method to selector at runtime

I want to programmatically associate code with selectors. I am not clear on how to do that in Objective C. In Ruby, I might override method_missing. In Common Lisp, I might define a macro. In Objective C, I can get part of the way there with #dynamic properties, but I'm unclear on how to actually implement them.
Here's a concrete example: I want to use an NSMutableDictionary to persistently store parts of my object. My class has two methods that handle the basic functionality, and a bunch of dynamic properties (matching #propertys exist in #interface):
#dynamic name;
#dynamic age;
#dynamic favoriteColor;
- (id)accessor:(NSString*)name {
return [[self dict] objectForKey:name];
}
- (void)mutator:(NSString*)name value:(id)value{
[[self dict] setObject:value forKey:name];
[[self dict] writeToFile:[self filename] atomically:YES];
}
Now I am looking for a way to translate a call like
[myInstance setName:#"iter"];
into
[self mutator:#"name" value#"iter"];
I wonder if there is an idiomatic way to do that in ObjC.
This isn't really an idiomatic thing to do in Objective-C, and there's certainly nothing like a Lisp macro available. NSObject and the runtime do, however, provide three possible points for you to intercept and handle messages referring to methods that don't otherwise exist. In the order they are used by the runtime: resolveInstanceMethod:, forwardInvocation: and doesNotRespondToSelector:. The documentation for each of them explains their use and gives some examples.
The first requires you to actually write out and add a method to the class, which doesn't seem like it will achieve the dynamic state of affairs you desire. The last by default raises an exception and doesn't provide for any return value. Almost certainly, forwardInvocation is what you want to look into. It allows your object to ask another object to handle a method call, including the passed arguments; it should be possible for you to make your object handle the call itself in a way that at least gets you close to what you're going for.
Also, the "Message Forwarding" chapter of the Runtime Programming Guide gives some examples of tasks similar to your requirement.
If an object does not have the method that you have called on it you can override forwardInvocation to delegate the method call to another object.
You can use the Objective-C runtime functions along with resolveInstanceMethod:. There's a short example in the resolveInstanceMethod: docs.

Failing to compile Objective-C on Xcode 4

I've bought Xcode 4 in order to start developing iOS applications. I come from a background of C, C++.
I've entered the examples from here:
http://en.wikibooks.org/wiki/Objective-C_Programming/syntax
to an XCode project ( Command line tool->Foundation template, not that I know what it means, just what I read somewhere ).
I named the files: point.h, point.m, main.m
At first, I got 3 errors. I got rid of 2 of them by changing the class's name from "Point" to "MyClass"
but now i get the following warning:
Method '+new' not found (return type defaults to 'id')
About the line:
MyClass *point = [MyClass new]
I also get no output in the debugger output section.
Any ideas how to solve this?
Seems you've got some issues...
I would say you forgot to inherit from NSObject, so the method +new is not found.
#interface MyClass : NSObject
#end
Ok, let's start at the beginning. Read this.
Now, "+ new" is meaningful. It's telling you that your requesting to send a message to the CLASS "MyClass". This is very different from an instance of "MyClass". Class messages in other languages are referred to as "static methods" or "class methods". In ObjC, class methods are represented with a +, and instance methods are represented with a -.
The most common class method is alloc. In ObjC you send this message to the class to create a new instance and return it. Once you've allocated memory for the new instance, you can send the init message to it. From then on, you can retain or release it. I think you get the idea. Most messages are intended to be sent to the instance of a class, not the class itself.
So....
MyClass* c = [[MyClass alloc] init];
[c doStuff];
[c release];
First, we allocate new memory to hold an object of MyClass. Then we send it an init message to ensure that it's all setup properly. After that, we send a doStuff message to the initialized instance of MyClass stored in the c variable. Then we release the memory by sending a release message.
A note about retain/release.
When we allocated, the retain count goes from 0 to 1. When we released, the retain count goes from 1 to 0. This is akin to some "smart pointers" in other languages. Once the retain count reaches 0, the object is deallocated. So, when the release message is sent here, you should be able to set a breakpoint inside your MyClass dealloc block (an instance method). Just remember, when you specify init or dealloc blocks, always send the message to super as well so that you get proper cleanup.
edit:
Yes, I think you should inherit from NSObject as #macmade says. You get all kinds of really useful stuff from this base class like new, alloc, init, release, retain, autorelease, etc. The reason for this is because your instance will be living on the heap, not the stack. In a language like Java or C#, you would get this unified type system transparently. Since this is ObjC, you need to opt-in for it.
If you would rather manage your Point like a struct (have a look at the built in CGPoint), you can do that too, but in that case you would need to manage it very differently. It would be stack memory, not heap memory. You can get a good example of the difference by looking at the source to things like CGPoint or CGRect. Actually, all this stuff is very clearly documented in Apple's The Objective-C Programming Language.

Objective C duplicate method signatures

Having just spent ages debugging this, I'm keen to understand what exactly is going on!
In a very contrived example, let's say we have two objects, Object1 has this method:
- (void) testMethod:(NSString *)testString
Object 2 has this method:
- (void) testMethod:(NSArray *)testArray
Then, back in Object1, there's the following code in a method:
NSArray *myArray = [[NSArray alloc] init];
[[[Object2 alloc] init] testMethod:myArray];
When I compile, Xcode gives a warning:
Incompatible pointer types sending 'NSArray *' to parameter of type 'NSString *'
I believe I'm right in saying the warning occurs because I never actually specify the type
of Object2. Explicitly casting the object to Object2 fixes it, but my questions are thus:
When calling testMethod on Object2, why is it using the method from Object1, when the objects are nothing to do with each other?
Why does the warning vanish if I move #import "Object2.h" into Object1.h instead of Object1.m?
Thank you!
When there are two methods with the same selector but different signatures, the compiler must decide which signature to use at compile time — because the signature can affect the code generated. Unfortunately, the compiler is deeply stupid, and the only way it has to tell which signature to use is by checking the static type of the receiver. In this case, both alloc and init return id, so the compiler has no information whatsoever with which it can decide what kind of object you're sending this message to. So it basically does this to break the tie: It closes its eyes, spins around in a circle a bunch of times, and whichever signature it's pointing to when it stops, that's the one it uses. Then it checks your argument type against this stochastic signature, and if it guessed wrong, it thinks you've passed the wrong type.
The best solution is to avoid signature collisions — descriptive method names usually take care of this on their own, and adding more specificity to one or both selectors is often a good way to solve the problem you're encountering (e.g. make it testMethodWithName:(NSString *)name).
It's also a good idea to statically type things as far as possible. Normally this isn't a problem, because you'll want to assign the newly created object to a variable anyway. In a pinch, when it would just be awkward to assign the result of the method to a variable, you can also just cast the ambiguous part to the correct type, like [(Object2 *)[[Object2 alloc] init] testMethod:myArray].

Why are alloc and init called separately in Objective-C?

Note: I'm relatively new to Objective-C and am coming from Java and PHP.
Could someone explain to me why I always have to first allocate and then initialize an instance?
Couldn't this be done in the init methods like this:
+ (MyClass*)init {
MyClass *instance = [MyClass alloc];
[instance setFoo:#"bla"];
return instance;
}
+ (MyClass*)initWithString:(NSString*)text {
MyClass *instance = [MyClass init];
[instance setFoo:text];
return instance;
}
...
Is this just a relict from the old C days or is there something that I'm not seeing?
I know this isn't a problem as I could as well always call alloc and init, but since it's a bit tedious I'd like to at least know why I'm doing it.
I'm liking the expressiveness of the language so far, but this is something that I want to fully understand in order to think the Objective-C way.
Thank you!
+new ends up sending an +alloc message to the class and an -init message to whatever comes back from +alloc.
The reason that NeXT departed from Stepstone's convention of using the +new message (which was a Smalltalk idea) is that early on, they encountered situations where they wanted to be able to initialize the same object more than once.
Because creating an instance and initializing an instance are two separate jobs.
You send an alloc message to the class to get an uninitialized instance. You must then initialize the instance, and you often have several ways to do that. For example:
myStr = [[NSString alloc] init]; //Empty string
myStr = [[NSString alloc] initWithFormat:#"%#.%#", parentKeyPath, key];
myStr = [[NSString alloc] initWithData:utf16data encoding:NSUnicodeStringEncoding error:&error];
myStr = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
Each of these initializes the string in a completely different way. How you initialize the string depends on what you want to initialize it from.
Of course, nobody likes writing alloc and then init and then autorelease every time, so you usually have convenience methods (e.g., stringWithFormat:) that do all three steps for you.
Edit: For more on this topic, including essential insights from commenters, see my blog post “Reunification”.
See NSZone.
+alloc is a shortcut cut for +allocWithZone:, which is a mechanism Cocoa provides for optimizing memory allocation.
So you have the option to do something like this:
foo = [[NSString allocWithZone:MyZone] initWithString:#"Foo"];
foo2 = [foo copyWithZone:MyZone];
The idea behind memory zones is that if you have a large number of similar objects that are frequently allocated and deallocated it may more efficient to use a separate memory zone for those objects.
In order for zoning to be effective you'd want to have +allocWithZone: available to every NSObject subclass, hence you need to separate allocation and initialization. You can create and use all the shortcuts you want, like +new, but underneath it all you need an -init method that initializes an object that has already been allocated.
"Separating the allocation and initialization stages of instance creation provides many benefits. It’s possible to use any variation of the +alloc class method to allocate an instance and then use any available initializer with the new instance.This makes it possible to create your own initialization methods without needing to provide alternate implementations of all allocation methods.
New allocation methods are seldom created because the existing methods meet almost every need. However, one or more new initializers are created for almost every class. Due to the separation of allocation and initialization stages, initializer implementations only have to deal with the variables of new instances and can completely ignore the issues sur- rounding allocation.The separation simplifies the process of writing initializers. Furthermore, Cocoa standard initializers like -initWithCoder: work with instances regardless of the way memory for the instance was allocated.
One negative consequence of the separation of allocation and initialization is the need to be aware of conventions such as the designated initializer.You must know which methods are designated initializers and how to create and document new initializers in sub- classes. In the long run, using designated initializers simplifies software development, but there is an argument to be made that theTwo-Stage Creation pattern adds to the early learning curve for Cocoa developers."
(c) Cocoa Design Patterns by Erik M. Buck and Donald A. Yacktman
You don't have to. You can use [MyClass new]. This is similar to your hypothetical init method.
Basically, Objective-C, which didn't have garbage collection initially, separates the concept of memory allocation and class initialization. That's why there are two distinct methods. When you call alloc, you are explicitly allocating memory.
Most classes have what you are asking for. You have gotten answers before on why this is like it is and why you wouldn't always want to use this all the time but if you read the documentation to classes you will see many class methods that act this way and they are often used.
For NSString you have, for example:
+ (id)string // (Empty string)
+ (id)stringWithFormat:... // Formatted string (like you use)
+ (id)stringWithContentsOfURL:... // String populated with contents of URL
And so on. And you would then use this like: NSString *myString = [NSString stringWithFormat:#"Hello %#\n", userName];
Most other classes have this, like NSArray:
+ (id)array
+ (id)arrayWithContentsOfFile:...
+ (id)arrayWithContentsOfURL:...
+ (id)arrayWithObjects:...
You just need to read the documentation. :) And read the other replies on why you don't want to use this too much.
alloc : Memory is allocated/given to the object-reference. Now reference has the possession of the memory but has not done anything yet. This memory be empty(rarest case) or with some anonymous data.
alloc and init : Allocated memory is cleaned/emptied. Memory is initiated by zero bit.
alloc and initwithdata... : Allocated memory is initiated with desired data respected to properties of the class.
For example when you purchase a plot you get the possession. This plot is given to you as it is, ruined bricks or old house may be there. This is alloc.
When you clean your plot and remove all dirt and litter. This is alloc with init.
When you build that into some valuable house it becomes more meaningful to you. And it is alloc initwith...