关联引用

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

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

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 ~

时间: 2024-10-13 17:39:11

关联引用的相关文章

浅析关联引用

背景 今日吃饱了,确实撑得慌,找了我的邻居-阿杰一起散步,走了好大一圈,最后在小区下聊起了技术,从YYKit,SDWebImage 等第三方库,扯到了关联引用,因为他们都用到了这个技术,然而我又想到了单例,单例和关联引用在实现上有一个相同点-都需要一个静态变量:那么疑问就来了:同样都需要一个静态变量,为什么结果不一样呢?或许你还没明白我的疑问是什么,请继续阅读吧! 一.回顾单例 我简单的写了个单例类 SingletonObject ,把静态变量 instance 放在 sharedInstanc

iOS Rumtime 之关联引用

关联引用: 允许开发者为任何对象附着键值数据, 很常用的用法是为分类添加属性. 节目预告 1. 简单的关联引用 2. 为UIViewController 添加MBProgressHUD的HUB属性 3. 为UINavigationBar添加一个view属性 来完成动态改变UINavigationBar的外观 官方API是这样的, 下面这篇博客也是围绕这些来展开 // 关联策略枚举值 typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) { OB

分类添加属性之关联引用

分类是不能合成属性的,因为合成属性会生成对应的实例变量,而分类是不允许添加实例变量的(实例变量所在内存区域已初始化为不可更改,无法在动态运行时修改之). 虽然不能增加实例变量,但是添加属性还是可以的,只不过需要自己在分类中实现get和set方法,同时标记属性为动态获取. 其中一种方法叫做关联引用,实现了用存取器来访问属性,当然实际上并没有实例变量,所以本质上只不过是增加了两个方法而已. 首先在.h中声明属性: #import <UIKit/UIKit.h> @interface UIViewC

Unity Inspector 给组件自动关联引用(二)

通过声明的变量名称,主动关联引用. 使用这个关联引用两种方式1.  给你组件继承  MonoAutoQuote 点击组件inspector 按钮执行2.  给你组件类添加[AAutoQuote] 特性  通过Plateface/SetSelectGameRef 执行 [AAutoQuote] public class MonoAutoQuote : MonoBehaviour ,IAutoQuote{} public interface IAutoQuote { } public class A

iOS关联对象

Associated Objects(关联对象)或者叫作关联引用(Associative References),是作为Objective-C 2.0 运行时功能被引入到 Mac OS X 10.6 Snow Leopard(及iOS4)系统.与它相关在<objc/runtime.h>中有3个C函数,它们可以让对象在运行时关联任何值: OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value,

gcc/g++ 编译时出现:“对’xxxx’未定义的引用,collect2: error: ld returned 1 exit status” 的错误

出现的问题: 在使用 make 编译实现一个程序时,出现了下面的错误.查看程序源文件所在的目录时发现程序已经完成了编译,并生成了 list_repo.o 的文件,说明是在程序链接生成可执行文件时发生了问题. storages/local.o:在函数‘LocalStorage::init(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >,

Associated Objects(关联对象)

#import <objc/runtime.h> Objective-C开发者应该小心谨慎地遵循这个危险咒语的各种准则.一个很好的原因的就是:混乱的运行时代码会改变运行在其架构之上的所有代码. 从利的角度来讲, <objc/runtime.h> 中的函数具有其他方式做不到的.能为应用和框架提供强大功能的能力.而从弊的角度来讲,它可能会会毁掉代码的sanity meter,一切代码和逻辑都可能被异常糟糕的副作用影响(terrifying side-effects). 因此,我们怀着巨

以引用对象代替单例模式

介绍: 系统中存在单例的全局訪问点,你希望将对单例的訪问通过对象引用来实现.往往是将对单例的依赖关系转换为关联关系. 动机: 在系统中引入单例模式往往并没有起到明显的效果却添加了系统的复杂性.不能只由于某个类只须要一个实例而採用单例模式.这些全然能够用引用对象代替. 通过全局訪问点使用单例对象往往造成依赖不清.可读性差等问题,我们全然能够通过显式的关联引用来做到在子系统中共享同一个实例,而且仅仅对须要这个实例的对象注入依赖.将对全局变量的依赖转变为对成员对象的依赖使类更易于理解. 当设计须要中不

UML中关联(Association)和依赖(Dependency)的区别

原文转自:http://blog.csdn.net/metasearch/article/details/2334853 在UMLCHINA精华区,看到了一些关联和依赖的讨论,似乎越讲越糊涂.我想谈一点自己的看法: 1.在<UML参考手册>第37页中,指出“关联和泛化都是依赖关系,但是它们有更特别的语义,故它们有自己的名字和详细的语义.我们通常用依赖这个词来指其他的关系.” 2.在<UML参考手册>30页中,定义了关联为“关联描述了系统中对象或实例之间的离散连接.最普通的关联是一对