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不存在这样的问题。
- (void)dealloc
{
NSLog(@"dealloc");
[AESingleObject sharedInstance].newForgetPasswordViewControllerTimerCallBack = nil;
}

一个类的对象中的函数可以访问全局的单例。
使用系统的单例的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 ]) {
  [self addchildV];

}

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:^{
  [RootNav pushViewController:[self commitYXView] animated:NO];

}];
}
第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++的二级指针相似。

    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setSafeObject:[GBAMapOrientation defaultOrientation].locationEntity.citycode forKey:@"cityCode"];
void(^block)(GBSelectAirportEntity *entity) = ^(GBSelectAirportEntity *entity){
@strongify(self);
self.flightArrAirportFullName = entity.flightArrAirport;
};
[userInfo setSafeObject:block forKey:@"block"];
[MGJRouter openURL:@"gb://selectAirport" withUserInfo:userInfo completion:nil];

这样通过三种block三种方法就能实现,从A页面包含或跳转到B页面,A页面可以控制B页面,B页面也能控制A页面,达到互相控制的目的。
第4种情况:block参数
咱们发送网络请求等封装的接口就是这种类型。咱们看一下它的简单模型:
ODCTripManageEntity.h

#import <Foundation/Foundation.h>
@class ODCTripListEntity;
@interface ODCTripManageEntity : NSObject
- (void)deCodeFilesWithblock:(void(^)())block;
@end

ODCTripManageEntity.m

@implementation ODCTripManageEntity
#pragma mark - 加载本地行程文件
- (void)deCodeFilesWithblock:(void(^)())block;
{
if (block) {
block();
}
}
@end

调用者:

    @weakify(self);
[self.tabview.refreshView startAnimating];
[self.tripManageEntity deCodeFilesWithblock:^{
@strongify(self);
[self.tabview.refreshView endAnimating];
[self.tabview reloadData];
}];