专栏首页我是做APP开发的OC基础Category和Extension区别

OC基础Category和Extension区别

Category 和 Extension介绍

Category
  • 可以给当前已知的类添加方法(类方法和实例方法),这个类可以是自定义的类,也可以是系统自带的类。当添加的方法和类的原有方法重名时,会‘覆盖’类的原有方法.

原类的方法还是存在的,并不是真的给覆盖了。因为在运行时当给对象发消息,会根据对象的‘isa’指针找到所属的类,然后在类的方法列表中根据方法名寻找,当找到第一个就返回了,而通过category添加的方法又在方法列表的最上面所以没有机会找到类原来方法`。

  • 可以通过property添加属性,但也只是对属性的set、get方法声明,没有实现,也不能生成带下划线的变量。
  • 不能添加成员变量。注意,通过runtime 关联对象添加的不叫属性,也不叫成员变量,它和当前类没有根本上的关系,只是仅仅的连在了一起。
Extension
  • 可以给一个已知的类添加方法(类方法和实例方法),这个类只能是自定义的类,不可以是系统自带的类,因为不能得到.m文件。由于在已知的类.m 中操作所以可以对外界隐藏一些方法或变量,使其成为私有。
  • 可以添加属性和成员变量,也可以为属性生成set、get方法和默认的实现。通过extension添加的方法和变量真的成为了当前类的一部分。

不同之处

eg:分别给自定义的User类添加Category,Extension

//Category
@interface User (InnterAdd)
-(void)test;
@end
@implementation User (InnterAdd)

-(void)test
{
    NSLog(@":%s",__func__);
}

@end

//Extension
@interface User ()

@property (copy)NSString * addr;

@end

表现形式上,Category有名称,有自己的.m文件,extension没有名称看起来像个匿名的分类,没有.m文件。 Category也可以没有名称,这样两者在表现上就一样了。

Category: 是在运行时加载处理的,这个过程中把添加的方法添加到类的方法列表中,由于类的内存结构布局是在编译时期确定的,所以在运行时不能再添加实例变量否则就破坏了内存结构(访问非法内存地址存在不可预知的错误,所以是禁止的)。那为啥能添加方法而不能添加成员变量呢?在runtime层,category用结构体category_t(在objc-runtime-new.h中可以找到此定义)如下:

typedef struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
} category_t;

从中可看出可以添加实例方法,类方法,甚至可以实现协议,添加属性。没有表示实例变量的存贮。

其实分类本身而言它就不是一个类,分类,分开类的一部分操作,就是一个在运行时给主类添加方法、属性、或者协议的操作或者对外提供的一种接口扩展,在分类中添加方法直接绑定到主类原有的方法列表。所以感觉把分类这个名字改为方法扩展更容易理解(o)/~,所以在这一点来看,Category和Extension在目的上还是一致的,都是对原有的类增加新的操作。

Extension:在编译时处理的,添加的变量和方法和类密切的在一起,就是类的一部分,类消失它也消失。

Category中关联对象

runtime提供了以下三个方法

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
objc_getAssociatedObject(id object, const void *key)
void objc_removeAssociatedObjects(id object)

其中objc_removeAssociatedObjects 移除已添加的所有对象,所以实际操作要注意别把其他地方添加的关联也给remove了。所以还是通过objc_setAssociatedObject 直接置为nil更为可靠。

#END

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Swift3项目升级到Swift5

    源项目 https://www.jianshu.com/p/3228bfa3be7d 曾经Swift3写的,业余更新造成年久失修。

    Light413
  • Flutter-初试牛刀,入门篇

    好像说的就是我呀。学习Flutter一段时间了,我感觉我要入门了,特来总结一下遇到的点点滴滴。如下效果就是我用Flutter重写的曾经项目部分效果,说是部分其实...

    Light413
  • iOS APNs的几个问题

    2、iOS从APNS Server获取device token,应用程序接收device token。

    Light413
  • Oracle云数据库初体验 之一 - 申请与介绍

    关于Oracle云数据库(Oracle Cloud Database)的一些体验和分享,也可以参考以下链接:

    数据和云01
  • 侠盗猎车手GTA5单机版

    《侠盗猎车手5》(Grand Theft Auto V)又名“给他爱5”,是由Rockstar Games游戏公司出版发行的一款围绕犯罪为主题的开放式动作冒险游...

    叮当叮
  • 干货 | 想在手机上用自己的ML模型?谷歌模型压缩包你满意

    谷歌在 Google AI 上撰文进行对刚刚发布的 ML Kit 中的核心技术:Learn2Compress 自动模型压缩技术进行了详细介绍和实战测试。

    AI科技评论
  • 想在手机上用自己的 ML 模型?谷歌模型压缩包你满意

    AI 研习社按: Google I/O 2018 上,谷歌发布了可供开发者定制移动端机器学习模型的 ML Kit 开发套件,关于该套件中的核心技术:Learn2...

    AI研习社
  • iOS runtime(实践篇)

    大壮
  • 使用 husky 和 lint-staged 来构建你的前端工作流

    ESLint 是一个在前端工具链中被众人熟知的代码检查工具,它能够被开发者灵活的配置,使其能够达到我们提前制定好的代码规范的要求,并且在编码过程中实时检测输入的...

    Originalee
  • Xcode 恢复初始状态

    我想问题可以是出在最新的 Xcode 11.2.1 版本上,我先下载一个 Xcode 10.3 版本看看能不能运行。

    iOSDevLog

扫码关注云+社区

领取腾讯云代金券