• Objective-C——关联对象


    动态语言

    OC是一种动态语言,它的方法,对象的类型都是到运行的时候才能够确定的。所以这就使得OC存在了关联对象这一强大的机制。

    关联对象

    所谓关联对象,其实就是我们在运行时对一个已存在的对象上面绑定一个对象,使两个对象变成动态的聚合关系。

    关联对象和属性一样有着关键字,以下是关联对象的存储策略:

    关联类型 等效的@property属性
    OBJC_ASSOCIATION_ASSIGN assign
    OBJC_ASSOCIATION_RETAIN_NONATOMIC nonatomic,retain
    OBJC_ASSOCIATION_COPY_NONATOMIC nonatomic,copy
    OBJC_ASSOCIATION_RETAIN retain
    OBJC_ASSOCIATION_COPY copy

    关联对象主要靠下面三个函数,它们都位于<objc/runtime>下

    void objc_setAssociatedObject(id object, void *key ,id value ,objc_AssociationPolicy policy)

    设置关联对象

    参数 说明
    object 要进行关联的对象
    key 一个内存表示,在比较两个关联对象是否相等时,比较的就是内存地址,所以一般用一个全局静态变量表示
    value 被关联的对象
    policy 存储策略

    id objc_getAssociatedObject(id object, void *key)

    获取关联对象

    void objc_removeAssociatedObjects(id object)

    删除关联对象

    作用

    关联对象一般用于动态的扩展一个对象,但是这一般都是在其他方法不行的事后才会使用,因为关联对象很可能会出现难以查找的bug。

    关联对象有时也会用于在category向类添加属性,这点等会儿在分析。

    下面Demo在UIAlertView上面动态绑定了一个block,把按钮处理逻辑和alert调用整合在了一起。

    static char *AlertKey = "alertKey";
    
    - (void)viewDidLoad {
        [super viewDidLoad];
       
        alert = [[UIAlertView alloc] initWithTitle:@"alert" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil];
    }
    
    - (IBAction)click:(id)sender {
        
        void (^block) (NSInteger) = ^(NSInteger buttonIndex){
            if (buttonIndex == 0){
                NSLog(@"click cancel");
            }
            else{
                NSLog(@"click other");
            }
        };
        objc_setAssociatedObject(alert, AlertKey, block, OBJC_ASSOCIATION_COPY);
        [alert show];
    }
    
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
        void (^block)(NSInteger) = objc_getAssociatedObject(alertView, AlertKey);
        block(buttonIndex);
    }

    运行程序点击两个按钮分别输出如下

    2015-08-11 22:51:27.146 Dynamic[4592:2833778] click other
    2015-08-11 22:51:28.262 Dynamic[4592:2833778] click cancel

    接下来我们给UIViewController在category中添加一个addition属性

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface UIViewController (Addition)
    
    @property(nonatomic ,copy) NSString *addition;
    
    @end
    #import "UIViewController+Addition.h"
    
    static const void *IndieBandNameKey = &IndieBandNameKey;
    
    @implementation UIViewController (Addition)
    
    -(void)setAddition:(NSString *)addition{
        objc_setAssociatedObject(self, IndieBandNameKey, addition, OBJC_ASSOCIATION_COPY);
    }
    
    -(NSString *)addition{
        return objc_getAssociatedObject(self, IndieBandNameKey);
    }
    
    @end

    这里说明一下,这里关联的实际上是形参addition,和属性没有什么关系,写@property 就是为了能够使用‘.’语法。但是@porperty里面的属性存储策略还是要和关联对象一致的,这样不容易造成误解。

    所以每次setAddition实际上我们并不是修改了原有内存的值,而是改变了指针指向的地址,这里需要注意一下。

    然后修改刚才alert的代码

    - (void)viewDidLoad {
        [super viewDidLoad];
       
        alert = [[UIAlertView alloc] initWithTitle:@"alert" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil];
        alert.delegate = self;
        self.addition = @"addition";
        
    }
    
    - (IBAction)click:(id)sender {
        
        void (^block) (NSInteger) = ^(NSInteger buttonIndex){
            if (buttonIndex == 0){
                NSLog(@"click cancel");
                objc_removeAssociatedObjects(self);
            }
            else{
                NSLog(@"click other");
                NSLog(@"%@",self.addition);
            }
        };
        objc_setAssociatedObject(alert, AlertKey, block, OBJC_ASSOCIATION_COPY);
        [alert show];
    }
    
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
        void (^block)(NSInteger) = objc_getAssociatedObject(alertView, AlertKey);
        block(buttonIndex);
    }

    注意三条加粗的语句,然后我们运行看结果

    2015-08-11 22:53:54.353 Dynamic[4655:2849502] click other
    2015-08-11 22:53:54.353 Dynamic[4655:2849502] addition
    2015-08-11 22:53:55.804 Dynamic[4655:2849502] click cancel
    2015-08-11 22:53:57.491 Dynamic[4655:2849502] click other
    2015-08-11 22:53:57.491 Dynamic[4655:2849502] (null)

    首先我们使用了关联对象,所以点击other的时候会看到打印出了addition。点击cancel的时候又因为我们remove了关联对象,此时再点击other的时候addition就变成null了。

  • 相关阅读:
    从零到一k8s(五)网络模型讲解(cilium,calico,flannel)
    从零到一k8s(六)集群管理深入
    从零到一k8s(九)devops&&cicd
    1kvm理论
    类和方法
    方法定义和调用
    2kvm安装
    Redis6.2.6源码CLion编译调试
    ubuntu16.04 nginx创建自签名SSL证书
    MySQL性能优化之参数配置
  • 原文地址:https://www.cnblogs.com/madpanda/p/4722602.html
Copyright © 2020-2023  润新知