原来写过一个解释很详细的分类和扩展的博客,感觉不是太直观,但是讲的很详细,今天就以一个简单的小例子来讲解一下。
首先是分类(Category)
它的作用就是为一个已有的类添加新的方法。说白了就是对类的扩展。看一下下面的例子:
首先我们新建一个Person类,该类继承自NSObject:
Person.h
#import <Foundation/Foundation.h> @interface Person : NSObject @end
Person.m
#import "Person.h" @implementation Person @end
我们可以在该类中声明我们需要的属性和方法。然后使用该类。这些都没有问题。但是有个比较奇葩的想法。我想让NSObject有个eat的方法,然后我在Person中去直接使用,就相当于调用了父类的eat方法,而且这个方法还不能在Person中实现。所以就会想到通过分类实现。
我们可以新建一个分类:File-->new-->然后在iOS中选择Objective-C File,然后填写File名称,File Type:(Extension/Protocol/Category/Empty File)。我们选择Category,然后设置Class为NSObject(Person的父类)。这里File名称我定为Category。完成后我们就会看到项目中多了两个我们刚才新建的那两个文件:
NSObject+Category.h和NSobject+Category.m。这就是我们新建的分类文件。看一下他的内容:
NSObject+Category.h:
#import <Foundation/Foundation.h> @interface NSObject (Category) @end
NSobject+Category.m
#import "NSObject+Category.h" @implementation NSObject (Category) @end
然后我们可以对上面的类中添加方法eat,添加过后的代码:
NSObject+Category.h
#import <Foundation/Foundation.h> @interface NSObject (Category) - (void)eat; @end
NSObject+Category.m
#import "NSObject+Category.h" @implementation NSObject (Category) - (void)eat { NSLog(@"调用分类中的文件,然后使劲吃"); } @end
这样一个添加有eat方法的NSObject分类就建好了。该怎么使用呢?看下边:
我们直接在Person.h中导入NSObject+Category.h文件:
#import <Foundation/Foundation.h> #import "NSObject+Category.h" @interface Person : NSObject @end
然后我们就可以在ViewController或者main类中开始使用了:(我是在ViewControlelr中直接使用的)
#import "ViewController.h" #import "Person.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; Person *person = [Person new]; [person eat]; // Do any additional setup after loading the view, typically from a nib. } @end
这样我们实例化的person就有了eat的方法了。
什么?项目中有什么用?
在项目中,举个栗子,在项目中我们可能会去处理时间,比如让时间以指定的格式去显示,这个时候可能项目中有好多地方都需要去使用这个时间处理。我们总不能一个一个都写吧,我们可以新建一个NSDate的分类,然后在里面写一个类方法。这样我们在需要的地方直接去导入该NSDate的分类,然后直接使用就行了。(当然你也可以直接在BaseViewController中或者Global中去定义,都可以)。
看的累么?如果累就继续往下看扩展吧。
什么是扩展勒?刚才你会发现我们用分类给已有的类添加了新的方法,那么你可以不可以在分类中添加新的属性呢?你可以试试。我试了,不行,不行,不行。那怎么办?那就靠扩展了。它可以给已有的类添加属性。那么厉害?对,就是那么厉害?
就那刚才的Person类,我们想定义一个idCard属性,要求不能在Person.h中定义,那么我们可以新建一个NSObject的扩展。怎么建呢?和刚才建分类一样,只不过把File Type改成Extension就行了。建完后会看到这个:
由于我输入的File name是Extenstion所以在项目文件夹里多了一个文件。一个文件?对的,没有错扩展只是生成了一个NSObject_Extension.h文件。.m不知道跑哪里了。添加idCard的扩展如下:
#import <Foundation/Foundation.h> @class NSString; @interface NSObject () @property (nonatomic,copy)NSString *idCard; @end
怎么使用呢?和刚才一样,导入.h即可:
#import "ViewController.h" #import "Person.h" #import "NSObject_Extenstion.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; Person *person = [Person new]; [person eat]; person.idCard = @"1312323423534543"; // Do any additional setup after loading the view, typically from a nib. } @end
这样我们的Person类就有一个属性idCard了。
说了这么多?你应该可以理解把?不理解?看看下边的总结:
----------------------------------------------这里是总结----------------------------------------------
1、分类(Category)是可以给现有的类去添加方法的。但是注意尽量不要去重写该类已有的方法。(我刚才试了一下,直接Crash了,还提示分类正在实现一个该类自身的私有类警告)。反正不管怎么着,尽量不要去重写该类的方法。
2、扩展(Extension)是可以给现有的类添加属性(实例变量)的。
3、你说可以在扩展中添加方法吗?你试试。我试了,不行,再说了,要知道在扩展里添加方法我们去哪里实现呢?.m都没有。。。。
4、你说可以在分类中添加属性吗?你也试试,我试了(添加name)。再分类的.m文件中说name需要name方法定义-使用@dynamic或者提供方法来实现在category中。我定义之后还是直接Crash。说明在分类中添加属性行不通。
----------------------------------------------结束语----------------------------------------------
就这么多吧,如果有什么错误欢迎指正。谢谢。
---------------------------------------------修改----------------------------------------------
1、上面总结的第四条中,分类中是不能添加实例变量,但是可以添加属性。