2-3 iOS 分类(Category)& 类扩展(Extension)

     分类(Category):

        分类是OC中的一个特有语法,它表示一个指向分类结构体的指针。一般情况下,我们只能添加给分类增加方法,而不能增加实例变量(成员变量)。

      分类的格式:

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

@implementation 待扩展的类(分类的名称)
@end

      分类的使用场景:

        我们知道,给一个A类添加方法,简单粗暴的方式就是直接在A类在.h中声明,.m中实现该方法。但是这样做,有时候不便于项目的管理和移植,试想,如果一个类有杂七杂八几十个不同的方法糅合在一个.h中。要是以后我们想要调用其中某一个方法,还得把整个移植过来,或者把方法扣出来。这多恼火。
     苹果为了解决这些问题,特地引入了分类这个概念。我们可以专门用一个文件夹管理这些分类。比如UIImage文件夹下面,UIImage+GIF,UIImage+Cache。。。等等。很直观,也更便于项目的管理与移植。

      为分类添加属性:

        直接给分类添加@property,编译器只会给你警告。但是如果你调用这个属性,就会报错。这是为什么呢?
        首先,我们来看看分类的源码组成,源码位于objc/runtime.h中。
        
struct objc_category {
    char * _Nonnull category_name                            OBJC2_UNAVAILABLE; //分类名称
    char * _Nonnull class_name                               OBJC2_UNAVAILABLE; //要扩展的类名
    struct objc_method_list * _Nullable instance_methods     OBJC2_UNAVAILABLE; //实例方法列表
    struct objc_method_list * _Nullable class_methods        OBJC2_UNAVAILABLE; //类方法列表
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE; //分类实现的协议
}
        我们发现,分类所指向的结构体中根本就没有属性列表。所以,就算是你强行用@property,编译器也不会给你自动生成setter/getter方法,也不会生成私有成员变量。
         但是,有些情况下,我们在给分类添加的方法中,如果有属性存在的话,会便利很多。比如,我想给一个UIButton类扩大点击区域,需要上下左右四个可变数值,用属性的话要便利很多。但如何去给分类添加属性呢?
         如果研究过runtime相关的代码,相信你肯定知道关联对象这一说法。如果你暂时还不了解,可以看看我之前的一篇博文 runtime动态关联对象,在此我就只简单描述一下。
          
定义静态变量,用其地址作为关联对象的key
#import <objc/runtime.h>
@implementation UIButton (EnlargeTouchArea)


static char topNameKey;
static char rightNameKey;
static char bottomNameKey;
static char leftNameKey;
设置关联对象
- (void)addIncreaseTapAreaWithTop:(CGFloat)top buttom:(CGFloat)buttom left:(CGFloat)left right:(CGFloat)right {

    objc_setAssociatedObject(self, &kTopNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kRightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kButtomNameKey, [NSNumber numberWithFloat:buttom], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kLeftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);

}

获取关联对象

    NSNumber *top = objc_getAssociatedObject(self, &kTopNameKey);
    NSNumber *right = objc_getAssociatedObject(self, &kRightNameKey);
    NSNumber *buttom = objc_getAssociatedObject(self, &kButtomNameKey);
    NSNumber *left = objc_getAssociatedObject(self, &kLeftNameKey);

以上,就是如何动态为分类添加属性。



     类扩展(Extension):

        类扩展其实也是分类的一种,我们应该说是时时刻刻都在打交道。类扩展和分类的区别就在于有没有分类的名称,以及类扩展是编译期属性,分类属于运行时属性。

      类扩展的实现:

@interface ExtionsionClass
@property (nonatomic,copy) NSString *name;
- (void)eat;
@end
        使用类扩展注意两点:
    1.一般类扩展写在依托的对应类的.m中,私有属性写到扩展中。

    2.类扩展中方法的实现,需要在依托的对应类的.m中实现(区别于分类,没有@implementation部分)。如果没有实现已经声明了的方法,编译器会报警(区别于分类,分类这种情况不会报警告。这就是我说的编译期和运行时的差别)。


    这两种如何合理使用,看各人的爱好以及对应业务的处理吧。





        


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值