• Effective Objective-C 2.0 — 第10条:在既有类中使用关联对象存放自定义数据


    • 可以通过“关联对象”机制来把两个对象连起来
    • 定义关联对象时可指定内存管理语义,用以模仿定义属性时所采用的“拥有关系”与“非拥有关系”
    • 只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的 bug

    目的:需要在对象中存放相关信息,方法一,从对象所属的类中继承一个子类,然后改用这个子类对象。

      方法二:关联对象(Associated Object),对象通过“键”来区分。

    可以把某对象想象成NSDictionary,把关联到对象上调用[object setObject:value forKey:key] 与 [object objectForKey:key]方法。但是设置关联对象那个时用的键(key)是个“不透明的指针“(opaque pointer),

    如果在两个键上调用”isEqual“方法返回值是 YES, 那么NSDictionary就认为两者相等;然而设置关联对象时,二者必须是完全相同的指针才行。鉴于此,在设置关联对象值时,通常使用静态全局变量做键。

     下列方法管理关联对象:

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

      此方法以给定的键和策略为某对象设置关联对象值

       id objc_getAssociatedObject(id object, void*key)

       此方法根据给定的键从某对象中获取相应的关联对象值

      void objc_removeAssociatedObjects(id object)

      此方法移除指定对象的全部关联对象

    例子:UIAlertView 类,警告信息,当用户按下按钮关闭该视图时,需要用委托协议(delegate protocol)在处理此动作,但是要想设置好这个委托机制,就得把创建警告视图和处理按钮动作的代码分开。比兔使用UIAlertView 时,一般都会这么写:

    - (void)askUserAQuestion {
        UIAlertView *alert = [[UIAlertView alloc]  initWithTitle:@"Question"
                                                                 message:@"What do you want to do?"
                                                                 delegate:self
                                                                 cancelButtonTitle:@"Cancel"
                                                                 otherButtonTiles:@"Continue",nil];
                [alert show];
    }
    // UIAlertViewDelegate protocol method
    - (void)alertView:(UIAlertView *)alertView
                clickedButtonAtIndex:(NSInteger)buttonIndex
    {
        if (buttoIndex == 0) {
               [self doCancel];
        } else {
                [self doContinue];
        }
    }

     如果想在同一个类里处理多个警告信息视图,那么代码就会变得更为复杂,必须在delegate方法中检查传入的 alertView 参数

    可以使用关联对象 在创建警告视图的时候直接把处理每个按钮的逻辑都写好:创建完警告视图之后,设定一个与之关联的“块” block,等到执行 delegate 方法是再将其读出来,代码如下

    #import <objc/runtime.h>
    static void *EOCMyAlertViewKey = "EOCMyAlertViewKey";  
    - (void)askUserAQuestion { 
           UIAlertView *alert = [[UIAlertViewalloc] 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_setAssociateObject(alert, EOCMyAlertViewKey, block, BJC_ASSOCIATION_COPY);
            [alert show];
    }
    // UIAlertViewDelegate protocol method 关联类型等效的@property 属性为
    - (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
        void (^block) (NSInteger) = objc_getAssociateObject(alertView, EOCMyAlertViewKey);
        block(buttonIndex);
    }                                       

    注意:块可能要捕获 (capture)某些变量,这也许会造成“保留环)(retain cycle)

  • 相关阅读:
    [Tutorial] How to check and kill running processes in Ubuntu
    [Tutorial] Getting started with Gazebo in ROS
    Linux基础命令
    Linux安装系统
    vue 前后端数据交互问题解决
    如何在cmd中启动MongoDB服务器和客户端
    selenuim模块的使用 解析库
    beautifhulsoup4的使用
    浅谈scrapy框架安装使用
    自动登录 点赞 评论 抽屉网
  • 原文地址:https://www.cnblogs.com/IDRI/p/5120639.html
Copyright © 2020-2023  润新知