Objective-C Associative References(关联引用)- 实践

关于什么是关联引用,这两篇文章作了详细的解释  Objective-C – 关联引用  Objective-C Associative References 

熟悉Category都知道,我们是不能在Category能创建实例变量的,但我们可以通过Associative References来达到目的。关联引用说白点,就是你可以往一个已存在的类添加属性,可以设置KEY,VALUE,当然你需要,也可以设置多个。通过上面的文章相信你已经知道什么是关联引用,但到底能干点什么,相信与我刚了解的时候疑惑是一样的。下面举例说明。

下面的UIAlertView block回调是通过Category + 关联引用来实现的。源码截取于:BlockUI

//UIAlertView
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"title"
                                                  message:@"message"
                                                 delegate:self
                                        cancelButtonTitle:@"ok"
                                        otherButtonTitles:nil];
[alert showWithCompletionHandler:^(NSInteger buttonIndex) {
        NSLog(@"button:%d",buttonIndex);
}];

上面的代码的回调相当的简洁,实用性很强。你只要往里边塞你的代码就可以了。省掉了写delegate的方法。

#import <UIKit/UIKit.h>
#import <objc/runtime.h>
@interface UIView(BUIView)<UIAlertViewDelegate>

//UIAlertView
-(void)showWithCompletionHandler:(void (^)(NSInteger buttonIndex))completionHandler;

@end

#import "BUIView.h"
#import <objc/runtime.h>
@implementation UIView(BUIView)

const char oldDelegateKey;
const char completionHandlerKey;

#pragma -mark UIAlerView

-(void)showWithCompletionHandler:(void (^)(NSInteger buttonIndex))completionHandler
{

    UIAlertView *alert = (UIAlertView *)self;

    // CcompletionHandler 是一个Block变量,也就是我们在{}写的代码
    if(completionHandler != nil)
    {
    	// 检索关联对象
        id oldDelegate = objc_getAssociatedObject(self, &oldDelegateKey);

        // 因为可能多次调用同一对象,所以先判断是否已设置。
        if(oldDelegate == nil)
        {

        	// 往UIAlerView 塞进了一个 变Key:oldDelegateKey 变量为:oldDelegate
        	// 按我理解,完全可以当作是实例变量,其实也就是本Delegate。当你发现,为什么要赋一个nil值,其实作者在下边有赋值
            objc_setAssociatedObject(self, &oldDelegateKey, oldDelegate, OBJC_ASSOCIATION_ASSIGN);
        }
        
		// 设置 Delegate 与 关联引用        
        oldDelegate = alert.delegate;
        alert.delegate = self;
        
        // 向 往UIAlerView 添加 completionHandlerKey 和 completionHandler
        // 目的是为了在 UIAlerView Delegate - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 中使用
        objc_setAssociatedObject(self, &completionHandlerKey, completionHandler, OBJC_ASSOCIATION_COPY);
    }

    // 弹出 往UIAlerView
    [alert show];
}

// UIAlerView Delegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    
    UIAlertView *alert = (UIAlertView *)self;

    // 检索关联对象, CcompletionHandler 也就是我们写的{}中的代码
    void (^theCompletionHandler)(NSInteger buttonIndex) = objc_getAssociatedObject(self, &completionHandlerKey);
    
    if(theCompletionHandler == nil)
        return;
    
    // 执行
    theCompletionHandler(buttonIndex);

     // 检索关联对象 oldDelegateKey
    alert.delegate = objc_getAssociatedObject(self, &oldDelegateKey);
}

我对源码加上了注释,希望你能更快的了解其作用和理解关联对象的使用方法。


上面的代码执行顺序是t先执行

 -(void)showWithCompletionHandler:(void (^)(NSInteger buttonIndex))completionHandler方法

当点击按扭的时候,就执行 

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

最后执行我们写的代码

[alert showWithCompletionHandler:^(NSInteger buttonIndex) {
        NSLog(@"button:%d",buttonIndex);
}];

这方法很清淅,很简单的实现了UIAlerView Block的回调方法。基于这种思路,你可以自己实现很多的回调的也可以参考或者使用BlockUI的源码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值