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
Related
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.
I'm reading this book and it says that this code will compile but cause a runtime exception. But when I run it on my computer it doesn't compile: "No known instance method..."
#import "Fraction.h"
int main (int argc, char * argv[])
{
#autoreleasepool {
Fraction *f = [[Fraction alloc] init];
[f noSuchMethod];
}
return 0;
}
My question is when does doing this cause a runtime exception and when does it cause a compile-time warning?
The compile-time error is because the selector noSuchMethod does not appear on any class the compiler has seen. Under ARC, the compiler cannot safely decide how to apply memory management rules in that case (it could try to follow standard naming conventions, but that could lead to extremely difficult bugs if the selector were declared with alternate semantics in some other header). It is also almost certain a mistake, so the compiler rightfully balks at guessing. (There is another issue related to the return type, and before ARC the compiler would guess about that, but it generally wasn't what you wanted even if it happen to guess right most of the time.)
If -noSuchMethod were known to exist on some class, but not Fraction, then the compiler would issue a warning. At runtime, if f failed to respond, you'd get a runtime exception. (This was the old behavior; it seems that clang may have gotten a bit more strict in my experiments and will throw an error now in this case, too. This may be the confusion with your book if it was written before the change, or the author has not rechecked it in a while.)
If noSuchMethod were known to exist, but f were declared of type id, then no warning would be generated. At runtime, if f failed to respond, you'd get a runtime exception.
It depends ...
When you use ARC then, per default, the compiler will throw an error for a method call when the method name is not known at compile time.
When you don't ARC then you get a warning only at compile time.
You can, however, customize the warning/error level of the compiler to get is passed in both cases.
Objective-C binds method calls during runtime. If you manage to get it compiled then you could even react on the runtime error right before the exception is thrown and dynamcially register a method during runtime under the name of noSuchMethod and actually perform some code when ever the method is invoked in the future during the same runtime session. It is probably this behaviour of dynamic binding during runtime that the autor of your book is trying to explain by example.
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.
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).
I have a lot question marks tolling above my head.
What I don't get is before xcode 4.3 I needed to declare forward declarations (for private methods) in my implementation file.
Like in my .m file:
// deleting this with xcode 4.3 the below code still does work
// in previous versions i had to put this because otherwise the compiler can't find methodFirst
#interface DetailViewController ()
- (void)methodFirst;
- (void)methodSecond;
#end
#implementation DetailViewController
- (void) methodSecond
{
// if i delete the forward declaration now adays i dont get a compiler error that he cant find method first
[self methodFirst];
}
- (void) methodFirst
{
}
#end
Now it seems I don't need to do that anymore? Did Apple update the compiler so that it isn't needed anymore to put forward declarations?
I can't find any reference to an official Apple source about this change. I wonder what other people have encountered in their new environment.
As of the LLVM Compiler version shipped with Xcode 4.3, if you try to call a method that the compiler has not previously seen, it will look in the rest of the current #implementation block to see if that method has been declared later. If so, then it uses that, and you don't get a warning. Hence, as of Xcode 4.3, there's much less need to pre-declare your internal methods. Clearly, you still need to declare methods that are publicly exposed to other classes.
This change was noted in the release notes of some of the Xcode 4.3 betas, but apparently didn't make it into the "What's New in Xcode 4.3" final documentation.
Unlike has been suggested in other answers, this is not just an "Undeclared Selector" warning that has been turned off by default. In fact, if you're using ARC, unrecognized selectors are still hard errors. Try calling [self myNonexistentMethod] and you'll see; the compiler still complains.
There aren't any private methods in Objective-C. What you're thinking of is the class continuation, the "nameless" category interface you can declare in your .m file to declare methods that will be in the class implementation, but that aren't in the public interface.
There's never been a requirement to declare methods before they're used. However, it's always been a good idea, and the compiler has a warning flag to indicate when methods that haven't been seen are used. The reason is to do with the operating system's calling convention for functions. Different types, such as structures, floating point numbers, integer numbers, and pointers, can all be handled in different ways when they are the arguments to or return values from functions. Indeed, on different computers and in different operating systems, they are handled in different ways. To know how to handle the arguments and return values for an Objective-C method, the compiler needs to know the signature for that method: how many arguments of what types it takes, and what type it returns.
If it hasn't seen a declaration of the method, then the compiler will need to make a guess. If that guess is incorrect, then it can end up putting the wrong values into the arguments, or interpreting the return value incorrectly, or trying to take something off the stack that doesn't exist.