一 . Category分类 Extension 扩展

分类是Objective-C 2.0之后添加的语言特性

它有如下功能:
  • 能够在不改变原来类内容的基础上,为类增加一些方法
  • 将类的实现分开写在几个分类里面
    • 可以把不同的功能组织到不同的Category里,从而减少单个文件的体积
    • 可以由多个开发者共同完成一个类
    • 可以按需加载想要的category
    • 可以声明类的私有方法
    • 可以模拟多继承。
分类使用过程中需要注意的点:
  • 分类只能增加方法,不能增加成员变量。
  • 分类方法实现中可以访问原来类中声明的成员变量。
  • 分类可以实现与原来类中相同的方法,但是这样做会覆盖掉原来的方法,实际上这里的覆盖和覆写类方法的覆盖是有区别的,这里的覆盖不是真正的替换,而是Category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,而运行时在查找方法的时候是顺着方法列表的顺序查找的,只要一找到对应名字的方法,就会停止查找,导致原来类中的方法不会被使用。
  • 当分类、原来类、原来类的父类中有相同方法时,方法调用的优先级:分类(最后参与编译的分类优先) –> 原来类 –> 父类
  • Category是在runtime时候加载,而不是在编译的时候。
  • Category不能添加成员变量因为在运行期,对象的内存布局已经确定,如果添加实例变量会破坏类的内部布局),但是可以结合关联对象来为分类添加属性
  • 可以在类的+load方法调用category中声明的方法,因为添加category到类的工作会先于+load方法的执行,load执行循序是先主类,然后分类,分类的顺序取决于在Build Phases的顺序。

总结来说类别可以添加实例方法,类方法,甚至可以实现协议,添加属性,但是不可以添加实例变量

Extension与Category区别

刚刚开始接触Objective C的时候最容易搞混的就是扩展与分类,最初感觉扩展就是匿名的分类一样,但是后面才知道其实扩展和分类是两码事

  • Extension 扩展
    Extension是类的一部分,它和头文件的@interface和实现文件里的@implement一起形成了一个完整的类。伴随着类的产生而产生,也随着类的消失而消失。
    Extension一般用来放置类的私有变量,必须有一个类的源码才能添加一个类的Extension

  • Category 分类
    是运行期决议的,类扩展可以添加实例变量,分类不能添加实例变量

推荐文章

深入理解Objective-C:Category
objc category的秘密
Objective-C封装技巧(一):Category和继承的博弈
YYCategories
iOS-Category

二. 协议 Protocol

学过Java的同学都知道接口这个概念,在Objective C 中对应的被称为协议也就是Protocol,Protocol只能定义公用的一套接口,但不能提供具体的实现方法。也就是说,它只告诉你要做什么,但具体怎么做,它不关心。

协议的作用很简单就是对某个或者某个系列的对象的行为起约束作用,就像给一个模版,后续只有满足这个模版的对象才能传入。

协议可用定义在单独.h文件中,也可用定义在某个类中:
  • 如果这个协议只用在某个类中,应该把协议定义在该类中
  • 如果这个协议用在很多类中,就应该定义在单独文件中
协议中方法声明的关键字
@required (默认) 要求实现,如果没有实现,会发出警告,但不报错
@optional 不要求实现,不实现也不会有警告
导入协议
@protocol 协议名称    告诉下面代码这是一个协议,但不知道协议里面有什么东西
#import “协议文件名.h” 需要知道协议里面的具体方法的时候需要通过这种方式导入
遵循协议
类遵守协议(这里可以写在外部接口,也可以写在内部扩展部分)
@interface 类名 : 父类名 <协议名称1, 协议名称2>

@end

@interface 类名()<协议名称1, 协议名称2>

@end

协议遵守协议

@protocol 协议名称 <其他协议名称1, 其他协议名称2>

@end
使用协议约束属性或者变量
@property中声明的属性也可用做一个遵守协议的限制
@property (nonatomic, strong) 类名<协议名称> *属性名;
@property (nonatomic, strong) Dog<MyProtocol> *dog;
@property (nonatomic, strong) id<协议名称> 属性名;
@property (nonatomic, strong) id<MyProtocol> dog2;
协议可以声明属性,但是不能添加实例变量

和分类一致的是协议也可以声明属性,但是一般很少这样做,一般协议中都是用于声明方法的,下面是协议声明属性的用法:

@protocol IDLTestProtocol <NSObject>

@property(nonatomic, strong, readwrite) NSString *test;

@end


@interface TestObject : NSObject<IDLTestProtocol>

@end


@implementation TestObject

@synthesize test/* 这个是供类外部使用的名称*/ = _helloWorld/* 这个是供类内部使用的名称*/;

- (instancetype)init {
self = [super init];
if (self) {
_helloWorld = @"linxiaohai";
}
return self;
}

@end

测试代码

TestObject *testObject = [[TestObject alloc] init];
IDLLogError(@"========>%@",testObject.test);

Contents
  1. 1. 一 . Category分类 Extension 扩展
    1. 1.1. 它有如下功能:
    2. 1.2. 分类使用过程中需要注意的点:
    3. 1.3. Extension与Category区别
  2. 2. 推荐文章
  3. 3. 二. 协议 Protocol
    1. 3.1. 协议可用定义在单独.h文件中,也可用定义在某个类中:
    2. 3.2. 协议中方法声明的关键字
    3. 3.3. 导入协议
    4. 3.4. 遵循协议
    5. 3.5. 使用协议约束属性或者变量
    6. 3.6. 协议可以声明属性,但是不能添加实例变量