最近赶项目 , 自己时间比较少 , 加上也没找到什么可写的东西 , 就写一点关于block的东西吧 . 一些细节还是值得思考的 , 基本上也把所有的情况和大致原理都罗列了一些 . 这里我们创建Person类 和ViewController类来做一些试验和比较.
Person类 .h 文件
#import <Foundation/Foundation.h>
/**
* 无返回值 可以接收参数的block
*
* @param number block接收参数类型
*/
typedef void(^MYOneBlock)(NSInteger number);
/**
* 无返回值,不能接收参数的block
*/
typedef void(^MYTwoBlock)();
/**
* 有返回值,可以接收参数的block
*
* @param number 接收参数类型
*
* @return 返回值类型
*/
typedef BOOL(^MYThreeBlock)(NSInteger number);
/**
* 有返回值,不能接收参数的block
*
* @return 返回值类型
*/
typedef BOOL(^MYFourBlock)();
@interface Person : NSObject
/**
*
*
* @param MYOneBlock 为此方法参数, block参数可以接收参数,无返回值
*/
+ (void)testWithOneBlock:(MYOneBlock)MYOneBlock;
/**
*
*
* @param MYTwoBlock 为此方法参数, block参数不能接收参数,无返回值
*/
+ (void)testWithTwoBlock:(MYTwoBlock)MYTwoBlock;
/**
* <#Description#>
*
* @param MYThreeBlock 为此方法参数, block参数可以接收参数,且有返回值
*/
+ (void)testWithThreeBlock:(MYThreeBlock)MYThreeBlock;
/**
* <#Description#>
*
* @param MYFourBlock 为此方法参数, block参数不能接收参数,有返回值
*/
+ (void)testWithFourBlock:(MYFourBlock)MYFourBlock;
Person类 . m 文件
@property (strong, nonatomic) UIView *testView;
@property (copy, nonatomic) void(^testBlock)();
@end
@implementation ViewController
#import "Person.h"
@implementation Person
+ (void)testWithOneBlock:(MYOneBlock)MYOneBlock
{
//此处回调
//向MYOneBlock参数传入5,执行block块,block块中打印参数
MYOneBlock(5);
NSLog(@"MYOneBlock当前类为:%@",[self class]);
}
/**
* MYTwoBlock();内 打印类为viewController
* 当前类为Person
* 结论: 当block块作为传输时,block块中的self是为地址传递
*/
+ (void)testWithTwoBlock:(MYTwoBlock)MYTwoBlock
{
//观察此处打印值 ,block中打印参数
MYTwoBlock();
NSLog(@"MYTwoBlock当前类为:%@",[self class]);
}
+ (void)testWithThreeBlock:(MYThreeBlock)MYThreeBlock
{
//向MYThreeBlock参数传入 10,并接收block块的返回值,当前方法中打印返回值
NSInteger number = MYThreeBlock(10);
NSLog(@"%li",number);
NSLog(@"MYThreeBlock当前类为:%@",[self class]);
}
+ (void)testWithFourBlock:(MYFourBlock)MYFourBlock
{
//执行MYFourBlock block参数,接收返回值,当前方法中打印返回值
NSInteger number = MYFourBlock();
NSLog(@"%li",number);
NSLog(@"MYFourBlock当前类为:%@",[self class]);
}
ViewController .m文件
例1: block调用机制
- (void)test0
{
/**
* 调用过程: 调用testWithOneBlock:方法 ,参数为可以接收参数的block块
*
* @param number <#number description#>
*
* @return <#return value description#>
*/
[Person testWithOneBlock:^(NSInteger number) {
NSLog(@"%li",number);
}];
/**
* 调用过程: 调用testWithTwoBlock:方法,传入block块
*/
[Person testWithTwoBlock:^{
NSLog(@"%@",[self class]);
}];
/**
* 调用过程:调用testWithThreeBlock: 方法,传入一个有返回值,且可以接收参数的block块
*
* @param number <#number description#>
*
* @return <#return value description#>
*/
[Person testWithThreeBlock:^BOOL(NSInteger number) {
return number + 10;
}];
/**
* 调用testWithFourBlock:方法,传入一个有返回值的block块
*/
[Person testWithFourBlock:^BOOL{
return 88;
}];
}
例 2 : block的循环引用 实验方法: 给当前类viewController增添一个block作为属性
- (void)test
{
/**
* 如此写法,会报一个警告: lead to a retain cycle 因为造成了循环引用
*/
//循环引用过程: testBlock作为当前类viewController实例对象(self)的属性,self.testBlock 指针指向testBlock块的内存空间.此处,访问self.testView,testBlock又指向了self.testView .因为循环引用,解决方式如下:
/*
self.testBlock = ^{
self.testView = [[UIView alloc]initWithFrame:(CGRect){100,100,100,100}];
};
*/
//解决方案原理一致,选择各按喜好
//解决方案1:
// typeof(self) weakself = self;
// self.testBlock = ^{
//
// weakself.testView = [[UIView alloc]initWithFrame:(CGRect){100,100,100,100}];
//
// };
//解决方案2:
__weak ViewController * weakself = self;
self.testBlock = ^{
weakself.testView = [[UIView alloc]initWithFrame:(CGRect){100,100,100,100}];
};
}
例3: block块中修改外界值
- (void)test2
{
//情况1: 访问外界对象
UIView *myView = [[UIView alloc]initWithFrame:(CGRect){100,100,100,100}];
self.testBlock = ^{
// a = 10;
myView.frame = CGRectMake(10, 10, 10, 10);
NSLog(@"%@",NSStringFromCGRect(myView.frame));
};
self.testBlock();
//情况2 : 访问外界变量
//经c++反编译可以得出 , block内部中访问外部变量 , 外部变量只是值的传递到block内部 ,所以如果不用__block修饰 , 直接在block内部 写 a = 10 , 是会报错的 . 如果用__block修饰之后 , block内部则可以访问到 a 的地址 对其值进行修改
__block int a =5;
self.testBlock = ^{
a = 10;
};
NSLog(@"%d",a);
//情况3: 访问外界变量
int b = 666;
self.testBlock = ^{
NSLog(@"%d",b);
};
b = 1000000000;
self.testBlock();
//此类情况 , NSLog会打印 666 而不是1000000000 原因是程序从上往下运行 ,NSLog(@"%d",b);这一步时已经记录了 b的值 , 所以后面 更改b =1000000000 并不能改变打印值