分享

Objective-C 编程语言官网文档(七)-关联引用

 现在决定明天 2015-10-20

声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正

尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有注意该语言的专有词,希望指正。如需转载,请注明出处


我的编程环境:

IDE:XCODE4.3.1

OS: MAC OS X 10.7.4

文章来译自:http://developer.apple.com/

关联引用

Associative references, 暂且称之为关联引用,从Mac OS X v10.6 开始可用, 模拟已经存在的类的额外对象实例。通过使用关联引用,你可以为一个对象增加存储空间而不必修改类的声明。当你无法访问类的源码或者由于二进制兼容问题你无法修改对象布局时,关联引用将会很有用。

关联是建立在键的基础上的。对于任何对象你都可以添加任意多的关联,每一个都使用不同的键。一个关联还可以确保关联的对象在源对象声明周期内都保持有效。

创建关联

使用 Objective-C 的运行时函数 objc_setAssociatedObject 可以创建一个对象跟另外一个对象的关联。这个函数有4个参数:源对象, 键, 值以及一个关联原则常量。其中,键跟关联原则将深入探讨下:

  • 键是一个 void 指针。每个关联的键必须都是唯一的。通常的形式是使用一个 static 变量。

  • 原则定义了是否关联的对象是 assigned, retained, or copied以及是否关联是自动完成的。形式类似与属性的额外属性 (可以参考 “Property Declaration Attributes”). 你可以使用一个常量来为关系指定原则(可以参考 objc_AssociationPolicy 和 Associative Object Behaviors).

 6-1 展示了如何为一个数组跟字符串建立关联

 6-1  

static char overviewKey;
 
NSArray *array =
    [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];
// For the purposes of illustration, use initWithFormat: to ensure
// the string can be deallocated
NSString *overview =
    [[NSString alloc] initWithFormat:@"%@", @"First three numbers"];
 
objc_setAssociatedObject (
    array,
    &overviewKey,
    overview,
    OBJC_ASSOCIATION_RETAIN
);
 
[overview release];
// (1) overview valid
[array release];
// (2) overview invalid

在(1)处, overview 字符串仍然是有效可用的,因为 OBJC_ASSOCIATION_RETAIN 原则指定了数组将保持这个相关的对象。当数组也被释放后,(2)的位置,overview 就也被释放了,此时所有的都将释放。要是你还试图去使用 overview,就会报运行时异常。

获取关联的对象

通过使用 Objective-C 的运行时函数 objc_getAssociatedObject可用获得一个关联对象。让我们继续 6-1 中的例子,你可以通过下面的代码从 array 中获取到overview

NSString *associatedObject =
    (NSString *)objc_getAssociatedObject(array, &overviewKey);

断开关联

要断开关联,你可以调用 objc_setAssociatedObject, 传一个 nil。 

继续使用 6-1的例子,你可以使用下面的代码断开array跟overview 字符串的关联:

objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);

关联的对象被设置为了 nil, 至于原则项这里都不重要。

要断开一个对象的所有关联,你可以调用 objc_removeAssociatedObjects通常来说,不应该使用这个方法,因为它会对所有的客户断开所有关联。只有当你想把一个对象重置到初始化状态时再使用这个方法。

完整的例子

下面是本节完整的例子

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
 
int main (int argc, const char * argv[]) {
 
    @autoreleasepool {
        static char overviewKey;
 
        NSArray *array = [[NSArray alloc]
            initWithObjects:@ "One", @"Two", @"Three", nil];
        // For the purposes of illustration, use initWithFormat: to ensure
        // we get a deallocatable string
        NSString *overview = [[NSString alloc]
            initWithFormat:@"%@", @"First three numbers"];
 
        objc_setAssociatedObject (
            array,
            &overviewKey,
            overview,
            OBJC_ASSOCIATION_RETAIN
        );
        [overview release];
 
        NSString *associatedObject =
            (NSString *) objc_getAssociatedObject (array, &overviewKey);
        NSLog(@"associatedObject: %@", associatedObject);
 
        objc_setAssociatedObject (
            array,
            &overviewKey,
            nil,
            OBJC_ASSOCIATION_ASSIGN
        );
        [array release];
 
    }
    return 0;
}

英文原文:点击打开链接


Associative References

Associative references, available starting in Mac OS X v10.6, simulate the addition of object instance variables to an existing class. Using associative references, you can add storage to an object without modifying the class declaration. This may be useful if you do not have access to the source code for the class, or if for binary-compatibility reasons you cannot alter the layout of the object.

Associations are based on a key. For any object you can add as many associations as you want, each using a different key. An association can also ensure that the associated object remains valid for at least the lifetime of the source object.

Creating Associations

You use the Objective-C runtime function objc_setAssociatedObject to make an association between one object and another. The function takes four parameters: the source object, a key, the value, and an association policy constant. Of these, the key and the association policy merit further discussion.

  • The key is a void pointer. The key for each association must be unique. A typical pattern is to use a staticvariable.

  • The policy specifies whether the associated object is assigned, retained, or copied, and whether the association is be made atomically or non-atomically. This pattern is similar to that of the attributes of a declared property (see “Property Declaration Attributes”). You specify the policy for the relationship using a constant (seeobjc_AssociationPolicy and Associative Object Behaviors).

Listing 6-1 shows how you can establish an association between an array and a string.

Listing 6-1  Establishing an association between an array and a string

static char overviewKey;
 
NSArray *array =
    [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];
// For the purposes of illustration, use initWithFormat: to ensure
// the string can be deallocated
NSString *overview =
    [[NSString alloc] initWithFormat:@"%@", @"First three numbers"];
 
objc_setAssociatedObject (
    array,
    &overviewKey,
    overview,
    OBJC_ASSOCIATION_RETAIN
);
 
[overview release];
// (1) overview valid
[array release];
// (2) overview invalid

At point 1, the string overview is still valid because the OBJC_ASSOCIATION_RETAIN policy specifies that the array retains the associated object. When the array is deallocated, however (at point 2), overview is released and so in this case also deallocated. If you try to, for example, log the value of overview, you generate a runtime exception.

Retrieving Associated Objects

You retrieve an associated object using the Objective-C runtime function objc_getAssociatedObject. Continuing the example shown in Listing 6-1, you could retrieve the overview from the array using the following line of code:

NSString *associatedObject =
    (NSString *)objc_getAssociatedObject(array, &overviewKey);

Breaking Associations

To break an association, you typically call objc_setAssociatedObject, passing nil as the value.

Continuing the example shown in Listing 6-1, you could break the association between the array and the stringoverview using the following line of code:

objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);

Given that the associated object is being set to nil, the policy isn’t actually important.

To break all associations for an object, you can call objc_removeAssociatedObjects. In general, however, you are discouraged from using this function because it breaks all associations for all clients. Use this function only if you need to restore an object to “pristine condition.”

Complete Example

The following program combines code from the preceding sections.

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
 
int main (int argc, const char * argv[]) {
 
    @autoreleasepool {
        static char overviewKey;
 
        NSArray *array = [[NSArray alloc]
            initWithObjects:@ "One", @"Two", @"Three", nil];
        // For the purposes of illustration, use initWithFormat: to ensure
        // we get a deallocatable string
        NSString *overview = [[NSString alloc]
            initWithFormat:@"%@", @"First three numbers"];
 
        objc_setAssociatedObject (
            array,
            &overviewKey,
            overview,
            OBJC_ASSOCIATION_RETAIN
        );
        [overview release];
 
        NSString *associatedObject =
            (NSString *) objc_getAssociatedObject (array, &overviewKey);
        NSLog(@"associatedObject: %@", associatedObject);
 
        objc_setAssociatedObject (
            array,
            &overviewKey,
            nil,
            OBJC_ASSOCIATION_ASSIGN
        );
        [array release];
 
    }
    return 0;
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多