FBI WARNING:纯属个人见解,有可能是错误的理解。O(∩_∩)O
block作用
1.可以传递数据,取代代理模式很方法,代码简洁。
2.当做回调,这是主要的用途。
写法也简单,固定格式,照着写就行,一般不会出错,记得防止出现循环引用就行。别的没啥。
问题:block它是怎么传递数据的,回调怎么工作的。我冥思苦想一番,感觉有点眉目了,记录一下,怕忘了。
一、函数。(或者叫<方法>,叫法不一样,感觉没啥区别)
1.1正常情况下,定义一个函数包括名字,参数,返回值3部分。
1.2使用起来包括定义、实现、调用3步。
例如:
定义+实现。大括号里就是一个函数的实现部分,前面定义了名字和参数返回值
- (void)testFunction1WithParameter:(NSString *)title{
NSLog(@"方法1的实现 -- %@", title);
}
调用:
[self testFunction1WithParameter:@"方法1"];
这就是函数的使用。
二、block
block是特殊函数!!!
这点很重要。时时刻刻记得这一点。重点:block是函数。
再强调一下,block就是特殊函数,本质还是函数,既然是函数,函数怎么用,block也怎么用,和上面函数是一样。
苹果用^这个符号标记block,告诉人们看到这个符号,就是个block了。没别的意思,给这个函数加了个标记,写法不一样了。
1.block也有方法名,参数,返回值。和普通函数一样。
定义一个block:和普通函数一样,都是定义+实现
void(^block)() = ^(){
NSLog(@"block的实现");
};
这就定义了一个无参数无返回值,叫block名字的的函数,用^标记一下,大括号依然是函数的实现部分。
block();
执行函数,由于block是特殊的函数,执行方式和普通函数也不一样,不用self调用,直接写函数名字跟个小括号就行了。比较不像oc。
总结:block是特殊函数,特殊的地方就在于定义和调用方式和普通函数不一样,实现部分没变化,还是在大括号里面实现。
另外:如果定义一个字符串,NSstring *a = @"字符串";
NSstring 是类型,a是名字。
函数有没有类型?当然有!
block这种函数的写法,相当于用这个特殊符号标记了一个函数的类型。void(block)() 这段代码就是block的定义。有名字、参数类型、返回值类型。
所以,block的写法可以定义一个函数的类型。这个函数的类型就是void(^)(),名字就是block。
2.经过上面的洗脑,慢慢接受了block是函数的观点,和普通函数没啥区别。就是样子怪怪的罢了。
如果block像上面这么定义+实现+调用,用法其实和普通函数没啥区别,就体现不出它的价值了。
注:如果block不作为参数,需要在^符号后面直接写上block名字,然后直接调用,如第1的例子。
如果作为参数需要像普通的参数那样写,在最后写上block名字,如下。
//block传递数据
- (void)testFunction2WithParameter:(NSString *)title testBlock:(void(^)(NSString *msg))block{
NSLog(@"方法2的实现 -- %@", title);
block(@"block的调用--传递数据data");
}
block参数的类型就是括号里的一串。这样就把一个函数(用block的写法)作为参数传给另外一个参数了。
3.回调
理解了函数的定义、实现、调用,函数作为参数传递给另外一个函数,就该说回调了。
重点:当A函数作为B函数的参数,那么A函数就具有了回调的功能。由于函数作为参数必须写成block格式,所以一般说block具有回调的功能。
上面说了,函数的使用包括定义、实现、调用3步。一般定义和实现写一块。
调用写在需要调用的地方。也就是说函数的调用和实现是分开的。
比如第一部分介绍普通函数的部分,定义实现完了,调用的时候才走实现的部分,这点很重要。
函数A:(即block)
void(^)(NSString *msg)
把A函数作为另外一个函数的参数,如下:
函数B:
//B的定义和实现
- (void)testFunction2WithParameter:(NSString *)title testBlock:(void(^)(NSString *msg))block{
NSLog(@"方法2的实现 -- %@", title);
block(@"block的调用--传递数据data");
}
函数B的调用
[self testFunction2WithParameter:@"方法2" testBlock:^(NSString *msg) {
NSLog(@"block的实现");
NSLog(@"方法2的调用 -- %@", msg);
}];
后面的大括号其实是A函数的实现部分,这种block的写法,其实把函数的定义、实现、调用都分开了。而一般函数定义和实现是写一块的,比如B函数。
但是实现和调用都是分开的,这点没变。都是通过调用函数去实现大括号{ }里面的代码。
通过观察:可以得到:
1.B函数的实现里面写了block的调用,
2.B函数的调用的时候,把block实现了。
会出现什么情况?
按代码的执行顺序
第一步、在viewDidLoad里调用B函数,这是需要跳到B函数的实现部分,即大括号里
第二步、在B函数的实现里面,发现了A函数block的调用
第三步、既然有调用,必须去寻找怎么实现的,就跳到了A函数的实现部分
第四步、发现A的实现部分在B函数的调用后面,所以代码又回到了B函数的调用部分,回到了第一步的代码部分viewDidLoad里。这就实现了回调。
如果block带有参数,就把这个参数回调了B函数的执行地方,可以传递数据,这就实现了传递数据的功能。例如上面的函数传了个字符串。比如一些网络请求方法,通过写一个block就能把请求的数据传递到这个请求方法调用的地方,就算是得到了数据。
swift闭包一个道理,捋一捋就通了。