• 关联引用


    关联引用同意开发人员为不论什么对象附着键值数据

    这样的能力有非常多使用方法,一种常见的使用方法是:

    1)让分类为属性加入方法。

    考虑 Person 类这个样例。如果你要用分类加入一个新属性,叫做 emailAddress。可能其它程序也用到了 Person,有时候须要电子邮箱地址。有时候不须要,分类就是非常好的解决方式,能够避免在不须要的时候开销。或者 Person 不是你的,而维护者没有为你加入这个属性。无论哪种情况,你要怎么解决问题呢?

    首先,这里有一个主要的 Person 类:

    @interface Person : NSObject
    @property(nonatomic, readwrite, copy) NSString *name;
    @end
    
    @implementation Person
    @end
    如今在分类中关联引用加入一个新属性 emailAddress 。

    #import <objc/runtime.h>
    @interface Person(EmailAddress)
    @property(nonatomic, readwrite, copy) NSString *emailAddress;
    @end
    
    
    @implementation Person(EmailAddress)
    static char emailAddressKey;
    
    -(NSString *)emailAddress {
        return objc_getAssociatedObject(self, &emailAddressKey);
    }
    
    -(void)setEmailAddress:(NSString *)emailAddress {
        objc_setAssociatedObject(self, &emailAddressKey, emailAddress, OBJC_ASSOCIATION_COPY);
    }
    
    @end
    注意,关联引用基于键的内存地址,而不是值的。emailAddressKey 中存在着什么并不重要,仅仅要是唯一的不变的地址就能够了。这也是通常会用未赋值的 static char 变量作为键的原因。



    2)关联引用有良好的内存管理,能依据传递给 objc_setAssociatedObject 的參数正确的处理 copy、assign 和 retain 等语义。当相关对象被销毁时关联引用会被释放。这个事实意味着能够用关联引用来追踪还有一个对象何时被销毁

    比方:

    const char kWatcherKey;
    @interface WatcherKey : NSObject
    @end
    
    #import <objc/runtime.h>
    @implementation WatcherKey
    -(void)dealloc {
        NSLog(@"HEY! The thing I was watching is going away!");
    }
    @end
    
    ......
    NSObject *something = [NSObject new];
    objc_setAssociatedObject(something, &kWatcherKey, [Watcher new], OBJC_ASSOCIATION_RETAIN)
    这样的技术对调试非常实用,只是也能够用做非调试目的,比方运行清理工作。

    3)关联引用是给警告框或者控件附着相关对象的好办法。

    比方说,你能够给警告框附着一个“表示对象”。例如以下代码所看到的:

    #import <objc/runtime.h>
    
    @implementation ViewController
    
    static const char kRepresentedObject;
    
    - (IBAction)doSomething:(id)sender {
      UIAlertView *alert = [[UIAlertView alloc]
                            initWithTitle:@"Alert" message:nil
                            delegate:self
                            cancelButtonTitle:@"OK"
                            otherButtonTitles:nil];
      objc_setAssociatedObject(alert, &kRepresentedObject, 
                               sender,
                               OBJC_ASSOCIATION_RETAIN_NONATOMIC);
      [alert show];
      
    }
    
    
    如今,假设警告框被关闭了,你就可能知道原因了。

    - (void)alertView:(UIAlertView *)alertView 
    clickedButtonAtIndex:(NSInteger)buttonIndex {
      UIButton *sender = objc_getAssociatedObject(alertView, 
                                                  &kRepresentedObject);
      self.buttonLabel.text = [[sender titleLabel] text];
    }
    非常多程序用调用者的实力变量处理这样的任务。可是关联引用清晰非常多。也简单非常多。对熟悉 Mac 开发的人来说,这段代码类似于 representedObject ,可是更加灵活。

    最后。说一下关联引用的局限(或者其它不论什么通过分类加入数据的方法)是无法集成 encodeWithCoder: ,所以非常难通过分类序列化对象。


    拓展阅读:

    全局返回手势 FDFullscreenPopGesture ,里面就是用了关联引用,同一时候也能够学到 OC 的一些黑魔法,Nice ~

  • 相关阅读:
    Makefile:(实验)多个目标匹配时会采用最完整匹配的目标
    线程调度为什么比进程调度更少开销?
    关于makefile中自动产生依赖的理解
    makefile中重载与取消隐藏规则示例
    xargs命令的使用过程中一个小领悟:管道与xargs的差别
    CODING 远程办公 开工不断线
    【 ECUG 演讲分享】吴海黎:CODING 微服务架构演进之路
    张海龙:云时代企业研发人员需求与人才培养
    腾讯云大学 x CODING | DevOps 实战:Jenkins Docker
    腾讯云大学 x CODING | 敏捷开发与 DevOps 实战
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6875764.html
Copyright © 2020-2023  润新知