iOS关联对象的应用

本文介绍了Objective-C中关联对象的使用方法,包括如何通过objc_setAssociatedObject、objc_getAssociatedObject和objc_removeAssociatedObjects来管理关联对象。此外还展示了如何利用关联对象给UIAlertView添加额外的行为逻辑及分类中属性的实现。

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

可以通过下列方法管理关联对象:

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

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

id objc_getAssociatedObject(id object, void *key)

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

void objc_removeAssociatedObjects(id object)

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

用法举例:

1)创建UIAlertView

- (void)askUserAQuestion {

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"question"

                                                    message:nil

                                                   delegate:self

                                          cancelButtonTitle:@"取消"

                                          otherButtonTitles:@"确定", nil];

    [alert show];

}

#pragma mark - <UIAlertViewDelegate>

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {

    if (buttonIndex == 0) {

        // do ...

    }else {

        // do ...

    }

}

但是有时候我们想让创建警告视图与处理操作结果的代码都放在一起,这样更易懂我们也不需要在两部分代码之间来回游走,即可明白视图的用处。所以我们采用关联对象修改一下:

static void *alertViewKey = "alertViewKey";

- (void)askUserAQuestion {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"question"
                                                    message:nil
                                                   delegate:self
                                          cancelButtonTitle:@"取消"
                                          otherButtonTitles:@"确定", nil];
    void (^block)(NSInteger) = ^(NSInteger buttonIndex) {
        if (buttonIndex == 0) {
            // do something
        }else {
            // do something
        }
    };
    objc_setAssociatedObject(alert,
                             alertViewKey,
                             block,
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [alert show];
}
#pragma mark - <UIAlertViewDelegate>
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    void (^block)(NSInteger) = objc_getAssociatedObject(alertView, alertViewKey);
    block(buttonIndex);
}

需要注意:块可能要捕获某些变量,这也许会造成循环引用。其实例子相当于给alertView增加了个block属性,同理也可以用关联对象给分类添加属性:

@interface NSObject (WKCategoryProperty)

@property (nonatomic, copy) NSString *categoryProperty;

@end

#import "NSObject+WKCategoryProperty.h"

#import <objc/runtime.h>

static void *categoryPropertyKey = "categoryPropertyKey";

@implementation NSObject (WKCategoryProperty)

- (NSString *)categoryProperty {

    return objc_getAssociatedObject(self, categoryPropertyKey);

}

 

- (void)setCategoryProperty:(NSString *)categoryProperty {

    objc_setAssociatedObject(self, categoryPropertyKey, categoryProperty, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

@end

注意:

@property (nonatomic, copy) NSString *property;

这行代码实际上会做三件事情:

1)生成实例变量property

2)生成get方法

3)生成set方法

这些都是编译器帮助生成的,虽然我们看不到,但它确实就在那里。哪为什么分类中不能使用呢,@property` 其实有元编程的思想,它能够为我们自动生成实例变量以及存取方法,而这三者构成了属性这个类似于语法糖的概念,为我们提供了更便利的点语法来访问属性,因为分类的实例变量的布局已经固定,使用 @property 已经无法向固定的布局中添加新的实例变量(这样做可能会覆盖子类的实例变量),所以我们需要使用关联对象以及两个方法来模拟构成属性的三个要素

总结:

可以通过“关联对象”机制来把两个对象连起来。

定义关联对象时可指定内存管理语义,用以模仿定义属性时所采用的“拥有关系”与“非拥有关系”。

只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难以查找的bug。

 demo:

https://github.com/GitWangKai/AssociationObject

转载于:https://www.cnblogs.com/byxixiblogs/p/8250150.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值