示例:代理型网络请求转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);函数是个什么鬼?
来一个原理图:
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...
}));
完结。