引言
准备:首先搭建好可以跑runtime源码的过程,参考配置运行objc4-750和使用
- 我们试试给category添加属性看看呢?
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
@property(nonatomic,strong)NSString * name;
@end
Animal.m
#import "Animal.h"
@implementation Animal
@end
Animal+category.h
#import "Animal.h"
@interface Animal (category)
@property(nonatomic,strong)NSString*address;
@end
Animal+category.m
#import "Animal+category.h"
@implementation Animal (category)
@end
//此时我们发现系统会提示:
1.Property 'address' requires method 'address' to be defined - use @dynamic or provide a method implementation in this category
2.Property 'address' requires method 'setAddress:' to be defined - use @dynamic or provide a method implementation in this category
使用:main.h
#import <Foundation/Foundation.h>
#import "Animal+category.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
Animal *animal = [[Animal alloc]init];
animal.name = @"啊黄";
animal.address = @"地址"; //直接炸了
NSLog(@"%@",animal.name);
NSLog(@"%@",animal.address);
}
return 0;
}
发现:command+B 编译没有问题,
command+R 运行就炸了
-[Animal setAddress:]: unrecognized selector sent to instance 0x1018159a0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Animal setAddress:]: unrecognized selector sent to instance 0x1018159a0'
--------
至此我们发现:
- 在分类里面添加属性(@property...),编译器只会生成set和get方法的声明,但是没有set和get方法的实现,而不会生成成员变量
- 在分类里面是不能添加成员变量的
- 那怎么办呢?
其实我们可以间接的去为分类添加成员变量的
如下:
Animal+category.h
#import "Animal.h"
@interface Animal (category)
@property(nonatomic,strong)NSString*address;
@property(nonatomic,assign)int age;
@end
Animal+category.m
#import "Animal+category.h"
#import <objc/runtime.h>
@implementation Animal (category)
-(void)setAddress:(NSString *)address{
objc_setAssociatedObject(self, @selector(address), address, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)address{
return objc_getAssociatedObject(self, _cmd); ///_cmd = @selector(address)
}
-(void)setAge:(int)age{
objc_setAssociatedObject(self, @selector(age), @(age), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(int)age{
return [objc_getAssociatedObject(self, _cmd) intValue];
}
@end
使用:
#import <Foundation/Foundation.h>
#import "Animal+category.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
Animal *animal = [[Animal alloc]init];
animal.name = @"啊黄";
animal.address = @"地址";
animal.age = 100;
NSLog(@"%@",animal.name);
NSLog(@"%@",animal.address);
NSLog(@"%d",animal.age);
}
return 0;
}
打印:
05.关联对象[22877:7181963] 啊黄
05.关联对象[22877:7181963] 地址
05.关联对象[22877:7181963] 100
-
可见使用【关联对象】可以添加成员变量的哟
API如下:
添加关联对象 void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) 获得关联对象 id objc_getAssociatedObject(id object, const void *key) 移除所有的关联对象 void objc_removeAssociatedObjects(id object) //文件处于:objc-runtime.mm
-
其中key的使用定义
static void *Mykey= &Mykey;
objc_setAssociatedObject(obj,Mykey,value,OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj,Mykey);
--------
static char Mykey;
objc_setAssociatedObject(obj,&Mykey,value,OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj,&Mykey);
--------
使用属性名作为key
objc_setAssociatedObject(obj,@"property",value,OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj,@"property");
--------
使用get方法的@selector作为key
objc_setAssociatedObject(obj,@selector(getter),value,OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj,@selector(getter));
补充:@selector(name) 返回的是某个结构体的指针(首地址)
- objc_AssociationPolicy的说明
- objc_AssociationPolicy 对应的修饰符
- OBJC_ASSOCIATION_ASSIGN -----> assign
- OBJC_ASSOCIATION_RETAIN_NONATOMIC. ----->strong,nonatomic
- OBJC_ASSOCIATION_COPY_NONATOMIC ----->copy,nonatomic
- OBJC_ASSOCIATION_RETAIN ----->strong,actomic
- OBJC_ASSOCIATION_COPY ----->copy,actomic
-
关联对象的原理(可以点进去见源码)
关联对象_01.jpeg
友情链接:
网友评论