Objective C, why declare method in the interface - objective-c

I just started reading my first Objective-C book and it's mostly pretty clear, however I want to understand why it teaches me to declare a method in the interface first, I've tried deleting it from the interface and just doing it in the implementation section and all seems to work so my question is does it matter and if so, what does this help to accomplish?

It's C. Declaring functions/methods in a header allows other compilation units to see your function prototypes and compile based on them. Objective-C works via dynamic dispatch though, so even if you don't declare a method in the header, it still exists at runtime. When you call a method, it is resolved at runtime, so it doesn't matter if it was in the header or not.
The only issue is, if you don't include the method in the header, the compiler has to make assumptions about the return and argument types. It defaults to id, which is 4 or 8 bytes depending on your architecture, and therefore you will get into trouble if the actual return type is of a different size (e.g. structs or BOOL etc).

You have to declare your methods in the interface (header) to make it public (accessible by/from other classes). If you're using a method internally in your class only, you don't have to declare it in the interface.

Objective-C is a highly dynamic language (and runtime) that defers the decision-making to as late as possible.
The code runs fine because at runtime the object does actually respond to the selector you've specified.
By declaring methods, however, you can help the Objective-C compiler to provide you with help in checking that you won't encounter any unexpected situations at runtime.
For example, take the following class:
#interface MDFoo : NSObject
- (void)blah;
#end
#implementation MDFoo
- (void)blah {
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
- (void)boo {
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
#end
Let's say that in another controller class, you create an instance of MDFoo and want to send it some messages.
MDFoo *foo = [[MDFoo alloc] init];
[foo blah];
[foo boo]; // compiler warning
[foo yell]; // compiler warning
When you compile the program, the compiler should give you a warning that both of the last two methods can't be found and that an instance of MDFoo may not respond to those selectors.
If you then run the program, the following is what's logged:
foo[10540:303] [MDFoo blah]
foo[10540:303] [MDFoo boo]
foo[10540:303] -[MDFoo yell]: unrecognized selector sent to instance 0x1001082f0
foo[10540:303] *** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[MDFoo yell]:
unrecognized selector sent to instance 0x1001082f0'
So at runtime the warning about boo turned out to be nothing, but the warning about yell was correct and caused the application to terminate.
From a design standpoint, it's also how you let other objects know what messages can be called. (See Objective-C Programming Language: Defining a Class - The Role of the Interface).

Related

Why would compiler give an error if a method get called cannot be found within the given glass since Objective-C checks it during runtime? [duplicate]

I heard that Objective-C is influenced by the "message passing mechanism" of SmallTalk.
Objective-C, like Smalltalk, can use dynamic typing: an object can be
sent a message that is not specified in its interface. This can allow
for increased flexibility, as it allows an object to "capture" a
message and send the message to a different object that can respond to
the message appropriately, or likewise send the message on to another
object.
And I felt for codes like [anObject someMethod], the binding of someMethod to the machine code may happen at run-time..
Therefore, I write a demo like this:
#import <Foundation/Foundation.h>
#interface Person : NSObject {
#private char *name;
}
#property (readwrite, assign) char *name;
- (void)sayHello;
#end
#implementation Person
#synthesize name;
- (void)sayHello {
printf("Hello, my name is %s!\n", [self name]);
}
#end
int main() {
Person *brad = [Person new];
brad.name = "Brad Cox";
[brad sayHello];
[brad sayHelloTest];
}
I tried [brad sayHelloTest] to send brad a message sayHelloTest which brad doesn't know how to handle with.. I expect the error will NOT happen at compile-time..
However, the compiler still throws an error:
main.m:24:11: error: instance method '-sayHelloTest' not found (return type defaults to 'id') [-Werror,-Wobjc-method-access]
[brad sayHelloTest];
^~~~~~~~~~~~
main.m:3:12: note: receiver is instance of class declared here
#interface Person : NSObject {
^
Change [(id)brad sayHelloTest] to [(id)brad sayHelloTest]; doesn't work either.. (The compiling command is clang -Wall -Werror -g -v main.m -lobjc -framework Foundation -o main)
In Objective-C, does the binding of method really happen at "run-time"? If so, why will there be a compiler error like this?
If the binding doesn't happen at "run-time", why was "Objective-C" called "dynamic typing language"?
Does anyone have any ideas about this?
One job of a compiler is to catch as many errors at compile time as possible. If it can tell that the call will fail at runtime, you generally want it to complain.
You can suppress this via casting to show that runtime resolution is happening:
[(id)brad sayHelloTest];
Because the IDE can infer the obvious error from the context.
When you write if (a = 1),you will get a warning. A good IDE should help you find mistakes as early as possible.
I figured out the reason finally..
It throw errors during compiling because -Werror flag is included, which will turn warning into error..
http://clang.llvm.org/docs/UsersManual.html#cmdoption-Werror
After I delete -Werror flag, everything works as expected and the error only happens at run-time.
It has become a compiler error only within the last five years for there to be no known declaration of a method. It has to do with Automatic Reference Counting. Under ARC, the compiler is now responsible for the reference-counting-based memory management that Cocoa uses.
Given that responsibilty, it must be able to see the declarations of methods for any messages before they are sent, so that it knows what retains and releases are appropriate.
The method resolution (the lookup of the method on the class) does still happen at runtime, and -- particularly if you disable ARC -- you can still take advantage of message forwarding.
One way around ARC's requirement was given by Marcelo Cantos -- cast the receiver to id. Another is to use performSelector:. A third -- though I can't recommend it -- is to use objc_msgSend() directly.
Note that the "binding" of the method does, and always did, happen at compile time. Methods are associated with classes, when the classes are defined. Messages are distinct from methods, and it is they that resolve at runtime to a method.

Why #selector can call a method which is declared in an implementation file?

I have declared (between #interface and #end) and implemented a method in the .m file of Class A. For instance:
- (void)zoneChange:(NSNotification *)note
{
NSLog(#"The system time zone has changed!");
}
And in Class B, I want to send zoneChange message to a observer when the system zone is changed.
[[NSNotificationCenter defaultCenter] addObserver:anObserver
selector:#selector(zoneChange:)
name:NSSystemTimeZoneDidChangeNotification
object:nil];
The code above works. When user changes the time zone on Mac, zoneChange method get called. However, the compiler gives me a warning about the #selector: Undeclared selector "zoneChange:". What confused me is that sincezoneChange is a private method, why can it been seen by the #selector in Class B beyond the Class A? Anyone can explain it for me?
Private methods are just that: private. They still exist, they're just kept secret from the outside world. There's nothing built in to Objective-C to check where a method is being called from and complain at runtime; that compile-time warning about an undeclared selector is exactly the failure of Class B to see the method that you expect!
In the world of Objective-C, when you write [receiver zoneChange:note], you are actually sending a message (zoneChanged:) to the receiving object receiver, rather then making a function call directly. Although eventually there are some C-functions called, the Objective-C messages are still very different from the traditional C functions - I think that's why you are confused.
C functions are "static." The process of calling a C function is in fact just jumping to some point and executing some code, which is determined at compile time. However, messages are processed at run-time. Objective-C is a dynamic language, which means you can add methods or even classes at run time. As a result, there is no way to determine whether a class implements (or responds) to one particular selector at compile-time. Case in point, some accessors of NSManagedObject are added at run time when called. So despite the warning, actually you can send any message to any object (including nil) using performSelector without getting a compilation error.

Objective C beginner - method calls without casting

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.

Proxies and ARC, incompatible?

I'm trying to implement proxies for database stored procedures. The idea is to have my code find a series of stored procedures in the database, then create a proxy object in memory which will implement methods matching those stored procedures. That proxy object could be derived from NSProxy or NSObject, both should work. The basic idea is that any method calls made to my proxy object would go to resolveInstanceMethod: and be handled there if the method call matched a stored procedure in the database.
But before even getting close to my objective, I'm stumped by ARC seemingly not allowing me to do method calls to undeclared methods. Back in the days before ARC, we got a warning like "object may not respond to selector" from the compiler and that was that, but with ARC enabled, I'm getting a compiler error saying "no known instance method for selector...". This also happens if I first cast the proxy object to (id).
This all seems to imply that ARC is incompatible with runtime discovery of methods, which is one of the fundamental characteristics of objective-c. It seems to mandate that all methods used must be declared in interfaces before compilation, just as in C++.
Or, more likely, I'm missing something essential. If so, what?
Edited to include code:
int main(int argc, const char * argv[])
{
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
MyTargetClass *mtc = [[MyTargetClass alloc] init];
[mtc doSomething];
}
return 0;
}
MyTargetClass contains nothing:
#interface MyTargetClass : NSObject
#end
The [mtc doSomething] call elicits a warning if in a non-ARC project, but elicits a compiler error with ARC. IMHO that means I can't add methods to a class in runtime if ARC is used.
mwehlou,
First, if you don't show us any code, then it is really hard to help you.
Second, if you know that you will provide the instance method, then you can silence the warnings with the following #pragmas:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[Your Selector Based Code Here]
#pragma clang diagnostic pop
If that is the warning symbol, well, you can probably find it from within your build settings in Xcode.
Andrew

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.