美文网首页
Obj-C的已有类中,添加关联对象存放自定义数据

Obj-C的已有类中,添加关联对象存放自定义数据

作者: 奔跑吧小二 | 来源:发表于2016-12-02 12:02 被阅读15次

    全文引自
    《Effective Objective-C 2.0 编写高质量iOS与OS X代码发的52个有效方法》,旨在为大家提供一点思路。Github 笔记

    涉及到的方法

    objc_setAssociatedObject
    objc_getAssociatedObject

    有时需要在对象中存储相关信息,这时我们通常会从对象所属的类中继承一个子类,然后改用这个子类对象。然而,并非所有情况都能这么做,有时候类的实例可能是由某种机制所创建的,而开发者无法令这种机制创建出自己所写的子类实例。Objective-C中有一项强大的特性可以解决此问题,这就是『关联对象 Associated Object』。

    可以给某对象关联许多其他对象,这些对象通过『键』来区分。存储对象值的时候,可以指明『存储策略 storage policy』,用以维护相应的"内存管理语义"。存储策略由名为objc-AssociationPolicy的枚举所定定义,包括下面的值,同事累出了与之等效的@property属性:假如关联对象成为了属性,那么它就会具备对应的语义。

    关联类型 等效的属性@property
    OBJC_ASSOCIATION_COPY copy
    OBJC_ASSOCIATION_RETAIN retain
    OBJC_ASSOCIATION_ASSIGN assign
    OBJC_ASSOCIATION_RETAIN_NONATOMIC nonatomic, reatin
    OBJC_ASSOCIATION_COPY_NONATOMIC nonatomic,copy
    下列方法可以管理关联对象:
    // 此方法以给定的键和策略为某对象设置关联对象
    void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    
    // 此方法根据给定的键从某对象中获取相应的关联对象值
    id objc_getAssociatedObject(id object, const void *key)
    
    // 此方法移除所指定对象的全部关联对象
    void objc_removeAssociatedObjects(id object)
    

    举例说明

    ______iOS开发中,之前经常用到UIAlertView类『现在已经过期』,该类提供了一种标准视图,可向用户展示警告信息。当用户按下按钮关闭该视图时,需要用委托协议(delegate protocol)来处理动作,但是,要想设置好这个委托机制,就得把创建警告视图和处理按钮动作的代码分开。由于代码分做两块,所以读起来不方便。比如说,我们之前使用UIAlertView时,一般会这么写:

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"关联对象" message:@"添加一个Block" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil];
    [alertView show];
    
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
        if (buttonIndex == 0) {
            [self cancelDeal];
        }else{
            [self doDeal];
        }
    }
    

    ____如果想在同一个类里,处理多个警告信息视图,那么代码就会变得更为复杂,我们必须在delegate方法中检查传入的alertView参数,并根据此选用相应的逻辑。要是能在创建警告视图的时候直接把处理每个按钮的逻辑都写好,那就简单多了。
    ____这可以通过关联对象来做,创建完警告视图之后,设定一个与之关联的"块 Block",等到执行delegate方法时再将其读出来。此方案的代码实现如下:

    #import <objc/runtime.h>
    static void * kAlertBlockKey = @"AlertBlockKey";
    
    - (void)showAlert{
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"关联对象" message:@"添加一个Block" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil];
        
        void (^touchAlertBlock)(NSInteger) = ^(NSInteger index) {
            if (index == 0) {
              [self cancelDeal];
            }else{
              [self doDeal];
            }
        };
     
        objc_setAssociatedObject(alertView, kAlertBlockKey, touchAlertBlock, OBJC_ASSOCIATION_COPY);
        
        [alertView show];
    }
    
    // UIAlertViewDelegate
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
        void (^alertBlock)(NSInteger) = objc_getAssociatedObject(alertView, kAlertBlockKey);
        
        if (alertBlock) {
            alertBlock(buttonIndex);
        }
    }
    

    Tip

    上面的例子只是一个最简单的应用,可以根据具体的需求实现自己想要的结果。

    相关文章

      网友评论

          本文标题:Obj-C的已有类中,添加关联对象存放自定义数据

          本文链接:https://www.haomeiwen.com/subject/xcnfmttx.html