美文网首页程序员iOS学习开发iOS Developer
深入category的高级使用及解惑

深入category的高级使用及解惑

作者: CoderDancer | 来源:发表于2017-07-26 16:44 被阅读427次

category的高级使用

1. 分类为什么会覆盖掉类的同名方法,对应的类方法是不存在了么?
2. 怎么解除分类对类方法的覆盖?
3.category怎么关联对象的?
4.多个category,哪个方法优先执行?

Category是在Objective-C 2.0时提供的新的语言特性,其原因简单,不管类设计的多么完美,总有无法预测的状况,Category就是作为一种方式来扩展类的。

关于基础部分,网上很多相关文档可供查阅,此文不赘述。
作者只做分类的底层及高级用法作使用说明。

1. 分类为什么会覆盖掉类的同名方法,对应的类方法是不存在了么?

1. category的方法没有“完全替换掉”原来类已经有的方法,也就是说如果category和原来类都有methodA,那么category附加完成之后,类的方法列表里会有两个methodA
2. category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,这也就是我们平常所说的category的方法会“覆盖”掉原来类的同名方法,这是因为运行时在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会罢休^_^,殊不知后面可能还有一样名字的方法。

2. 怎么解除分类对类方法的覆盖?

/*
怎么调用到原来类中被category覆盖掉的方法?
对于这个问题,我们已经知道category其实并不是完全替换掉原来类的同名方法,只是category在方法列表的前面而已,所以我们只要顺着方法列表找到最后一个对应名字的方法,就可以调用原来类的方法:
*/
+ (void)useClassMethodInsteadCayegoryMethod: (SEL)seletor {
    
    if (self) {
        unsigned int methodCount;
        Method *methodList = class_copyMethodList([self class], &methodCount);
        IMP lastImp = NULL;
        SEL lastSel = NULL;
        for (NSInteger i = 0; i < methodCount; i++) {
            Method method = methodList[i];
            NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))
                                                      encoding:NSUTF8StringEncoding];
            NSString *selectorName = NSStringFromSelector(seletor);
            if ([selectorName isEqualToString:methodName]) {
                lastImp = method_getImplementation(method);
                lastSel = method_getName(method);
            }
        }
        typedef void (*fn)(id,SEL);
        
        if (lastImp != NULL) {
            fn f = (fn)lastImp;
            f(self,lastSel);
        }
        free(methodList);
    }
}

3.category怎么关联对象的?

#import <Foundation/Foundation.h>
#import "LearnCategoryClass.h"

@interface LearnCategoryClass (Addition)

@property(nonatomic, strong) NSString *newName;



#import "LearnCategoryClass+Addition.h"
#import <objc/runtime.h>

@implementation LearnCategoryClass (Addition)

- (void)testCategory {
    NSLog(@"分类里是%@,方法名是%s",[self class], __PRETTY_FUNCTION__);
}

//运行时动态添加set和get方法(Xcode9 更新了提醒功能,超级牛逼。比如此处在分类里声明了属性,但不添加set/get方法会warnning,这里说下,厉害了我的苹果)
- (void)setNewName:(NSString *)newName
{
    objc_setAssociatedObject(self,
                             "newName",
                             newName,
                             OBJC_ASSOCIATION_COPY);
}

- (NSString*)newName
{
    NSString *nameObject = objc_getAssociatedObject(self, "newName");
    return nameObject;
}
@end

4.多个category,哪个方法优先执行?

好吧,这其实不是一个问题,是一串问题。
可以分为:

  1. category里的方法是什么时候注册到Class的method_list的,在+load阶段么?
  1. 如果有多个category,怎么办?

我们知道,在类class和category中都可以有+load方法,那么有两个问题:

  1. 在class的+load方法调用的时候,我们可以调用category中声明的方法么?
  1. 这么多个+load方法,调用顺序是咋样的呢?

答案是

  1. 可以调用,而且附加category到类的工作会先于+load方法的执行;
  2. +load的执行顺序是先class,后category,而category的+load执行顺序是根据编译顺序决定的。

可以这么理解方法的调用。
有一个类似有压栈入栈的栈结构,先把class里的methodA添加到methodList中,然后添加分类中的方法,编译器会从上到下找分类,先找到的分类就先放入methodList中,后找到的就后放入。
所以最终形成了一个Class里的方法在最底层,最后编译的分类在最上层的栈结构。
而方法的调用是从上到下执行的,冉调用对应的方法,就会从methodList里找对应的SEL,找到就停止,所以Class和前面便轻易的分类虽然都在methodList里,但因为找到了就不会继续查找。
以上就是方法掉用顺序的原理。
当然,编译顺序可以在 Build Phases里的Compile Source里修改。

奇葩问答:

  • 如果在分类里声明了,但不实现,method_list里不会有,当然也不会调用分类方法。但若是实现了,即使不在.h文件声明,也会调用分类的方法;
  • 如果分类里是- (void)testCategory,而Class里是- (int)testCategory;返回值不同,也会覆盖,因为虽然返回值不同,但OC里,这两者依然是一个方法。
  • 对于多个分类,方法的调用是执行最后编译的分类方法;

文末

关于category及其OC的深入研究,请转移到Github—>OCDeepLearning
欢迎star和issues参与讨论。

之于category的更底层实现,可以参照:参考文章

相关文章

  • 深入category的高级使用及解惑

    category的高级使用 1. 分类为什么会覆盖掉类的同名方法,对应的类方法是不存在了么?2. 怎么解除分类对类...

  • Category and Extension

    目录 Category category的背景和概念 category的声明及实现 category的使用 cat...

  • OC--Category、AssociatedObject

    Category原理、作用深入理解Objective-C:Category (OC1.0)结合 category ...

  • 类别的高级玩法(Category)

    Category的简单介绍 作用及使用场景 Category的主要作用是为已经存在的类添加方法(包括实例方法和类方...

  • iOS Category详解

    Extension详解,及与Category的区别 1、什么是Category? category是Objecti...

  • Category VS Extension 原理详解

    Category VS Extension 原理详解 深入理解Objective-C:Category 一: ca...

  • iOS Category的使用及原理

      Category是我们在开发中经常用到的,它可以在我们不改变原有类的前提下来动态地给类添加方法,通过这篇文章,...

  • Category底层原理

    一 Category基本使用 二 Category的底层结构三 Category的加载处理流程四 Category...

  • 5.分类Category

    参考:深入理解Objective-C:Category 1. 简介 category是Objective-C 2....

  • Category深入解读

    引入 众所周知,面向对象的编程语言的基础是类,方法是依赖于类存在的,类是结构和功能的基本单位。编程的主要方面就是增...

网友评论

    本文标题:深入category的高级使用及解惑

    本文链接:https://www.haomeiwen.com/subject/dldokxtx.html