为什么 "methodSignatureForSelector:" 的实例方法可以被 class 对象调用

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

让我怀疑的是class对象可以调用实例方法。

methodSignatureForSelector的方法是实例方法 但是当我通过实例对象调用它时,它出错了。

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

选择器

  • 选择器按名称识别方法,而不是方法实现。
  • 一个 class 中的 hallo 方法与另一个 class 中的 hallo 方法具有相同的选择器。
  • 一个 class 方法和一个同名的实例方法分配了相同的选择器。

选择器只是通过名称来识别方法,它是 class 还是实例无关紧要。

  • -(void)hallo; -> 选择器 = hallo
  • +(void)hallo; -> 选择器 = hallo

NSMethodSignature

方法签名描述了return值和参数的类型信息。它没有说明方法名称,如果它是一个实例方法,一个 class 方法,... 只是类型 .

  • -(void)hallo; - signature/encoding = v@:
    • v - 无效,return 类型
    • @ - 对象
    • : - 选择器
  • +(void)hallo; - signature/encoding = v@:

Type Encodings 了解更多信息。

为了让它更明显,假设您有以下方法:

- (void)foo {
}

+ (NSUInteger)foo {
    return 2;
}

它们都有 foo 作为选择器,但它们在编码上确实不同:

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

用法

举个例子。如果您的 class 方法和实例方法等于(名称和 return 类型和参数类型),您可以在 class 和实例上使用相同的选择器和方法签名。 invokeWithTarget: 表示 - 发送消息(选择器标识符 = 方法名称和签名 = return 值和参数类型) - target 可以是任何可以接收此消息的东西。

简化了一点,但应该解释这里发生了什么。

样本class:

@interface MyClass: NSObject

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

@end

@implementation MyClass

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

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

@end

调用:

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)

文档

已存档,但仍然值得学习:

评论

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.

没有。检查 methodSignatureForSelector: 方法 aSelector 参数文档:

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.

什么选择器识别?按名称命名的方法,在我们的例子中是 hallo - 不是 +(void)hallo 也不是 -(void)hallo,只是 hallo - 这就是我所说的无关评论。

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

i是接收者,i是实例,所以下面的代码要求的是-(void)hallo方法签名,而不是+(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是接收者,c是class,所以下面的代码请求的是+(void)hallo方法签名,而不是-(void)hallo

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

还有 + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector,您可以在 class 上调用它来获取实例方法选择器:

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

我要么不明白你的意思,要么你误用了实例方法术语。

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]实际上意味着发送hallo消息到i&[c hallo]实际上意味着发送halloc 的消息,其中 i 是一个实例,cClass.

在我看来,您只是用错了术语。如果我正确理解了您的评论,是的,您可以向实例或 class.

发送消息

以下是与此主题相关的其他资源: