类方法和实例方法,类和元类

假设A类继承自B类,B类继承自NSObject
A便是途中的Subclass(class),B便是图中的Superclass(class),NSObject便是Root class(class);
A *a = [A new];
其实A和a一样,也是对象,A称为类对象,a称为实例对象。
每一个类对象都有一个isa指针,指向元类。
 

我们新建一个NSObject的分类NSObject+Method我们在里面实现两个方法

- (void)sayObject{

  NSLog(@"NSObject===%s",__func__);

}

+ (void)sayClass{

  NSLog(@"NSObject===%s",__func__);

}

新建一个AClass类继承于NSObject,我们直接调用如下代码

int main(int argc, const char * argv[]) {

  @autoreleasepool {

    AClass *p = [AClass alloc];

    [AClass performSelector:@selector(sayClass)];

    [AClass performSelector:@selector(sayObject)];


    NSLog(@"Hello, World!");

  }

  return 0;

}

2021-07-01 11:31:23.567714+0800 KCObjcBuild[70678:3948791] NSObject===+[NSObject(Method) sayClass]

2021-07-01 11:31:23.568099+0800 KCObjcBuild[70678:3948791] NSObject===-[NSObject(Method) sayObject]

可以看出来两个都调用成功了,在oc底层其实没有“+”“-”方法的区分,只是方法存储的位置不同而已。我们具体分析下调用成功的流程:

1、NSObject中sayClass是类方法,在NSObject的元类(Root Class Meta)中存储,AClass调用sayClass方法,会从AClass的元类中找,找不到的话。从元类的父类找(Super Class Meta),继续找根元类(Root Class Meta),此时找到imp,返回。

2、NSObject中sayObject的实例方法,在NSObject的类中存储,AClass调用sayObject,会从AClass的元类中找,找不到的话。从元类的父类找(Super Class Meta),继续找根元类(Root Class Meta),再继续找(Root Class class)找到NSObject,此时找到imp,返回。

我们再进一步,用实例对象p调用看看是怎样的结果

int main(int argc, const char * argv[]) {

  @autoreleasepool {

    AClass *p = [AClass alloc];

    //[p performSelector:@selector(sayClass)];

    [p performSelector:@selector(sayObject)];

    NSLog(@"Hello, World!");

  }

  return 0;

}

我们发现sayObject调用成功了,sayClass直接崩溃,找不到方法

具体分析一下调用流程:

3、sayObject调用成功,我们很好理解。直接AClass继承于NSObject,AClass里面没有实现,直接找到父类的实现。

4、sayClass没有调用成功,我们前面分析过sayClass存在NSObject的元类(Root Class Meta)当中,对象去调用方法的时候,先查找AClass类中查找,此时没有,再往父类(NSObject)中查找,我们发现此时也没有。再找NSObject的父类就是nil了,所以查找不到。因为这个流程并没有查找到NSObject的元类(Root Class Meta)当中去,所以找不到。

总结实例对象可以调用NSObject里面的所有实例方法,但不能调用类方法,类可以掉用NSObject里面的所有方法,包括类方法和实例方法。

原因是类调用方法时,是从类的元类的方法列表里查找,一直往上找到元类的父类,一直到根元类,根元类的isa指向自己,NSObject的isa也指向它,从而找到NSObject的类方法列表,储存在根元类的方法列表中。

根元类的父类指向NSObject,因而找到NSObject方法列表。NSObject的方法列表中存储了NSObject的实例方法。

实例对象调用方法是先在自己的方法列表里找,然后父类,然后父类的父类,直到NSObject。NSObject的方法列表中存储了NSObject的实例方法。从而可以调用NSObject的实例方法。

NSObject的父类指向nil。所以无法找到NSObject的类方法列表,无法调用类方法。

有点绕,但只要看懂了上面的图形指向,就一目了然了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在面向对象编程中,是一种抽象的数据型,描述了具有相似属性和行为的对象集合。中包含了属性和方法方法中定义的一些函数,用于执行特定的操作。 方法实例方法都属于方法,但它们之间存在一些差异。 方法是在级别上定义的方法,即不需要创建实例就可以调用方法使用`@classmethod`装饰器声明,第一个参数是`cls`,代表本身。方法可以访问变量,但不能访问实例变量。 实例方法是在实例级别上定义的方法,即需要创建实例才能调用实例方法使用普通的函数定义方式,第一个参数是`self`,代表实例本身。实例方法可以访问实例变量和变量。 下面是一个示例代码,说明方法实例方法的用法: ```python class MyClass: class_variable = "This is a class variable." @classmethod def class_method(cls): print("This is a class method. The class variable is:", cls.class_variable) def __init__(self, instance_variable): self.instance_variable = instance_variable def instance_method(self): print("This is an instance method. The instance variable is:", self.instance_variable) # 调用方法 MyClass.class_method() # 创建实例调用实例方法 my_instance = MyClass("This is an instance variable.") my_instance.instance_method() ``` 输出结果为: ``` This is a class method. The class variable is: This is a class variable. This is an instance method. The instance variable is: This is an instance variable. ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值