美文网首页iOS
(四)关联对象

(四)关联对象

作者: dandelionYD | 来源:发表于2019-03-12 16:53 被阅读22次

    引言

    准备:首先搭建好可以跑runtime源码的过程,参考配置运行objc4-750和使用

    gitHub_Demo

    • 我们试试给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
    关联对象_02.jpeg

    友情链接:

    相关文章

      网友评论

        本文标题:(四)关联对象

        本文链接:https://www.haomeiwen.com/subject/fymnpqtx.html