Accessing forwardInvocation'd methods with ARC?
Asked Answered
H

1

2

I'm writing a clone of OpenStruct in Objective-C, using forwardInvocation:. However, the compiler isn't aware of the forwarding at compile time apparently. Compiling with ARC gives me a ton of warnings.

The code is open source and available on Github, but is currently compiled with -fno-objc-arc. If anyone could take a look at how I could make this ARC compatible, I'd greatly appreciate it.

Hylotheism answered 22/10, 2011 at 10:53 Comment(2)
It would help if you posted at least one of the errors and the corresponding code where the compiler has an issue with.Khudari
It is not possible to do what you’re trying to do. The compiler needs to know the method signatures at compile time and will complain if it doesn’t know them.Anemoscope
K
3

I tried this code:

OpenStruct *myStruct = [[OpenStruct alloc] initWithDictionary:myDictionary];
NSLog(@"%@ says %@", @"Cow",  [myStruct cowSound]);

I get warnings or errors with and without ARC, with LLVM 3.0 or LLVM GCC 4.2. I think you've misunderstood that forwardInvocation: still requires the method to be declared at some level, if only in a category (@interface) of the class you're sending the message to.

For example, when you do:

[someObject doSomething];

Then this will always generate at least a warning ("someObject may not respond to doSomething") if doSomething is not declared anywhere, regardless of whether the someObject class implements forwardInvocation or not. Like you noticed, the compiler is indeed not aware of the forwarding, and it also can't rely that your implementation of forwardInvocation guarantees message delivery. With LLVM 3.0 with or without ARC this may have been changed to generate an error instead, because ARC's development goal was to err on the side of more compiler errors rather than runtime issues.

Now you can still send messages to an object that doesn't implement a method. For example by using Objective-C runtime method objc_msgSend or via NSInvocation. But that voids the simple to use interface that you were planning to create.

Btw, your usage example for OpenStruct does not really justify why it is any simpler to access the dynamic struct via messaging compared to simple accessors like [struct getValueForKey:@"moo"]; … if you think this over then [struct moo] gives users little or no benefit over the first approach. The "moo" method is dynamic either way (a string or forwarded message) and a typo won't be caught at runtime.

Khudari answered 3/11, 2011 at 22:21 Comment(10)
The benefit would simply be smaller code. I think it's more to the point. [cow sound] immediately says that you're interested in the sound the cow makes.Hylotheism
Sure but then you could just write a Cow class with a sound method, right? Or, better yet, an Animal class that implements the sound method, and the sound filename can be set on init or via a property. All other classes like Cow, Frog, Pterodactyl inherit from Animal and can subsequently play sound.Khudari
The use case I'm thinking of is for an interface to a CMS. The content will be managed by a web application. The iOS application will sync to it. It's not possible to predefine all potential fields in the iOS code because they can be added and removed at will by the user through the web interface. Using dictionaries or key-value coding is clumsy syntax and a lot of typing compared with using the property syntax.Amateur
You can use the property syntax (eg. myLabel.stringValue) only with properties that are defined using @property in the header file. So as stated above, -(id)getObjectForKey: is most likely the better choice. Objective C is extremely verbose. It is generally advisable to embrace the best practices of a language rather than trying to circumvent them with dangerous hacks.Lavish
Your first point isn't true. foo.bar is equivalent to [foo bar] and works without any property declaration. On what basis are you calling this a "dangerous hack"?Amateur
foo.bar = 10 works if the -(void) setBar:(int)value {} setter method is implemented, likewise for the getter. I agree with Jakob that it is a dangerous hack because it would bypass any checks that the compiler can do and turn them into runtime errors (crashes) if they do occur.Khudari
The same problems apply to the alternatives though. Objects in dictionaries have no type checking. Key-value coding has no type checking. Are they both "dangerous hacks" as well?Amateur
I'm calling it a dangerous hack because it uses a very complicated feature of the Objective C language for something it is clearly not intended to do, while at the same time, there's a proven, simple, standard way of accomplishing the ultimate goal (key-value data storing). It seemed to me as if you are trying to implement a whole new framework just because -objectForKey: is too much to type.Lavish
@JakobEgger: That an object can have the ability to handle any message that comes to it is one of the unique features of Objective-C, and has many uses. I wouldn't call it a dangerous hack.Scythe
@Scythe It has many uses, but I doubt that re-implementing a dictionary is a good example. I'm not calling it a dangerous hack in general, just in this specific situation.Lavish

© 2022 - 2024 — McMap. All rights reserved.