objective-cnsinvocation

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

Solution

  • Selector

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

    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.

    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:

    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: