__block妙用

示例:代理型网络请求转block
表示头一回在项目里遇上代理型网络请求,这肯定是非常令人头疼的,场景如下:
这是网络请求对象和一个调用的c api

//  APIObject 表示一个通过delegate进行回馈的网络请求对象

#import 

@class APIObject;
@protocol APIObjectDelegate 
-(void)apiDelegateSuccessFunction:(APIObject*)api;
-(void)apiDelegateFaulterFunction:(APIObject*)api;
@end

@interface APIObject : NSObject
@property (nonatomic, weak) id delegate;
@end

//执行 创建对象,执行操作,返回对象
APIObject* api_object(NSString *param, id delegate);
#import "APIObject.h"

@interface APIObject()
@property (nonatomic, copy) NSString* param;
@end

@implementation APIObject

-(void)doSomething:(NSString*)params
{//模拟执行一些处理
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (arc4random() % 2) {
            [self.delegate apiDelegateSuccessFunction:self];
        } else {
            [self.delegate apiDelegateFaulterFunction:self];
        }
    });
}

@end

APIObject* api_object(NSString *param, id delegate)
{
    APIObject *apiObject = [[APIObject alloc] init];
    apiObject.delegate = delegate;
    apiObject.param = param;
    [apiObject doSomething:param];
    return apiObject;
}

下边是运用场景

#import "ViewController.h"
#import "APIObject.h"

@interface ViewController ()

@end

@implementation ViewController
{
   APIObject *apiObj;
}

- (void)viewDidLoad
{
   [super viewDidLoad];
   
   apiObj = api_object(@"参数", self);
   
}

#pragma mark - APIObjectDelegate
-(void)apiDelegateSuccessFunction:(APIObject*)api {
   if (api == apiObj) {
       //codes...
   }
}

-(void)apiDelegateFaulterFunction:(APIObject*)api {
   if (api == apiObj) {
       //codes...
   }
}

@end

先来看一下转换后的运用场景

#import "ViewController.h"
#import "APIObject.h"
#import "APIBlock.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    api_object(@"参数", api_block(^(APIObject *api, BOOL success) {
        if (success) {
            //codes...
        } else {
            //codes...
        }
    }));
    
}

@end

看到这里或许你会觉得很奇怪,APIObject 的delegate属性是weak修饰,api_object( id, id);执行后返回的是一个局部变量,给局部变量丢一个若引用对象也能正常且正确的执行起来,这个api_block(block);函数是个什么鬼?
来一个原理图:


左边为Delegate模式 | 右边为APIBlock模式

APIBlock 的实现有一个必要前提、一个关键点和一个注意点:
必要前提:存在一个或几个必定会执行的方法!
关键点:让APIBlock对象和Block两者产生相互引用,避免对象释放。
注意点:解除循环引用,让对象能够及时释放。

来看一下APIBlock的实现

#import "APIBlock.h"
#import "APIObject.h"

@interface APIBlock : NSObject
@property (nonatomic, strong) APIObject* object;
@property (nonatomic, copy) void(^callBack)(APIObject* api, BOOL success);
@end

@implementation APIBlock

-(void)apiDelegateSuccessFunction:(APIObject*)api {
    self.callBack(api, YES);
}

-(void)apiDelegateFaulterFunction:(APIObject*)api {
    self.callBack(api, NO);
}

@end

还有 api_block(id,block)

id api_block(void(^callBack)(APIObject* api, BOOL success))
{
    __block APIBlock *apiBlock = [[APIBlock alloc] init];
    apiBlock.callBack = ^(APIObject* api, BOOL success){
        apiBlock = nil;
        if (callBack) {
            callBack(api, success);
        }
    };
    return apiBlock;
}

到这已经完成了一半了,因为APIObject还没有强持有APIObject
实现很简单,采用runtime 方法交换一下 -[APIObject setDelegate:] 搞一些小动作便可

@implementation APIObject(APIBlock)

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL originalSelector = @selector(setDelegate:);
        SEL swizzledSelector = @selector(api_setDelegate:);
        Method originalMethod = class_getInstanceMethod(self, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
        BOOL success = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        if (success) {
            class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

-(void)api_setDelegate:(id)delegate
{
    [self api_setDelegate:delegate];
    if ([delegate isKindOfClass:[APIBlock class]])
    {
        APIBlock *apiBlock = delegate;
        if (apiBlock.object) {
            apiBlock.object.delegate = nil;
        }
        apiBlock.object = delegate;
    }
}

@end

最后比较一下转换前和转换后的api调用

    apiObj = api_object(@"参数", self);//delegate模式,delegate方法就不写出来了

             api_object(@"参数", api_block(^(APIObject *api, BOOL success) {//APIBlock模式
                 //codes...
             }));

完结。

你可能感兴趣的:(__block妙用)