Is it possible to invoke a msg from a different class? - objective-c

I have been knocking my head against the wall trying to figure whether it is possible to call a function defined in a different class. Unfortunately, my limited knowledge in Objective C prevented me to reach a satisfactory answer. Basically, I have one class called Caller and a different class called Functions that I would like to hook to at run time. Class Functions will have all the functions defined that caller is going to reference to at run time.
This is the code in its entirety:
--- Caller.h -------------------
#import "Functions.h"
#interface Caller
{
int callerId;
NSMethodSignature *sig;
NSInvocation *func;
}
#property(retain) NSInvocation* func;
#end
--- Caller.m -------------------
#import "Caller.h"
#implementation Caller
#Synthesize func;
-(id)initWithFunction: (SEL)f
{
if (self)
{ Sig = [Caller instanceMethodSignatureForSelector: f];
func= [NSInvocation invocationWithMethodSignature: Sig];}
return self;
}
#end
--- Functions.h -------------------
#interface Functions
-(int)SayHello;
#end
--- Functions.m -------------------
#import "Functions.h"
#implementation
-(int)SayHello
{
NSLog(#"Hello");
return 0;
}
---------main.m-----------------
#import <Foundation/Foundation.h>
#import "Caller.h"
#import "Functions.h"
int main
{
NSAutoreleasePool * pool [[NSAutoreleasePool alloc]init];
Functions* ftn = [[Functions alloc]init];
Caller * c = [[Caller alloc]initWithFunction: #selection(SayHello)];
[c.func setTarget:c];
[c.func invoke];
[pool drain];
return 0;
}
The code was compiling fine but at run time, it encountered an error because instanceMethodSignatureForSelector is 0. If I make Caller class inherit from Functions class, then the program will work like a charm. But Functions class in my case has to be independent from Caller class. Is there a work around?

+instanceMethodSignatureForSelector: returns nil because Caller doesn't have such a method - it is implemented in another class which you can't know with the given data at that point.
Instead you can retrieve the method signature from the target later, e.g.:
#implementation Caller
// ...
- (void)invokeWithTarget:(id)target {
NSMethodSignature *sig = [target methodSignatureForSelector:sel_];
// ...
}

Related

Assigning instance variance in method leads to segfault

Below is rather basic objective-c code. It contains one instance variable i. The problem is whenever I attempt to assign to it, it leads to segfault almost immediately following that assignment operation. Note: It does not segfault at the point of assignment. Usually it segfaults after the assignment and I try to invoke a method. ALSO, notice that this is not your standard mac/apple objective-c code. I'm using cygwin (Linux) plain vanilla version of objective-c. So I have to generate my own alloc and dealloc methods.
#import <objc/runtime.h>
#import <objc/Object.h>
#interface Test
{
int i;
}
+(id)alloc;
- (id) init;
- (int) load;
#end
#implementation Test
+(id)alloc
{
self = class_createInstance(self,0);
return self;
}
-(id)init
{
i = 0; // <------ if I comment out this line, there is no segfault
return self;
}
-(int) load
{
return i;
}
#end
int main(int argc, const char * argv[])
{
Test * test = [[Test alloc] init];
int v = [test load]; //segfaults here (NOTE: if I comment out this line, it does not segfault)
return 0;
}
What is causing the segfault?
I expect that, for a root class like yours, you need to explicitly declare the isa instance variable. Without it, your i is being interpreted as though it were the isa, which is why you get a crash.
So:
#interface Test
{
Class isa;
int i;
}
If you didn't intend to create a root class, you should probably inherit from Object or the like.

Objective-C hidden static method calling

I google this question and spend some time to figure it out by myself but with a bad luck.
I need to call class's static method which is hidden for class's user.
// MyClass.h
#interface MyClass : NSObject
#end
// MyClass.m
#implementation MyClass
- (NSString *)myInstanceMethod
{
return #"result string";
}
+ (NSString *)myStaticMethod
{
return #"result string";
}
#end
------------------------------------------------------------
// MyCallerClass.m
#import "MyClass.h"
#implementation MyCallerClass
- (void) testMethod
{
MyClass *inst = [MyClass new];
// call 1
NSString *resultInstance = [inst performSelector:#selector(myInstanceMethod)];
// call 2
NSString *resultStaitc = [inst performSelector:#selector(myStaticMethod)];
// call
[MyClass myStaticMethod];
}
#end
Call 1 works good, Call 2 returns nil, Call 3 does not compile.
How can I call static method which does not defined in .h file and give correct returned object?
Thank in advance,
Rost
For Call 2 ,
since it is an class method you should call like
NSString *resultStaitc = [[inst class] performSelector:#selector(myStaticMethod)];
inst is the object.To call a class method you must call with class.
The object instance's class is supposed to be calling the method, not the instance itself.
For call 3
It should be working fine,The result value is never used .the compile error is because
+ (NSString *)myStaticMethod;
not declared in .h
use
NSString *resultStaitc1 =[MyClass myStaticMethod];
and it will return the value to the resultStaitc1
Another option is to declare an informal protocol for MyClass at the top of MyCallerClass.m. An informal protocol is just a category interface without the implementation block. You can stick you method declaration(s) in there. It does raise synchronisation problems between the two source files, but so does performSelector:. Doing it this way lets you call methods that have a different signature to just take [0-2] object arguments and return and object.

Is it possible to declare an Objective-C method outside a class?

I know that you can declare a C function outside of a class, but is it possible to declare a Objective-C method outside of a class?
Example:
// Works
void printHelloC()
{
NSLog(#"Hello.");
}
// Error
-(void) printHelloOC
{
NSLog(#"Hello.");
}
int main (int argc, const char * argv[])
{
#autoreleasepool {
printHelloC();
[self printHelloOC];// 'self' obviously would not work but you get the idea
}
return 0;
}
It depends. You can do something similar with method adding at runtime:
#import <objc/runtime.h>
void myCustomMethod(id self, SEL _cmd, id arg1, id arg2)
{
NSLog(#"This is a test, arg1: %#, arg2: %#", arg1, arg2);
}
int main(int argc, char *argv[])
{
Class NSObjClass = [NSObject class];
class_addMethod(NSObjClass, #selector(myNewMethod::), (IMP) myCustomMethod, "v#:##");
NSObject myObject = [NSObject new];
[myObject myNewMethod:#"Hi" :#"There"];
[myObject release];
return 0;
}
But that is about it outside of a #class construct, and it really just covers up what happens with a category.
You can use a category for this.
As an instance method:
#interface NSObject (MONStuff)
- (void)printHelloOC;
#end
#implementation NSObject (MONStuff)
- (void)printHelloOC
{
NSLog(#"Hello.");
}
#end
// in use:
NSObject * obj = ...;
[obj printHelloOC];
As a Class method:
#interface NSObject (MONStuff)
+ (void)printHelloOC;
#end
#implementation NSObject (MONStuff)
+ (void)printHelloOC
{
NSLog(#"Hello.");
}
#end
// in use:
[NSObject printHelloOC];
Of course, you must associate that with a class - so it's not exactly the same as you posted, but it's a close definition + declaration separate from the formal class declaration.
A method without an associated class is a meaningless concept. Functions, as you've noted, are just fine.
No, it is not possible - you will need to either use global C functions or class (+) methods.
Objective c functions are always associated with a class. If you mean you want to use an objective-c function without instantiating a class, you can of course write a class method (notice the plus sign instead of the usual hyphen)
#interface Test
+ (void)aClassMethod;
#end
then you can call it by calling
[Test aClassMethod];

Objective-C inheritance; calling overridden method from superclass?

I have an Objective-C class that has a method that is meant to be overridden, which is uses in a different method. Something like this:
#interface BaseClass
- (id)overrideMe;
- (void)doAwesomeThings;
#end
#implementation BaseClass
- (id)overrideMe {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (void)doAwesomeThings {
id stuff = [self overrideMe];
/* do stuff */
}
#end
#interface SubClass : BaseClass
#end
#implementation SubClass
- (id)overrideMe {
/* Actually do things */
return <something>;
}
#end
However, when I create a SubClass and try to use it, it still calls overrideMe on the BaseClass and crashes due to doesNotRecognizeSelector:. (I'm not doing a [super overrideMe] or anything stupid like that).
Is there a way to get BaseClass to call the overridden overrideMe?
What you are describing here should work so your problem is likely elsewhere but we don't have enough information to help diagnose it.
From your description, I'd say either the instance you're messaging is not the class you think it is or you made some typo in your code when declaring the method names.
Run your application under gdb, add a symbolic breakpoint on objc_exception_throw, reproduce your problem. Once your process has stopped on the "doesNotRecognizeSelector" exception, print object description and it's class.
Or log it before calling -overrideMe:
NSLog(#"object: %# class: %#", obj, [obj class])
Write a category for BaseClass to override the method.
#interface BaseClass (MyCategory)
- (id) overrideMe;
#end
#implementation BaseClass (MyCategory)
- (id) overrideMe
{
/* Actually do things */
return <something>;
}
#end
Now all instances of BaseClass will respond to selector overrideMe with the new implementation.

Method signature for a Selector

I'm new to the Objective C business (Java developer most of the time) and am woking on my first killer app now. :-)
At the moment I am somehow confused about the usage of selectors as method arguments. They seem to be a little bit different than delegates in C# for example.
Given the following method signature
-(void)execute:(SEL)callback;
is there a way to enforce the signature for the selector passed to such a method?
The method is expecting a selector of a method with the following signature
-(void)foo:(NSData*)data;
But the SEL (type) is generic, so there is a good chance to pass a wrong selector to the
execute method. OK at least at runtime one would see a funny behavior... but I would like to see a compiler warning/error when this happens.
The quick answer is: no, there is no way to have the compiler enforce the method signature of a method selector that is provided via a SEL argument.
One of the strengths of Objective-C is that it is weakly-typed language, which allows for a lot more dynamic behaviour. Of course, this comes at the cost of compile-time type safety.
In order to do what (I think) you want, the best approach is to use delegates. Cocoa uses delegates to allow another class to implement "callback"-type methods. Here is how it might look:
FooController.h
#protocol FooControllerDelegate
#required:
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#interface FooController : NSObject
{
id <FooControllerDelegate> * delegate;
}
#property (assign) id <FooControllerDelegate> * delegate;
- (void)doStuff;
#end
FooController.m
#interface FooController (delegateCalls)
- (void)handleData:(NSData *)data;
#end
#implementation FooController
#synthesize delegate;
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
delegate = nil;
...
return self;
}
- (void)doStuff
{
...
[self handleData:data];
}
- (void)handleData:(NSData *)data
{
if (delegate != nil)
{
[delegate handleData:data forFoo:self];
}
else
{
return;
// or throw an error
// or handle it yourself
}
}
#end
Using the #required keyword in your delegate protocol will prevent you from assigning a delegate to a FooController that does not implement the method exactly as described in the protocol. Attempting to provide a delegate that does not match the #required protocol method will result in a compiler error.
Here is how you would create a delegate class to work with the above code:
#interface MyFooHandler <FooControllerDelegate> : NSObject
{
}
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#implementation MyFooHandler
- (void)handleData:(NSData *)data forFoo:(FooController *)foo
{
// do something here
}
#end
And here is how you would use everything:
FooController * foo = [[FooController alloc] init];
MyFooHandler * fooHandler = [[MyFooHandler alloc] init];
...
[foo setDelegate:fooHandler]; // this would cause a compiler error if fooHandler
// did not implement the protocol properly
...
[foo doStuff]; // this will call the delegate method on fooHandler
...
[fooHandler release];
[foo release];
To directly answer your question, no, the SEL type allows any type of selector, not just ones with a specific signature.
You may want to consider passing an object instead of a SEL, and document that the passed object should respond to a particular message. For example:
- (void)execute:(id)object
{
// Do the execute stuff, then...
if ([object respondsToSelector:#selector(notifyOnExecute:)]) {
[object notifyOnExecute:self];
}
// You could handle the "else" case here, if desired
}
If you want to enforce the data handling, use isKindOfClass inside your selector. This works a lot like instanceof which you are familiar with in Java.