1.单例声明的block
2.被包含的对象声明的block
3.调用者的block被当变量传入被调用对象
4.block参数
block使用要注意使用不当,容易出现内存泄漏而崩溃,要注意判空处理,使用时尽量使用弱引用( __weak typeof(self) weakSelf = self;)。
第一种方式:单例声明的block。
它可以全局使用,当多个地方使用该block时,只有最后一个注册的单例block有用。所以你想在多个类中使用相同的处理,那么你就要在单例中声明多个不同的block.
SingleObject.h文件:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
typedef void(^TimerProgress1)();
@interface SingleObject : NSObject
- (SingleObject *)sharedInstance;
- (void)regisiterTimerProgress1Callback:(TimerProgress1)callback;
@end
SingleObject.m文件
#import “SingleObject.h”
@implementation SingleObject
+(SingleObject *) sharedInstance
{
static SingleObject *sharedInstace = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstace = [[self alloc] init];
});
return sharedInstace;
}
-(void)progress1
{
if (self.timerProgress1) {
self.timerProgress1();
}
} - (void)regisiterTimerProgress1Callback:(TimerProgress1)callback
{
self.timerProgress1 = callback;
}
@end
单例子block的使用: - (void)regisiterSingleObjectTimerProgress1Callback {
__weak typeof(self) weakSelf = self;
[[SingleObject sharedInstance] regisiterTimerProgress1Callback:^{
[weakSelf progress1];
}];
}
注意:单例block在页面销毁时要把它,置空,不然就是原来所在页面销毁了,由于它是全局的终生的,它还活着,你判空时发现它不是空,还会继续回调。就是你的内存泄漏了,只是泄漏的很少,不容易观察到。需要在dealloc函数里销毁它。
单例block可以代替一对一的通知。并且不存在通知的注册时间,是实时注册,实时生效。通知是在注册后不是立即生效,需要时间调度到才能生效,这个时间极短。部分多线程应用,当在通知还在注册过程中发送了通知,有几率闪退,而单例block不存在这样的问题。
一个类的对象中的函数可以访问全局的单例。
使用系统的单例的block:
__weak typeof(self) weakSelf = self;
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
[app regisiterXYContinueListenOrderCallback:^{
[weakSelf continueListenOrder];
}];
第二种方式:对象声明的block.
控制器页面包含的控件或使用的对象的block的使用,控制器间的block使用.
第1种,控制器页面包含的控件block的使用。
CustomNavigationBar.h文件
#import <UIKit/UIKit.h>
typedef void (^backBlock)(BOOL iSuccess);
@interface CustomNavigationBar : UIView
- (void)backResult:(backBlock)back;
@end
CustomNavigationBar.m文件
#import “CustomNavigationBar.h”
@interface CustomNavigationBar ()
@property (nonatomic,copy) backBlock backResult;
@end
@implementation CustomNavigationBar - (instancetype)initWithFrame:(CGRect)frame{
if (self=[super initWithFrame:frame ]) {
}
return self;
}
- (void)backResult:(backBlock)back{
self.backResult = back;
} - (void)backAction:(UIButton *)sender {
if(self.backResult)
{
self.backResult(YES);
}
}
@end
页面包含的控件的block使用如下:
-(void)loadButtonAction
{
[_customCommonNavigationBar backResult:^(BOOL iSuccess) {
[self.navigationController popViewControllerAnimated:YES];
}];
}
第2种情况,页面控制器间的block使用。
LoginViewController.h文件
#import <UIKit/UIKit.h>
#import “YXBaseViewController.h”
@interface LoginViewController : YXBaseViewController
{
}
//登陆成功以后的回调
@property (nonatomic, copy) void (^didClickLoginSuccessBlock)();
@end
LoginViewController.m文件
#import “LoginViewController.h”
@interface LoginViewController ()
{
}
@end
@implementation LoginViewController - (void)loginAction:(UIButton *)sender {
[self.view endEditing:YES];
if (self.didClickLoginSuccessBlock) {
self.didClickLoginSuccessBlock();
}
}
@end
其它页面使用block.
-(void)commitRootViewController:(NSDictionary *)launchOptions
{
LoginViewController *LoginVC = [[LoginViewController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:LoginVC];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
[LoginVC setDidClickLoginSuccessBlock:^{
}];
}
第3种情况:调用者的block被当变量传入被调用对象。
前面两种情况都是说明的A对象的成员变量或函数内的变量是声明block的B对象,那么是否可以A页面调用了B页面,进入B页面,B页面是否可以直接控制A页面的部分控件的显示内容。注意,B页面看似无法持有A页面的对象指针,不然就破坏了object c的封装性(你像C++一样把A页面的self当对象指针传递给B页面,编译器会告警,虽然你可能实现你的功能,那样使用是不合法的。),你可以在跳转B页面前,申请个block,把这个bock传递给B页面,那么你就可以在B页面控制A页面的部分控件了。这种方法本质方法还是指针的传递,和C++的二级指针相似。
这样通过三种block三种方法就能实现,从A页面包含或跳转到B页面,A页面可以控制B页面,B页面也能控制A页面,达到互相控制的目的。
第4种情况:block参数
咱们发送网络请求等封装的接口就是这种类型。咱们看一下它的简单模型:
ODCTripManageEntity.h
ODCTripManageEntity.m
调用者: