iOS开发之基础篇(12)—— Category(分类)、Ext

2017-11-07  本文已影响38人  看影成痴

版本

Xcode 8.3.2

一、分类

Category这里称分类(另说类别、类目)。
分类的作用:扩展已有类(包括系统类)的功能。比如给NSString增加一个字符串反转的方法。你可能想到了,用继承也可以增加这个功能。那为什么又搞出个分类呢?不妨来对比一下。

1、继承(Inherit) VS 分类(Category)

2、给分类添加方法

步骤:

按图:

1 2 3 4

注意到上图中的+Revers和(Revers),这些是固定格式,表过不提。

接下来贴上开头提到的字符串反转代码:

.h文件

#import <Foundation/Foundation.h>

@interface NSString (Revers)

// 字符串反转方法
-(NSString *)stringByReversString;

@end

.m文件

#import "NSString+Revers.h"

@implementation NSString (Revers)

// 字符串反转方法
-(NSString *)stringByReversString {

    NSUInteger length = [self length];
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:length];

    for(long i=length-1; i>=0; i--){
        unichar c = [self characterAtIndex:i];
        [array addObject:[NSString stringWithFormat:@"%c",c]];
    }

    NSMutableString *str = [NSMutableString stringWithCapacity:length];
    for(int i=0; i<=length-1; i++){
        [str appendString:array[i]];
    }

    return str;
}

@end

main中调用:

#import <Foundation/Foundation.h>
#import "NSString+Revers.h"

int main(int argc, const char * argv[]) {

    NSString *str = @"abcde";
    str = [str stringByReversString];
    NSLog(@"%@",str);

    return 0;
}

输出如下:

3、给分类添加属性

前文提到,分类添加属性,系统只能生成setter和getter方法的声明,不能生成方法的实现,也不会生成带“_”的成员变量。
如果我们仍然想给分类添加可用的属性,那么可以使用Runtime里的运行时关联对象方法来实现属性的setter和getter方法。
关于Runtime的技术原理,请参考这里

实现步骤如下:

#import <Foundation/Foundation.h>

@interface NSString (Revers)

@property (nonatomic, retain) NSNumber *tag;

@end
#import "NSString+Revers.h"
#import <objc/runtime.h>

static char tagKey;    // 用来标记是哪一个属性的key(静态变量地址唯一且不变)

@implementation NSString (Revers)

// tag的setter方法
- (void)setTag:(NSNumber *)tag {

    // 注意第四个参数参数OBJC_ASSOCIATION_RETAIN_NONATOMIC是和属性修饰符对应的
    objc_setAssociatedObject(self, &tagKey, tag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

// tag的getter方法
- (NSNumber *)tag {
    
    return objc_getAssociatedObject(self, &tagKey);
}


@end
    NSString *str = @"abcde";   
    str.tag = @101;
    NSLog(@"tag:%@",str.tag);

注意
Xcode中对objc_setAssociatedObject的定义如下。

objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                         id _Nullable value, objc_AssociationPolicy policy);

第三个参数(即要关联的数据类型)是id数据类型,而id类型是指向对象的指针,所以说,关联对象不能是基本数据类型(如BOOL、NSInteget、long等等)。当我们需要为分类添加基本数据类型的时候,可以先将基本数据类型转化成OC对象,再添加属性。

二、扩展

先来看看:

1 2 3

注意到上图中的_Exs和(),这些是扩展固定格式,是不是感觉和分类有点相似呢?
其实,扩展也叫匿名分类,区别是扩展只有.h文件,而实现是写在被扩展类的.m文件中的。因此,扩展的功能可以认为是被扩展类所私有的,其他类无法使用。
扩展的作用:为类增加私有的属性和方法。一般不用于给系统类添加方法。
因为是私有属性和方法,我们一般不另外生成Extension(扩展)的.h文件,而是将.h文件里的内容(声明)直接写在被扩展类的.m文件里。
例如,我们要扩展一个自定义的Person类,不用另外创建Extension的.h文件,而是在Person的.m文件里加入:

@interface Person () {
    //  添加成员变量
    NSString * _sex;
}
// 添加方法,实现要写在下方的@implementation里
- (void)sayHello;

@end
上一篇 下一篇

猜你喜欢

热点阅读