extension和category(一)
category
OC中使用category匿名类的方式来扩展已经存在类,添加方法、“属性”等,有时候为了代码看起来更加清楚,也可以把一系列相关的方法放在一个匿名类中。
一、category不可以添加实例变量(interface的{}中声明的变量) :instance variables may not be placed in categories
// Student+Image.h #import <Foundation/Foundation.h> #import "Student.h" @class UIImage; @interface Student(Image){ //NSString *urlStr; //instance variables may not be placed in categories } @property (nonatomic) UIImage *avarta; -(void)goHome; @end
二、给category匿名类添加属性。由于在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,所以,category中声明的property并不会被自动生成一个对应的 实例变量,并且需要@dynamic 关键字修饰,表示属性对应的get和set方法由我们自己声明。我们可以通过一下两种方式模拟实现property:
1、objc_setAssociatedObject,设置关联对象。
2、implementation文件中声明一个局部变量,get、set方法操作此变量即可。
// Student+Image.h #import <Foundation/Foundation.h> #import "Student.h" @class UIImage; @interface Student(Image){ //NSString *urlStr; //instance variables may not be placed in categories } @property (nonatomic) UIImage *avarta; -(void)goHome; @end // Student+Image.m #import <UIKit/UIKit.h> #import <objc/runtime.h> #import "Student+Image.h" //@interface Student(Image)(){ // //} // //@end //error @implementation Student(Image) @dynamic avarta; UIImage *avarta_; -(UIImage *)avarta{ UIImage *obj = objc_getAssociatedObject(self, @"_avarta"); if(!obj){ obj = [UIImage imageNamed:@"invoice"]; } return obj; } -(void) setAvarta:(UIImage *)image{ if(image){ objc_setAssociatedObject(self, @"_avatar", image, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } @end // 方法二 -(UIImage *)avarta{ return avarta_; } -(void) setAvarta:(UIImage *)image{ avarta_ = image }
三、category声明属性、方法可以被Student、以及Student的子类访问和继承。当匿名类中声明了与被扩展类中相同的变量时,两个方法会同时存在,方法调用的时候调用最先在方法列表中被找到的那个(有待继续研究)。现在通过对比Student、Student+image、SubStudent的实例变量、属性、方法来研究一下三者的关系。
Student
// Student.h #import <Foundation/Foundation.h> @interface Student : NSObject { @public NSString *sno; } @property (nonatomic, copy,readonly) NSString *name; -(void)goHome; @end // Student.m #import "Student.h" @interface Student(){ @package NSString *cno; } @property (nonatomic, copy) NSString *name; @end @implementation Student -(instancetype)init{ if(self = [super init]){ _name = @"lcy"; sno = @"1"; cno = @"cno"; // [self goHome]; } return self; } -(NSString *)name{ [self goHome]; return _name; } -(void)goHome{ NSLog(@"goHome in Student"); } @end
Student 的实例变量、属性、方法有(sno、cno、_name)(name)(goHome、init、name、setName)
Student+Image
// Student+Image.h #import <Foundation/Foundation.h> #import "Student.h" @class UIImage; @interface Student(Image){ //NSString *urlStr; //instance variables may not be placed in categories } @property (nonatomic) UIImage *avarta; -(void)goHome; @end // Student+Image.m #import <UIKit/UIKit.h> #import <objc/runtime.h> #import "Student+Image.h" //@interface Student(Image)(){ // //} // //@end //error @implementation Student(Image) @dynamic avarta; UIImage *avarta_; -(UIImage *)avarta{ UIImage *obj = objc_getAssociatedObject(self, @"_avarta"); if(!obj){ obj = [UIImage imageNamed:@"invoice"]; } return obj; } -(void)goHome{ NSLog(@"goHome in Student(image)"); } -(void) setAvarta:(UIImage *)image{ if(image){ objc_setAssociatedObject(self, @"_avatar", image, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } @end
Student+Image新增的实例变量、属性、方法有()(avarta)(goHome、setAvarta、avarta)
Student目前拥有的实例变量、属性、方法有(sno、cno、_name)(name、avarta)(goHome、init、name、setName、goHome、setAvarta、avarta) ps:同时存在两个同名方法
SubStudent
// SubStudent.h #import <Foundation/Foundation.h> #import "Student+Image.h" @interface SubStudent: Student -(UIImage *)getImage; @end // SubStudent.m #import "SubStudent.h" @implementation SubStudent -(UIImage *)getImage{ NSString *name = sno; // 子类可引用父类成员变量 return self.avarta; // 可引用image category中生命的property } @end
SubStudent新增的实例变量、属性、方法有()()(getImage)
SubStudent目前拥有的实例变量、属性、方法有(sno、cno、_name)(name、avarta)(goHome、init、name、setName、goHome、setAvarta、avarta、getImage)
ps:再写要崩接下文http://www.cnblogs.com/beautylcy/p/7214373.html