iOS 分类(Category)
2019-04-09 本文已影响26人
飞不越疯人院
1:日常开发中用分类做哪些工作?
- 声明调用Framework或者类的私有方法;
例如
Cat
类有一个私有方法
-(void)privateEat:(NSString *)somthing
;
在viewDidLoad
方法中想要使用Cat的这个方法;
Cat* d = [[Cat alloc] init];
[d privateEat:@"Fish"];
这样不能编译通过, 但是我们给Cat
添加一个分类, 并且在分类.h中声明这个方法, 就可以正常调用这个方法了;示例代码
- 为体积庞大的类减负;
例如我们的工程中在LaunchVC中有很多逻辑处理(不讨论合理不合理), 其中路由部分有上千行代码, 这时采用Category方式将路由部分剥离开来很好的增加可读性;
Category的.h文件
Category的.m文件
在LaunchVC的合适地方调用
- 添加非正式协议;示例代码
2: 分类的特点?
- 运行时生效: 编写好分类后并没有立即将分类添加到相应的类中, 在运行时通过
runtime
将分类内容绑定到相应的类中; - 为系统类添加分类; 例如对
UIView
添加分类用self.x
直接获取到x
坐标; - 多个分类有同名方法时, 最后编译的分类的方法会被实现(覆盖前面的);
- 分类添加的方法可以"覆盖"宿主类方法;
- 名字相同的分类会引起编译报错;
3: 分类中可以添加哪些内容?
- 添加实例方法;
- 添加类方法;
- 添加(非正式)协议;
- 添加属性; 实际上是只声明了
setter
和getter
, 并没有添加成员变量
;
4: 能不能为分类添加成员变量?
可以添加; 不能在分类声明和定义实现的过程中添加成员变量; 但是可以通过关联对象的方式添加;通过这种方式添加的成员变量没有添加到元数组中; 所有不同的类添加的关联对象被放到了一个统一的全局容器中(AssociationsHashMap
);
@property
属性 = 成员变量+ getter
+ setter
; 通过对象关联方式,添加属性进而实现添加成员变量(能不能调用?如何调用?)
关联对象所用到方法:
const void *NameKey = nil;
- (void)setName:(NSString *)name {
/**
objc_setAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>, <#id _Nullable value#>, <#objc_AssociationPolicy policy#>)
把value通过key, 用policy这种策略关联给object;
*/
objc_setAssociatedObject(self, NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
/**
objc_getAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>)
根据指定key从objectz中获取对应关联值;
*/
return objc_getAssociatedObject(self, NameKey);
}
/**
objc_removeAssociatedObjects(<#id _Nonnull object#>)
移除obeject的所有关联对象
*/
5: 附加: 成员变量, 属性, 实例变量区别
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Cat : NSObject {
///成员变量
NSString *color;
NSInteger age;
}
///属性
@property (nonatomic, copy) NSString *kind;
@end
NS_ASSUME_NONNULL_END
声明在大括号内是成员变量, 下面的property
修饰的是属性; 实例变量本质上就是成员变量, 实例变量是相对于类的概念;
成员变量 | 属性 |
---|---|
不会自动生成setter和getter, 需要自己手动实现 | 自动生成setter和getter方法 |
外部不能用"." 语法, 要用"->"
|
外部可以使用"." 语法(本质上是setter 和getter ) |
默认是@protected 修饰 |
默认是@protected 修饰(外部并不能直接访问这个成员变量, 而是需要通过getter 和setter ) |
成员变量外部不能用
"."
语法调用, 需要用"->"
方式
成员变量的默认修饰为@protected
, 如果外部想调用需要手动修改为@public
; 如图:
示例代码下载
有理解错误的地方,请指正;