李晨光
李晨光

Reputation: 3

why the instance method that is "methodSignatureForSelector:" can be invoke by the class object

What make me doubt is that the class object can invoke instance method.

The method of "methodSignatureForSelector is instance method but when I invoke it by instance object, it go wrong.

NSString *classStr = @"NSInvocationObject";

// 获取class
Class objClass = NSClassFromString(classStr);

// 获取函数
SEL selector = NSSelectorFromString(@"classTest");

// 获取对象
Class stclass = [objClass class];
// - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE(""); here is a instance method ,but be invoke by objClass 
NSMethodSignature *singature = [objClass methodSignatureForSelector:selector];

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:singature];

invocation.target = objClass;
invocation.selector = selector;
[invocation invoke];ere

Upvotes: 0

Views: 348

Answers (1)

zrzka
zrzka

Reputation: 21249

Selector

  • Selector identifies method by name, not method implementations.
  • The hallo method in one class has the same selector as hallo method in another class.
  • A class method and an instance method with the same name have assigned the same selector.

Selector just identifies method by name and it's irrelevant if it's a class or an instance.

  • -(void)hallo; -> selector = hallo
  • +(void)hallo; -> selector = hallo

NSMethodSignature

Method signature describes type information of the return value and parameters. It doesn't say anything about method name, if it's an instance method, a class method, ... Just types.

  • -(void)hallo; - signature/encoding = v@:
    • v - void, return type
    • @ - object
    • : - selector
  • +(void)hallo; - signature/encoding = v@:

Type Encodings for more info.

To make it more obvious, imagine you have following methods:

- (void)foo {
}

+ (NSUInteger)foo {
    return 2;
}

Both of them have foo as a selector, but they do differ in encoding:

  • -(void)foo - signature/encoding = v@:
  • +(NSUInteger)foo - signature/encoding = Q@:

Usage

Here's an example. If your class method & instance method equals (name & return type & parameter types), you can use the same selector and method signature on the class and on the instance. invokeWithTarget: says - send a message (identifier by selector = method name & signature = return value & parameter types) - target can be anything that can receive this message.

Simplified a bit, but should explain what's going on here.

Sample class:

@interface MyClass: NSObject

+(void)hallo; // Class method
-(void)hallo; // Instance method

@end

@implementation MyClass

+(void)hallo {
    NSLog(@"classHallo");
}

-(void)hallo {
    NSLog(@"instanceHallo");
}

@end

Invocations:

Class c = [MyClass class];   // Class of MyClass
MyClass *i = [MyClass new];  // Instance of MyClass

// Selector identifies method by name
// It's irrelevant if it's a class or an instance method
SEL selector = @selector(hallo);

// Signature just contains types of return value & parameters
// It's irrelevant if it's a class or an instance method
// Get a signature of the +hallo method
NSMethodSignature *signature = [c methodSignatureForSelector:selector];

// Create invocation
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.selector = selector;  // Set the selector
[invocation invokeWithTarget:c]; // Invokes +hallo (class)
[invocation invokeWithTarget:i]; // Invokes -hallo (instance)

// Get a signature of the -hallo method
signature = [i methodSignatureForSelector:selector];

// Create invocation
invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.selector = selector;  // Set the selector
[invocation invokeWithTarget:c]; // Invokes +hallo (class)
[invocation invokeWithTarget:i]; // Invokes -hallo (instance)

Documentation

Archived, but still good to learn about:

Comments

MyClass only have a instance method: -(void)hallo; but when I execute the NSMethodSignature *signature = [c methodSignatureForSelector:@selector(hallo)], I can't get a signature of the method, signature is nil, if the selector just identifies method by name and it's irrelevant if it's a class or an instance, I should get a signature of method.

No. Check the methodSignatureForSelector: method aSelector argument documentation:

A selector that identifies the method for which to return the implementation address. When the receiver is an instance, aSelector should identify an instance method; when the receiver is a class, it should identify a class method.

What selector identifies? Method by name and it's hallo in our case - NOT +(void)hallo and NOT -(void)hallo, just hallo - this is what I meant with irrelevant comment.

When the receiver is an instance, aSelector should identify an instance method;

i is the receiver, i is an instance, so the following code asks for the -(void)hallo method signature, not +(void)hallo.

MyClass *i = [MyClass new];   // Instance of MyClass
SEL selector = @selector(hallo);
NSMethodSignature *signature = [i methodSignatureForSelector:selector];

when the receiver is a class, it should identify a class method.

c is the receiver, c is a class, so the following code asks for the +(void)hallo method signature, not -(void)hallo.

Class c = [MyClass class];   // Class of MyClass
SEL selector = @selector(hallo);
NSMethodSignature *signature = [c methodSignatureForSelector:selector];

There's also + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector which you can invoke on a class to get an instance method selector:

Class c = [MyClass class];   // Class of MyClass
SEL selector = @selector(hallo);
NSMethodSignature *signature = [c instanceMethodSignatureForSelector:selector];

i think i had understanded why the class object can inkove instance method, the class object's isa point to a meta-class that the meat-class is still a NSObject type (same as meta-class : NSObject) ; so the class object is same to a isntance object in the sense , this mean that class'object and instance'object can inkove instance method

I either don't understand what do you mean with this or you're misusing the instance method term.

Objective-C Classes Are also Objects:

In Objective-C, a class is itself an object with an opaque type called Class. Classes can’t have properties defined using the declaration syntax shown earlier for instances, but they can receive messages.

Objects Send and Receive Messages

Sending an Objective-C message is conceptually very much like calling a C function.

[i hallo] actually means send a hallo message to i & [c hallo] actually means send a hallo message to c where i is an instance and c is a Class.

It seems to me that you're just using wrong term. If I understood your comment correctly, yes, you can send a message to either an instance or a class.

Here're other resources related to this topic:

Upvotes: 2

Related Questions