IOSBlock之页面之间的传值问题
一.字典 数组和字符串的传值
blcok的基本格式:返回值类型(^block变量名)(形参列表) = ^(形参列表) {
};
调用Block保存的代码
block变量名(实参);
默认情况下,Block内部不能修改外面的局部变量
Block内部可以修改使用__block修饰的局部变量
void (^myBlock1)(void); //无返回值,无参数
void (^myBlock2)(NSObject, int); //有返回值,有参数
NSString* (^myBlock3)(NSString* name, int age); //有返回值和参数,并且在参数类型后面加入了参数名(仅为可读性
有参数无返回值的Block
**
* 调用这个block进行两个参数相加
*
* @param int 参数A
* @param int 参数B
*
* @return 无返回值
*/
void (^sumBlock)(int ,int ) = ^(int a,int b){
NSLog(@"%d + %d = %d",a,b,a+b);
};
/**
* 调用这个sumBlock的Block,得到的结果是20
*/
sumBlock(10,10);
有参数有返回值的Block
/**
* 有参数有返回值
*
* @param NSString 字符串1
* @param NSString 字符串2
*
* @return 返回拼接好的字符串3
*/
NSString* (^logBlock)(NSString *,NSString *) = ^(NSString * str1,NSString *str2){
return [NSString stringWithFormat:@"%@%@",str1,str2];
};
//调用logBlock,输出的是 我是Block
NSLog(@"%@", logBlock(@"我是",@"Block"));
1.我发现字符串传值的话比较容易但是字典传值的时候需要将字典中的值取出来进行传值或者进行字典转模型进行传值也比较容易,总之来说字符串传值很轻松的 也解决了很多传值的bug问题.
其中代码是这么实现的
第二个控制器的.h中写出代码块和代码块需要实现的属性
TWOViewCtroll.h中
typedef void (^ReturnTextBlock)(NSString *showText);
@interface TWOViewCtroll : UIViewController
@property (nonatomic, copy) ReturnTextBlock returnTextBlock;
- (void)returnText:(ReturnTextBlock)block;
在.m中
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// lable = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
// lable.text = @"taishabi";
// lable.backgroundColor = [UIColor blueColor];
// lable.textColor = [UIColor blackColor];
// [self.view addSubview:lable];
// dic = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
// @"abc",@"name",
// @"12",@"age",
// @"老了",@"old"
// , nil];
arr = [NSMutableArray arrayWithObjects:@"123",@"456",@"789",@"101112",@"131415", nil];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click:)];
[self.view addGestureRecognizer:tap];
}
-(void)click:(UITapGestureRecognizer *)tap
{
[self dismissViewControllerAnimated:NO completion:nil];
}
- (void)returnText:(ReturnTextBlock)block {
self.returnTextBlock = block;
}
- (void)viewWillDisappear:(BOOL)animated {
if (self.returnTextBlock != nil) {
self.returnTextBlock([arr objectAtIndex:0]);
}}
在第一个界面需要代码
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
lable = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
// lable.text = @"123456789";
lable.backgroundColor = [UIColor blueColor];
lable.textColor = [UIColor blackColor];
[self.view addSubview:lable];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click:)];
[self.view addGestureRecognizer:tap];
}
-(void)click:(UITapGestureRecognizer *)tap
{
TWOViewCtroll *two = [[TWOViewCtroll alloc] init];
[two returnText:^(NSString *showText) {
lable.text = showText;
}];
[self presentViewController:two animated:NO completion:nil];
}
2.在这段代码中可以看出我们创建正常的字符串传值的话可以很轻松的进行传值在字典中可以将字典的所有key值进行便利出来for (<#type *object#> in <#collection#>) {
<#statements#>
}
在这里将所有字典key值全部取出放入字符串中便可实现轻松传值,如果我们在开发中会遇到各种各样的字典和json文件我们可以将json文件解析出来之后进行modle转模型便可实现轻松传值
3.我们在这段代码中可以发现我们的数组中的值也是通过下标进行取出的,这个道理和字典去key值是一样的都是将值取出来然后变成字符串属性传值到新的界面如果很多数据的数组我们便可以是使用for (<#type *object#> in <#collection#>) {
<#statements#>
}
来进行遍历了然后便可轻松地传值到新的界面了
二.block的特性
以上便是block的简单结构了不过blcok的结构很多这只是其中一种
1.blcok传值过程需要注意的是我们的传值类型必须和我们自己自定义的类型一直否则系统将导致崩溃或者更加困难的传值消失等等的bug出现
2.代码块进行排序数组以及和函数的关系等等代码如下
NSArray *stringArray = [NSArray arrayWithObjects:@"abc 1", @"abc 21", @"abc 12",@"abc 13",@"abc 05",nil];
NSComparator sortBlock = ^(id string1, id string2)
{
return [string1 compare:string2];
};
NSArray *sortArray = [stringArray sortedArrayUsingComparator:sortBlock];
NSLog(@"sortArray:%@", sortArray);
此代码便是代码块进行排序的,我们在这里可以看出代码块的类型或者属性类型可以使任意一中的 此处用到的便是升序和降序中的一种NSComparator然后使用新的数组将其排序后的数组进行归纳
3.代码块对递归的调用
代码块想要递归调用,代码块变量必须是全局变量或者是静态变量,这样在程序启动的时候代码块变量就初始化了,可以递归调用我们可以将所有的控件或者一些文本内容将其遍历之后将其所有想要改变的东西进行改变
4.在代码块中可以将代码块的属性使用全局变量或者局部变量进行接收从而实现全局属性的扩展
5.代码块的可变数据和不可变数据的结果是不同的如果是不可变得如果我们将可变数据放在block外面初始化的话他的内容地址不会进行改变如果我们将不可变数据放在外面初始化的话他的内容就会发生变化,如果我们将可变和不可以变数据在代码块中初始化的话那么他们的地址将不会发生任何的变化
6.可以看出在Block内,不可变对象的值任然是初始化时的值,可变对象的值变成了新值。这是因为Block初始化在前,可变对象的修改在后;如果颠倒顺序,先修改可变对象的值,再初始化Block,这样Block就能同步修改后的值了。
7.代码快传值不会将传进去的值进行改变
8.代码块消耗内存比较小,传值还是推荐代码块传值因为对内存要求比较小
9.Block的修饰
ARC情况下
如果用copy修饰Block,该Block就会存储在堆空间。则会对Block的内部对象进行强引用,导致循环引用。内存无法释放。
解决方法:
新建一个指针(__weak typeof(Target) weakTarget = Target )指向Block代码块里的对象,然后用weakTarget进行操作。就可以解决循环引用问题。
如果用weak修饰Block,该Block就会存放在栈空间。不会出现循环引用问题。
MRC情况下
用copy修饰后,如果要在Block内部使用对象,则需要进行(__block typeof(Target) blockTarget = Target )处理。在Block里面用blockTarget进行操作。
TWOViewCtroll *two = [[TWOViewCtroll alloc] init];
__weak typeof(TWOViewCtroll) *weakDemo = two;
[weakDemo returnText:^(NSString *showText) {
lable.text = showText;
}];
解决循环引用问题 但还是存在风险的因为这时候的block没有run这样就会导致内容改变因为内存对象早就被释放了
如果blcok是常数的情况下我们需要在变量前面加上 __weak
10.Block是什么?
- 匿名函数
- 截获自动变量
Block语法。
Block类型变量。
Block的用途。
- 作为函数参数
- 反向传值
- 循环引用
11.blcok和其他传值最明显的特点就是可以逆向传值,block可以进行多条数据同时传递这方便了很多程序员但是必须参数类型和传递类型一致的情况下才可以进行多条数据同时传递,Block 变数储存的是一个block的参考,我们使用类似宣告指标的方式来宣告,不同的是这时block变数指到的地方是一个函数,而指标使用的是「*」,block则是使用「^」来宣告,我们可以定义一个全域的block