Effective Objective-C 2.0: Associated Objects

原创 2013年12月03日 14:51:05

例子有点少, 内存管理方面不清楚~~, 


Item 10: Use Associated Objects to Attach Custom Data to Existing Classes

Sometimes, you want to associate information with an object. Normally, you would do this by subclassing the object’s class and use that instead. However, you can’t always do this, since instances of the class might be created for you by some means and you cannot tell it to create instances of your class instead. That’s where the powerful Objective-C feature called Associated Objects comes in handy.

Objects are associated with other objects, using a key to identify them. They are also designated a storage policy to govern memory-management semantics of the stored value. The storage policies are defined by the enumeration objc_AssociationPolicy, which contains the values shown in Table 2.1 against the @propertyattribute for the equivalent if the association were a property (seeItem 6 for further information on properties).

Table 2.1 Object Association Types

Image

Management of associations is performed using the following methods:

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

Sets up an association of object to value with the given key and policy.

Image id objc_getAssociatedObject(id object, void *key)

Retrieves the value for the association on object with the given key.

Image void objc_removeAssociatedObjects(id object)

Removes all associations against object.

The accessing of associated objects is functionally similar to imagining that the object is an NSDictionary and calling [object setObject:value forKey:key] and [object objectForKey:key]. An important difference to note, though, is that key is treated purely as an opaque pointer. Whereas with a dictionary, keys are regarded equal if they return YES for isEqual:, the key for associated objects must be the exact same pointer for them to matchFor this reason, it is common to use static global variables for the keys.

An Example of Using Associated Objects

In iOS development, it’s common to use the UIAlertView class, which provides a standard view for showing an alert to the user. There’s a delegate protocol to handle when the user taps a button to close it; however, using delegation splits up the code of creation of the alert and handling the tap. This makes it slightly awkward to read, as the code is split between two places. Here is an example of what using a UIAlertView would look like normally:

- (void)askUserAQuestion {
    UIAlertView *alert = [[UIAlertView alloc]
                             initWithTitle:@"Question"
                               message:@"What do you want to do?"
                                 delegate:self
                        cancelButtonTitle:@"Cancel"
                        otherButtonTitles:@"Continue"nil];
      [alert show];
}

// UIAlertViewDelegate protocol method
- (void)alertView:(UIAlertView *)alertView
        clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 0) {
        [self doCancel];
    } else {
        [self doContinue];
    }
}

This pattern gets even more complicated if you ever want to present more than one alert in the same class, since you then have to checkthe alertView parameter passed into the delegate method and switch based on that. It would be much simpler if the logic for what to do when each button is tapped could be decided when the alert is created. This is where an associated object can be used. A solution is to set a block against an alert when it is created and then read that block out when the delegate method is run. Implementing it would look like this:

#import <objc/runtime.h>

static void *EOCMyAlertViewKey = "EOCMyAlertViewKey";

- (void)askUserAQuestion {
    UIAlertView *alert = [[UIAlertView alloc]
                             initWithTitle:@"Question"
                               message:@"What do you want to do?"
                                  delegate:self
                        cancelButtonTitle:@"Cancel"
                        otherButtonTitles:@"Continue"nil];

      void (^block)(NSInteger) = ^(NSInteger buttonIndex){
        if (buttonIndex == 0) {
            [self doCancel];
        } else {
            [self doContinue];
        }
    };

      objc_setAssociatedObject(alert,
                               EOCMyAlertViewKey,
                               block,
                               OBJC_ASSOCIATION_COPY);

      [alert show];
}

// UIAlertViewDelegate protocol method
- (void)alertView:(UIAlertView*)alertView
        clickedButtonAtIndex:(NSInteger)buttonIndex
{
    void (^block)(NSInteger) =
        objc_getAssociatedObject(alertView, EOCMyAlertViewKey);
    block(buttonIndex);
}

With this approach, the code for creating the alert and handling the result is all in one place, making it more readable than before, as you don’t have to flick between two portions of code to understand why the alert view is being used. You would, however, need to be careful with this approach, as retain cycles could easily be introduced if the block captured. See Item 40 for more information on this problem.

As you can see, this approach is very powerful, but it should be used only when there’s no other way of achieving what you need to do. Widespread use of this approach could get out of hand very quickly and make debugging difficult. Retain cycles become harder to reason, since there is no formal definition of the relationship between the associated objects, as the memory-management semantics are defined at association time rather than in an interface definition. So proceed with caution when using this approach, and do not use it purely because you can. An alternative way of achieving the same with UIAlertView would be to subclass it and add a property to store the block. I would suggest this approach over associated objects if thealert view were to be used more than once.

Things to Remember

Image Associated objects provide a means of linking two objects together.

Image The memory-management semantics of associated objects can be defined to mimic owning or nonowning relationships.

Image Associated objects should be used only when another approach is not possible, since they can easily introduce hard-to-find bugs.

编写高质量的iOS代码--Effective Objective-C 2.0 读书笔记

编写高质量的iOS代码--Effective Objective-C 2.0 读书笔记 这本书年初刷完,感觉不错,介绍了很多小点,都是平日不怎么关注的. 第1章 熟悉Objective-C...
  • uxyheaven
  • uxyheaven
  • 2014年12月26日 23:56
  • 5054

Effective Objective-C 2.0 读书笔记

第 1 章 熟悉 Objective-C 第 2 章 对象消息运行时 第 3 章 接口和 API 设计 第 4 章 协议与分类 第 5 章 内存管理 循环引用 普通的两个变量互相引用 Block 循环...
  • xsl_bj
  • xsl_bj
  • 2016年06月06日 12:27
  • 4769

【Effective Objective-C 2.0读书笔记】第三章:接口和API设计

一旦你完成了一个应用,你可能会希望在以后的工程中重用部分代码。你也可能会发布一些代码以供其他人来使用。这意味着你需要使用Objective-C的范式和理解众多的陷阱。...
  • freeWayWalker
  • freeWayWalker
  • 2015年07月06日 15:23
  • 594

iOS-Effective Objective-C 2.0 读书笔记(三)

第三章的内容主要是说接口和API设计相关的注意事项。比如说我们自己写的代码需要设计以便于代码复用时,应该注意的一些问题包括哪些。简单总结  有些注意事项实际上很简单,而且很常见,我觉得并不需要太长篇幅...
  • linyousong
  • linyousong
  • 2016年04月29日 22:31
  • 415

阅读《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》总结

第1条:了解Objective-C语言的起源 Objective-C为C语言添加了面向对象特性,是其超集。Objective-C使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型。接收一...
  • caojengineer
  • caojengineer
  • 2015年06月07日 22:52
  • 1187

《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》读书笔记(下)

1.为避免在不经意间使用了无效对象,一般在release之后会清空指针,=nil; 2.通常利用弱引用或者“手动”解除引用的方式破坏循环引用。 3.ARC下,规定以alloc、new、copy、mut...
  • zhaochen_009
  • zhaochen_009
  • 2017年04月06日 10:44
  • 327

《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》--读书笔记

个人觉得这本书很不错!里面有很多很实用但以前没有太注意的地方,所以想纪录下来,当作自己的读书笔记吧。 熟悉Objective-C 1)Objective-C语言使用“消息结构”而不是“函数调用”。O...
  • weimeng809
  • weimeng809
  • 2016年01月11日 00:18
  • 585

《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》读书笔记(上)

1.OC对象所占内存总是分配在"堆"中,而绝不会分配在"栈"中,不能再栈中分配OC对象。"栈"中对象借助栈帧进行维护,"堆"中对象的管理借助引用计数机制. -(NSMutableArray *)te...
  • zhaochen_009
  • zhaochen_009
  • 2017年04月05日 10:10
  • 292

《Effective Objective-C 2.0:编写高质量iOS与OS X代码的52个有效方法》 笔记1

NSString *someString = @"The string";   NSString *anotherString = someString;  描述了此时的内存布局。存放在N...
  • ssyyjj88
  • ssyyjj88
  • 2016年04月13日 14:51
  • 190

Objective-C Associated Objects 的实现原理

我们知道,在 Objective-C 中可以通过 Category 给一个现有的类添加属性,但是却不能添加实例变量,这似乎成为了 Objective-C 的一个明显短板。然而值得庆幸的是,我们可以通过...
  • jinglijun
  • jinglijun
  • 2015年07月08日 15:01
  • 1721
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effective Objective-C 2.0: Associated Objects
举报原因:
原因补充:

(最多只允许输入30个字)