编写高质量代码的52个有效方法

52个有效方法(24) - 将类的实现代码分散到便于管理的数个分

2018-09-05  本文已影响17人  SkyMing一C
分类(Category)

分类(Category)是OC中的特有语法,它是表示一个指向分类的结构体的指针。原则上它只能增加方法,不能增加成员(实例)变量。其定义如下:

typedef struct objc_category *Category;
struct objc_category {
  char *category_name                          OBJC2_UNAVAILABLE; // 分类名
  char *class_name                             OBJC2_UNAVAILABLE; // 分类所属的类名
  struct objc_method_list *instance_methods    OBJC2_UNAVAILABLE; // 实例方法列表
  struct objc_method_list *class_methods       OBJC2_UNAVAILABLE; // 类方法列表
  struct objc_protocol_list *protocols         OBJC2_UNAVAILABLE; // 分类所实现的协议列表
}
  1. 分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。所以< 原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过objc/runtime添加属性 > 。

  2. 分类中的可以写@property, 但不会生成setter/getter方法, 也不会生成实现以及私有的成员变量(编译时会报警告)。

  3. 可以在分类中访问原有类中.h中的属性。

  4. 如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法。所以同名方法调用的优先级为 分类 --> 本类 --> 父类。因此在开发中尽量不要覆盖原有类。

  5. 如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。

分类格式
@interface 待扩展的类(分类的名称)
@end

@implementation 待扩展的名称(分类的名称)
@end
//.h
#import <Foundation/Foundation.h>

@interface EOCPerson : NSObject<NSCopying>
@property (nonatomic,copy) NSString *name;
@property (nonatomic,readonly) NSArray *friends;
@property (nonatomic,assign) int age;
@end

@interface EOCPerson (FriendShip)
- (void)addFriend:(EOCPerson *)person;
- (void)removeFriend:(EOCPerson *)person;
@end

@interface EOCPerson (Play)
- (void)playPingPong;
- (void)playFootball;
- (void)sing;
- (void)run;
@end
//.m
#import "EOCPerson.h"
@interface EOCPerson ()
@property (nonatomic,readwrite,strong) NSMutableArray *friends;
@end
@implementation EOCPerson
- (instancetype)initWithName:(NSString *)name age:(int)age
{
    self = [super init];
    if (self) {
        self.name = name;
        self.age = age;
        _friends = [NSMutableArray array];
    }
    return self;
}

- (NSArray *)friends{
    return [_friends copy];
}

- (id)copyWithZone:(NSZone *)zone{
    EOCPerson *p = [[[self class] allocWithZone:zone] initWithName:_name age:_age];
    p->_friends = [_friends mutableCopy];
    return p;
}
@end

@implementation EOCPerson (FriendShip)
- (void)addFriend:(EOCPerson *)person{
    if(person){
        [_friends addObject:person];
    }
}
- (void)removeFriend:(EOCPerson *)person{
    if(person){
        [_friends removeObject:person];
    }
}
@end
@implementation EOCPerson (Play)
- (void)playPingPong {
}
- (void)playFootball {
}
- (void)sing{
}
- (void)run{
}
- (void)eat{
}
@end
分类优点
私有的方法
给分类添加属性
@interface NSObject (EOC_CX)
/**
 *  为每一个对象添加一个name属性
 */
@property (nonatomic,copy) NSString *name;
/**
 *  为每个对象添加一个View属性
 */
@property (nonatomic,strong) UIView *booksView;
/**
 *   为每个对象添加一个是否被选中属性
 */
@property(nonatomic, assign) BOOL isSelected;

@end
#import "NSObject + EOC_CX .h"
#import <objc/runtime.h>
// 使用对象关联需引入#import <objc/runtime.h>头文件
@implementation NSObject (EOC_CX)
// 用一个字节来存储key值,设置为静态私有变量,避免外界修改
static void *nameKey;
- (void)setName:(NSString *)name
{
    // 将某个值与某个对象关联起来,将某个值存储到某个对象中
    objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
     return objc_getAssociatedObject(self, &nameKey);
}
static void *booksViewKey;
- (void)setBooksView:(UIView *) booksView
{
    objc_setAssociatedObject(self, &booksViewKey, booksView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIView *) booksView
{
    return objc_getAssociatedObject(self, &booksViewKey);
}
//将bool类型转变成NSNumber类型来进行添加属性 这样储存策略为OBJC_ASSOCIATION_COPY_NONATOMIC
static void *isSelectedKey;
- (void)setIsSelected:(BOOL)isSelected {
    objc_setAssociatedObject(self, &isSelectedKey, @(isSelected), OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (BOOL)isSelected {
    return [((NSNumber *) objc_getAssociatedObject(self, &isSelectedKey)) boolValue];
}
@end
#import "NSObject + EOC_CX .h"
#import <objc/runtime.h>
// 使用对象关联需引入#import <objc/runtime.h>头文件
@implementation NSObject (EOC_CX)
- (void)setName:(NSString *)name
{
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
     return objc_getAssociatedObject(self, _cmd);
    //_cmd 代替了 &nameKey 或者 @selector(name).
}
- (void)setBooksView:(UIView *)booksView
{
    objc_setAssociatedObject(self, @selector(booksView), booksView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIView *) booksView
{
    return objc_getAssociatedObject(self, _cmd);
    //_cmd 代替了 &booksKey 或者 @selector(booksView).
}
//将bool类型转变成NSNumber类型来进行添加属性 这样储存策略为OBJC_ASSOCIATION_COPY_NONATOMIC
- (void)setIsSelected:(BOOL)isSelected {
    objc_setAssociatedObject(self, @selector(isSelected), @(isSelected), OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (BOOL)isSelected {
    return [objc_getAssociatedObject(self, _cmd) boolValue];
    //_cmd 代替了 &isSelectedKey 或者 @selector(isSelected).
}
@end
要点
  1. 使用分类机制把类的实现代码划分成易于管理的小块。

  2. 将应该视为“私有”的方法归入名叫private的分类中,以隐藏实现细节。

上一篇 下一篇

猜你喜欢

热点阅读