Objective c 为什么可以对类名或类对象使用-respondsToSelector:instance方法?

Objective c 为什么可以对类名或类对象使用-respondsToSelector:instance方法?,objective-c,class,class-method,instance-methods,respondstoselector,Objective C,Class,Class Method,Instance Methods,Respondstoselector,在目标C,4e,第9章,程序9.3中的编程中: #import "Square.h" int main (int argc, char * argv[]) { @autoreleasepool { Square *mySquare = [[Square alloc] init]; ... // respondsTo: if ( [mySquare respondsToSelector: @selector (setSide:)] == YES

在目标C,4e,第9章,程序9.3中的编程中:

#import "Square.h"
int main (int argc, char * argv[])
{
   @autoreleasepool {
      Square *mySquare = [[Square alloc] init];
      ...
      // respondsTo:
      if ( [mySquare respondsToSelector: @selector (setSide:)] == YES )
         NSLog (@"mySquare responds to setSide: method");
      ...
      if ( [Square respondsToSelector: @selector (alloc)] == YES )
         NSLog (@"Square class responds to alloc method");
      ...
   }
   return 0;
}
问题1:

既然-respondsToSelector:是实例方法,而不是类方法,为什么可以直接在Square类上使用它呢

问题2:

书上说你可以在这里使用Square而不是[Square class]。这只是一个例外的捷径,还是背后有什么机制

任何帮助都将不胜感激!提前谢谢

//第一季度:

既然-respondsToSelector:是实例方法,而不是类方法,为什么可以直接在Square类上使用它呢//

您似乎认为类方法不能从实例方法调用,反之亦然。相反,这似乎是方法-RealdStistRe选择器的意图,很可能通过用类方法获取发送器的类,然后查询类是否响应选择器并在更本地化的示例中返回“是”或“否”,请考虑以下内容:

-(void)someInstanceMethod{
     [MyCurrentClass doClassMethod]; //basic equivalent of [self doClassMethid];
}
在Objective-C中完全有效,前提是MyCurrentClass都是alloc'd和init'ed

//问题2:

书上说你可以在这里使用Square而不是[Square class]。这只是一个例外的捷径,还是背后有什么机制//

将-class发送给一个类是完全多余的!它没有什么意义,只是额外的不必要的代码-类只是查询Receiver的类,无论它是实例还是类对象。

/p>/Q1:

既然-respondsToSelector:是实例方法,而不是类方法,为什么可以直接在Square类上使用它呢//

您似乎认为类方法不能从实例方法调用,反之亦然。相反,这似乎是方法-RealdStistRe选择器的意图,很可能通过用类方法获取发送器的类,然后查询类是否响应选择器并在更本地化的示例中返回“是”或“否”,请考虑以下内容:

-(void)someInstanceMethod{
     [MyCurrentClass doClassMethod]; //basic equivalent of [self doClassMethid];
}
在Objective-C中完全有效,前提是MyCurrentClass都是alloc'd和init'ed

//问题2:

书上说你可以在这里使用Square而不是[Square class]。这只是一个例外的捷径,还是背后有什么机制//


将-class发送给一个类是完全多余的!它没有什么意义,只是额外的不必要的代码-类只是查询Receiver的类,无论它是实例还是类对象。

真正的实现,直接从NSObject.m开始,如下所示:

- (BOOL)respondsToSelector:(SEL)aSelector {
        PF_HELLO("")
        return class_respondsToSelector( isa, aSelector );
}
现在,我不知道为什么会有PF_HELLO,但正如您所看到的,它实际上是在运行时询问类嘿,您是否有一个称为aSelector的isa[实例]方法


而且,在Objective-C中,类方法也属于实例,但是,在类方法之前调用与类方法同名的实例方法的优先级较低

Objective-C动态类型的另一个方面是id类型实际上声明如下:

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;
因此,您的实例对象实际上是一个类指针。这意味着-respondsToSelector消息也会转到实例类型的类。在您的例子中,这意味着-respondsToSelector将首先进入objc_类

现在,在一个测试案例中,直接从libFoundation得出,我的答案可以总结如下:

Test *tst = [Test new];

    fail_unless([tst respondsToSelector:@selector(testInstanceMethod)], "-[Test respondsToSelector:] returned NO for a valid instance method (testInstanceMethod).");
    fail_if([tst respondsToSelector:@selector(testClassMethod)], "-[Test respondsToSelector:] returned YES for a class method (testInstanceMethod).");
    fail_unless([Test respondsToSelector:@selector(testClassMethod)], "+[Test respondsToSelector:] returned NO for a valid class method (testClassMethod).");
    fail_if([Test respondsToSelector:@selector(testInstanceMethod)], "+[Test respondsToSelector:] returned YES for an instance method (testInstanceMethod).");
    fail_unless([tst respondsToSelector:@selector(init)], "-[Test respondsToSelector:] returned NO for an inherited instance method (-[NSObject init].");
    fail_unless([Test respondsToSelector:@selector(alloc)], "+[Test respondsToSelector:] returned NO for an inherited class method (+[NSObject alloc]).");

    [tst release];

NSObject.m的真正实现是这样的:

- (BOOL)respondsToSelector:(SEL)aSelector {
        PF_HELLO("")
        return class_respondsToSelector( isa, aSelector );
}
现在,我不知道为什么会有PF_HELLO,但正如您所看到的,它实际上是在运行时询问类嘿,您是否有一个称为aSelector的isa[实例]方法


而且,在Objective-C中,类方法也属于实例,但是,在类方法之前调用与类方法同名的实例方法的优先级较低

Objective-C动态类型的另一个方面是id类型实际上声明如下:

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;
因此,您的实例对象实际上是一个类指针。这意味着-respondsToSelector消息也会转到实例类型的类。在您的例子中,这意味着-respondsToSelector将首先进入objc_类

现在,在一个测试案例中,直接从libFoundation得出,我的答案可以总结如下:

Test *tst = [Test new];

    fail_unless([tst respondsToSelector:@selector(testInstanceMethod)], "-[Test respondsToSelector:] returned NO for a valid instance method (testInstanceMethod).");
    fail_if([tst respondsToSelector:@selector(testClassMethod)], "-[Test respondsToSelector:] returned YES for a class method (testInstanceMethod).");
    fail_unless([Test respondsToSelector:@selector(testClassMethod)], "+[Test respondsToSelector:] returned NO for a valid class method (testClassMethod).");
    fail_if([Test respondsToSelector:@selector(testInstanceMethod)], "+[Test respondsToSelector:] returned YES for an instance method (testInstanceMethod).");
    fail_unless([tst respondsToSelector:@selector(init)], "-[Test respondsToSelector:] returned NO for an inherited instance method (-[NSObject init].");
    fail_unless([Test respondsToSelector:@selector(alloc)], "+[Test respondsToSelector:] returned NO for an inherited class method (+[NSObject alloc]).");

    [tst release];
从Objective-C编程语言

所有对象、类和实例都需要一个到 运行时系统。类对象和实例都应该能够 反思他们的能力,并报告他们在社会中的地位 继承层次结构。这是NSObject类的范围 提供此接口

因此,NSObject方法不必实现两次,一次就可以实现一次 为实例提供运行时接口,并再次复制该接口 类对象的接口类对象得到特殊特许,可以执行 e根类。 当一个类对象收到一条它不能用 类方法,运行时系统确定是否存在根 可以响应的实例方法。唯一的实例方法 类对象可以执行的是在根类中定义的类,并且只有在没有类方法可以执行该任务的情况下才能执行

在本例中,NSObject是根类。由于NSObject实例都符合NSObject协议,其中定义了-respondsToSelector:,大多数类对象应该能够从Objective-C编程语言执行-respondsToSelector:。

所有对象、类和实例都需要一个到 运行时系统。类对象和实例都应该能够 反思他们的能力,并报告他们在社会中的地位 继承层次结构。这是NSObject类的范围 提供此接口

因此,NSObject方法不必实现两次,一次就可以实现一次 为实例提供运行时接口,并再次复制该接口 类对象的接口类对象被授予执行根类中定义的实例方法的特殊特权。 当一个类对象收到一条它不能用 类方法,运行时系统确定是否存在根 可以响应的实例方法。唯一的实例方法 类对象可以执行的是在根类中定义的类,并且只有在没有类方法可以执行该任务的情况下才能执行


在本例中,NSObject是根类。由于NSObject实例都符合NSObject协议,其中定义了-respondsToSelector:,因此大多数类对象应该能够执行-respondsToSelector:。

Objective C运行时当前将类作为其他类的实例对象实现。因此,类将响应某些实例方法。

Objective C运行时当前将类实现为其他类的实例对象。因此,类将响应某些实例方法。

Q1:

简单的答案是,除了类方法之外,您可以调用根类的任何实例方法,不管您的类的根类是什么;在本例中,NSObject位于类对象上

更复杂的答案是类对象是元类的实例。而实例方法是在类中定义的实例上的方法;类方法是在元类中定义的类对象上的方法。每个类都有自己的元类。元类的继承遵循其类的继承;i、 e.NSString的元类继承自NSObject的元类。最终,根类的元类继承自根类;i、 e.NSObject的元类继承自NSObject。这就是为什么NSObject的所有实例方法都可用于类对象的原因

问题2:

[Square class]调用与-class无关的类方法+类+类本质上是一个标识方法,它只返回对其调用的对象,就像-self一样;i、 如果foo是指向类对象的指针,那么[foo class]与foo相同

所以+类看起来很没用;我们为什么要用它?这是因为在Objective-C语言的语法中,类名不像Smalltalk那样是有效的表达式。所以你不能说id bar=Square;;那是不可能的。作为语法中的特例,在消息调用表达式中允许用类名代替接收方,并将消息发送给类对象;i、 [把某物弄成正方形]。因此,如果您想在任何其他表达式上下文中使用class对象,我们可以通过调用像+class这样的identity方法来迂回地实现这一点;i、 e.[Square class]是一个可以在任何表达式上下文中使用的表达式[Square self]也可以工作,但我们按照约定使用[Square class],这是不幸的,因为它与-class混淆了;我们本希望只使用Square,但由于语言原因,我们不能使用Square

在您的例子中,它已经是消息调用表达式中的接收方,因此不需要执行[Square class];Square已经在那里工作了。

Q1:

简单的答案是,除了类方法之外,您可以调用根类的任何实例方法,不管您的类的根类是什么;在本例中,NSObject位于类对象上

更复杂的答案是类对象是元类的实例。而实例方法是在类中定义的实例上的方法;类方法是在元类中定义的类对象上的方法。每个类都有自己的元类。元类的继承遵循其类的继承;i、 e.NSString的元类继承自NSObject的元类。最终,根类的元类继承自根类;i、 e.NSObject的元类继承自NSObject。这就是为什么NSObject的所有实例方法都可用于类对象的原因

问题2:< /p> [Square class]调用与-class无关的类方法+类+类本质上是一个标识方法,它只返回对其调用的对象,就像-self一样;i、 如果foo是指向类对象的指针,那么[foo class]与foo相同

所以+类看起来很没用;我们为什么要用它?这是因为在Objective-C语言的语法中,类名不像Smalltalk那样是有效的表达式。所以你不能说id bar=Square;;那是不可能的。作为语法中的特例,在消息调用表达式中允许用类名代替接收方,并将消息发送给类对象;i、 [把某物弄成正方形]。因此,如果您想在任何其他表达式上下文中使用class对象,我们可以通过调用像+class这样的identity方法来迂回地实现这一点;i、 e.[Square class]是一个可以在任何表达式上下文中使用的表达式[Square self]也可以工作,但我们按照约定使用[Square class],这是不幸的,因为它与-class混淆了;我们本希望只使用Square,但由于语言原因,我们不能使用Square



在您的例子中,它已经是消息调用表达式中的接收方,因此不需要执行[Square class];Square已经在那里工作了。

1。简单的回答是,归根结底,它们都是选择器。2.Square大写已经是一个类,class方法实际上返回相同的对象。Q2:Square计算为Square的元类,它是一个表示Square类的对象。它是一个对象实例,因此您可以向它发送消息。将+类发送到一个元类对象,会返回自身。实际上,我上面的评论回答了您的两个问题:@CodaFi:谢谢您的快速回复!但是,像-respondsToSelector:这样的实例方法不应该只用于实例对象吗?好吧,您必须理解选择器是什么。无论是类还是实例方法,所有选择器都是SEL类型,这是该方法采用的参数之一。它只是检查您提供的类是否响应它。类方法无论如何都可以在实例方法内部调用,所以这一点是没有意义的。简单的回答是,归根结底,它们都是选择器。2.Square大写已经是一个类,class方法实际上返回相同的对象。Q2:Square计算为Square的元类,它是一个表示Square类的对象。它是一个对象实例,因此您可以向它发送消息。将+类发送到一个元类对象,会返回自身。实际上,我上面的评论回答了您的两个问题:@CodaFi:谢谢您的快速回复!但是,像-respondsToSelector:这样的实例方法不应该只用于实例对象吗?好吧,您必须理解选择器是什么。无论是类还是实例方法,所有选择器都是SEL类型,这是该方法采用的参数之一。它只是检查您提供的类是否响应它。类方法无论如何都可以在实例方法内部调用,所以这一点是没有意义的。在Q2上它应该是+Class,否则调用将不起作用。我还要注意,类方法也属于实例,但不具有优先权。您的Q1完全忽略了这个问题,这就是为什么您可以在类对象上调用respondsToSelector:的原因。在Q2上它应该是+class,否则调用将不起作用。我还要注意,类方法也属于实例,但不具有优先权。您的Q1完全没有回答这个问题,这就是为什么可以在类对象上调用respondsToSelector:的原因。我想知道NSObject.m代码来自哪里。不知道苹果公司何时开放他们的基础框架。旧新闻,GNUStep和CigaTRON。GNUSTEP是基于Mac OS X基金会之前的OpenSTEP,来自原始NEXSTEP基金会。您的意思是所有实例方法都可以执行类对象吗?但@ZhangChn的回答是,只有在根类中定义的实例方法才能在类对象上执行。你知道这个矛盾吗?谢谢他解释的是我定义的优先级——对象也可以执行类方法。反之亦然,这是我直接从GNUStep源代码和libFoundation测试中提供的。而且,在Objective-C中,类方法也属于实例,但优先级较低,完全错误。因此,您的实例对象实际上是一个类指针。什么也就是说,对象的isa字段是一个类指针,也就是说,如果您有id obj;然后obj->isa是一个类指针;你甚至可以做Class*obj,它是一个类指针;但obj不是类指针。这意味着-respondsToSelector消息也会转到实例类型的类。绝对不是。我想知道NSObject.m代码来自哪里。不知道苹果公司何时开放他们的基础框架。旧新闻,GNUStep和CigaTRON。GNUSTEP是基于Mac OS X基金会之前的OpenSTEP,来自原始NEXSTEP基金会。您是指所有实例方法吗?
s可以在类对象上执行吗?但@ZhangChn的回答是,只有在根类中定义的实例方法才能在类对象上执行。你知道这个矛盾吗?谢谢他解释的是我定义的优先级——对象也可以执行类方法。反之亦然,这是我直接从GNUStep源代码和libFoundation测试中提供的。而且,在Objective-C中,类方法也属于实例,但优先级较低,完全错误。因此,您的实例对象实际上是一个类指针。什么也就是说,对象的isa字段是一个类指针,也就是说,如果您有id obj;然后obj->isa是一个类指针;你甚至可以做Class*obj,它是一个类指针;但obj不是类指针。这意味着-respondsToSelector消息也会转到实例类型的类。绝对不是。