iOS中Category类别基本介绍和使用

一、Categories

类别是一种为现有的类添加新方法的方式,利用Objective-C的动态运行时分配机制,可以为现有的类添加新方法,它可以为任何类添加新的方法,包括那些没有源代码的类。在创建类别时,会生成.h和.m两个文件

一、声明类别

声明类别与声明类的形式很相似

@interface NSString(NumberConvenience) 
-(NSNumber *)lengthAsNumber; 
@end//NumberConvenience 
二、实现类别
@implementation NSString(NumberConvenience) 
-(NSNumber *)lengthAsNumber 
{ 
unsigned int length = [self length]; 
return ([NSNumber numberWithUnsignedInt : length]); 
} //lengthAsNumber 
@end //NumberConvenience 
三、类别的局限性

(1)**Categories只能添加方法,不能添加实例变量(**categories为运行期决议,此时对象内存布局已定)
(2)名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。

四、类别的作用

(1)将类的实现分散到多个不同文件或多个不同框架中。
(2)创建对私有方法的前向引用。
(3)将应该视为“私有”的方法归入peivate分类中,隐藏实现细节。

下面我们分别实践一下类别的作用

1、将类的实现分散到多个不同文件或多个不同框架中。
在一个类的实现中,我们可以将类的接口放入.h文件中,将类的实现放入.m文件中,但不可以将@implementation分散到多个不同的.m文件中,但利用类别,可以将一个类在@implementation方法按照方法的功能拆分到不同的类别中,使编程人员更加容易的阅读头文件
举例代码:
头文件CatagoryThing.h包含类的声明和一些类别,导入Foundation框架,然后带有3个整型变量的声明

# import

@interface CategoryThing : NSObject { 
int thing1; 
int thing2; 
int thing3; 
} 
@end 

//类声明之后是3个类别,每个类别具有一个实例变量的访问器,将这些实现分散到不同的文件中 
@interface CategoryThing(Thing1) 
- (void) setThing1: (int) thing1; 
- (int) thing1; 
@end 

@interface CategoryThing (Thing2) 
- (void) setThing2: (int) thing2; 
- (int) thing2; 
@end

@interface CategoryThing (Thing3) 
- (void) setThing3: (int) thing3; 
- (int) thing3; 
@end

2、使用类别创建前向引用
如果其他类中的方法未实现,在你访问其他类的私有方法时编译器报错,这时使用类别,在类别中声明这些方法(不必提供方法实现),编译器就不会再产生警告

向类别中添加属性

(3)必须在类别中添加实例变量时怎么办?
方法一:
iOS中协议中和分类中是可以用@property形式声明属性的,只不过在协议、分类中声明的属性,只有对应的setter/getter方法,并没有生成对应的成员变量。因为协议中只可以声明方法,分类中只能声明方法和对应的实现。

Protocol

@protocol MyProtocol

@property (nonatomic, strong)NSString *protocolName;

@end

@interface ViewController :UIViewController

@end

如果一个类遵守这个协议的话,在该类中即可调用出self.protocolName,但是如果直接调用self.protocolName = @“就是个这个鬼”;

self.protocolName = @“这是个什么鬼啊”;

NSLog(@"%@",self.protocolName);

项目会直接出现崩溃

Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: '-[ViewController setProtocolName:]: unrecognized selector sent to instance 0x7f9fb350aa20’

实现方法1:

这是由于在协议当中的属性只有对应的setter/getter,但是没有成员变量,如果直接直接将其get方法写出如下:

- (NSString*)protocolName

{

return @“这个是个什么鬼”;

}

这样调用的话,就能够直接调用

NSLog(@"%@",self.protocolName);
输出结果为:
2018-04-10 15:30:36.373180+0800 这个是个什么鬼

实现方法2:

使用**@synthesize**告诉编译器需要生成对应的getter/setter方法以及实例变量

@interface ViewController ()

@end

@implementation ViewController

@synthesize protocolName =_protocolName;

使用@synthesize protocolName =_protocolName,编译器为 _protocolName 成员变量合成访问器方法,访问器方法操作的就是_protocolName这个变量。

self.protocolName = @“啊啊啊”;
NSLog(@"%@",self.protocolName);
2018-04-10 15:30:36.373180+0800****啊啊啊

实现方法3:

利用runtime黑魔法,通过runtime.h中objc_getAssociatedObject / objc_setAssociatedObject来访问和生成关联对象。这两个方法可以让一个对象和另一个对象关联,就是说一个对象可以保持对另一个对象的引用,并获取那个对象。

//NSObject+IndieBandName.h
@interface NSObject (IndieBandName)
@property (nonatomic, strong) NSString *indieBandName;
@end

//上面是头文件声明,下面的实现的.m文件:
// NSObject+IndieBandName.m 
#import "NSObject+Extension.h"
#import <objc/runtime.h>
static const void *IndieBandNameKey = &IndieBandNameKey; 
@implementation NSObject (IndieBandName)
@dynamic indieBandName;
- (NSString *)indieBandName 
{ 
return objc_getAssociatedObject(self, IndieBandNameKey);
}

- (void)setIndieBandName:(NSString *)indieBandName 
{ 
objc_setAssociatedObject(self, IndieBandNameKey, indieBandName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

其他可以阅读下面两篇文章
美团技术团的一篇博文
转自:http://www.2cto.com/kf/201502/376993.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的修养

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值