category
使用场景
1.为已经存在的类添加方法。
2.可以把类的实现放到不同的文件中。
3.声明私有方法。
表现形式
#import "ClassName.h"
@interface ClassName (CategoryName)
//method declarations
@end
使用注意
category的使用
声明:
@interface NSString(Add)
- (NSString *)Add:(NSString*)string;
@end
实现:
@implementation NSString(Add)
- (NSString *)Add:(NSString*)string
{
return [self stringByAppendingString:string];
}
@end
调用:
NSString *testString = @"Hello";
testString = [testString Add:@"World!"];
NSLog(@"%@", testString);
输出:
2015-11-04 20:22:14.000 TestIphone[9986:238906] HelloWorld!
因为category是在运行时决定的,所以其可以在没有类源码的情况下添加category,这也就导致了其不能不能添加实例变量。如果category想要访问类的任何实例变量,则必须导入其所扩展类的接口文件。当类别中的方法与原有类中的方法名冲突是,类别的方法将取而代之(置于方法链表的前面)。当category中出现方法名与原有类方法重名时,category的方法被加入的方法列表的前面,而原来的类方法则处于新方法列表的后面。这就造成了我们所见的category方法覆盖了原有类的同名方法。主要是因为运行时查找方法的时候是沿着方法列表顺序查找的,只要找到对应的方法即返回。
也正因为category是运行时决定的,所以可以通过runtime机制添加实例变量。主要API为:
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
id objc_getAssociatedObject(id object, const void *key)
使用示例:
声明:
@interface NSString(Add)
@property (nonatomic, strong)NSString *myNameString;
- (NSString *)Add:(NSString*)string;
@end
实现:
#import "objc/runtime.h"
static const char *myNameString = "myNameString";
@implementation NSString(Add)
- (NSString *)Add:(NSString*)string
{
return [self stringByAppendingString:string];
}
// get方法
- (NSString *)myNameString {
return (NSString *)objc_getAssociatedObject(self, myNameString);
}
// set方法
- (void)setMyNameString:(NSString *)nameString {
objc_setAssociatedObject(self, myNameString, nameString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
调用:
NSString *testName = [[NSString alloc] init];
testName.myNameString = @"zhanyawei";
NSLog(@"%@", testName.myNameString);
输出:
2015-11-04 20:31:58.496 TestIphone[10008:242495] zhanyawei
extension
使用场景
1.隐藏类的私有信息。
表现形式
#import "ClassName.h"
@interface ClassName ()
//method declarations
@end
使用注意
常用于声明公有的只读属性和私有的读写属性。
比如:
@interface MyClass : NSObject
@property (retain, readonly) float value;
@end
// 私有的extension, 隐藏在主实现文件中.
@interface MyClass ()
@property (retain, readwrite) float value;
@end
extension和category行驶时看起来差不多,但是其行为却差别很大。extension在编译期和原有的类一起编译成一个完整的类,其与原有的类‘同生共死’。所以定义extension需要原有类的源码,也可以定义实例变量。