ios block
来源:互联网 发布:数控车床编程教学ppt 编辑:程序博客网 时间:2024/06/07 15:52
1.block的特点:
2、定义blockblock是c语言;
block是一种数据类型,可当做参数使用,也可以用作返回值;总之,对比int的用法用即可【定义的时候,最好跟函数对比】;
block是预先准备好的代码块,在需要的时候调用;
有返回值、有参数:返回类型^(blockName)(参数)=^返回类型(参数列表){//代码实现}
无返回值、有参数:void^(blockName)(参数)=^(参数列表){//代码实现}
无返回值、无参数void^(blockName)()=^{//代码实现}
速记代码块:InlineBlock,编译器会提示:
returnType(^blockName)(parameterTypes)=^(parameters){
statementes
};
3、block引用外部变量
在定义block时,如果使用了外部变量,block内部会默认对外部变量做一次copy;
默认情况下,不允许在block内部修改外部变量的值;
在外部变量声明时,使用__block修饰符,则可以在block内部修改外部变量的值;
4、数组的遍历和排序;
遍历:enmuerateObjectsUsingBlock: 方法,该方法的所有参数都应准备到位,可以直接使用,效率比for高;
举例:懒加载enumerateObjectsUsingBlock遍历:[tempArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL*_Nonnull stop) {NSDictionary *dict = (NSDictionary*)obj;
Heros *hero = [HerosherosWithDict:dict];[ArrMaddObject:hero];}];for—IN遍历:for (NSDictionary*dict in tempArray) {
Heros *heros = [HerosherosWithDict:dict];
[ArrM addObject:heros];}排序:sortedArrayUsingComparator:
5、block的数据的逆向传值
被调用方:准备块代码;
调用方:定义代码属性,在适当的时候调用block;
举例说明:调用方:定义块代码属性在适当的时候执行:
- #import <Foundation/Foundation.h>
- #import <UIKit/UIKit.h>
- @class YSCNSOperationOP;
- typedef void(^setUpUIImage)(YSCNSOperationOP *);
- @interface YSCNSOperationOP : NSOperation
- @property (nonatomic, copy) NSString *urlString;
- @property (nonatomic, strong) UIImage *image;
- @property (nonatomic, copy) setUpUIImage myBlock;
- - (void)setUpUIImage:(setUpUIImage )block;
- @end
被调用方:准备代码块
- #import "YSCNSOperationOP.h"
- @implementation YSCNSOperationOP
- - (void)main {
- @autoreleasepool {
- UIImage *image = [self downLoadImage:self.urlString];
- self.image = image;
- dispatch_async(dispatch_get_main_queue(), ^{
- self.myBlock(self);
- });
- }
- }
- - (UIImage *)downLoadImage:(NSString *)urlString{
- NSURL *url = [NSURL URLWithString:urlString];
- NSData *data = [NSData dataWithContentsOfURL:url];
- UIImage *image = [UIImage imageWithData:data];
- return image;
- }
- - (void)setUpUIImage:(setUpUIImage )block {
- if (block) {
- self.myBlock = block;
- }
- }
- @end
6、block的底层实现原理
- #import "ViewController.h"
- #import "YSCNSOperationOP.h"
- @interface ViewController ()
- @property (weak, nonatomic) IBOutlet UIImageView *iamgeView;
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- }
- - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- YSCNSOperationOP *yscOp = [[YSCNSOperationOP alloc] init];
- yscOp.urlString = @"http://h.hiphotos.baidu.com/image/pic/item/9825bc315c6034a8094ace24c9134954082376ee.jpg";
- [yscOp setUpUIImage:^(YSCNSOperationOP *op) {
- self.iamgeView.image = op.image ;
- }];
- NSOperationQueue *queue = [[NSOperationQueue alloc] init];
- [queue addOperation:yscOp];
- }
- @end
block是一个指针结构体,在终端下通过clang-rewrite-objc指令看看c++代码;
创建一个OSX工程,写一个最简单的block;
利用终端编译成c++代码:clang-rewrite-objc main.m
#import <Foundation/Foundation.h>int main(int argc, const char * argv[]) { @autoreleasepool { void (^myblock)() = ^() { NSLog(@"hello block"); }; myblock(); } return 0;}
几个重要的结构体和函数简介:
- __block_impl:这是一个结构体,也是C面向对象的体现,可以理解为block的基类;
- __main_block_impl_0: 可以理解为block变量;
- __main_block_func_0: 可以理解为匿名函数;
- __main_block_desc_0:block的描述, Block_size;
1、__block_implstruct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr;};2、__main_block_impl_0struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }};3、__main_block_func_0static void __main_block_func_0(struct __main_block_impl_0 *__cself) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_gc_5fkhcz0n6px48vzc744hmp6c0000gn_T_main_eef954_mi_0); }4、 __main_block_desc_0staticstruct __main_block_desc_0 { size_t reserved; size_t Block_size;} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; void (*myblock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)); ((void (*)(__block_impl *))((__block_impl *)myblock)->FuncPtr)((__block_impl *)myblock); } return 0;}
注意事项:block容易造成循环引用,在block里面如果使用self,然后形成强引用时,需要打断循环引用;
在MRC下用_block,在ARC下使用_weak;
7、关于block在内存中的位置:
block块的存储位置(block入口的地址)可能存放在3个地方:代码区(全局区)、堆区、栈区(ARC情况下会自动拷贝到堆区,因此ARC下只有两个地方:代码区和堆区);ARC下也会有栈块的存在,只有把栈块赋值给strong对象或者block类型变量的时候才会触发_Block_copy函数,即[block copy],此时的栈块才会变成堆块。
代码区:不访问除去栈区的变量(如局部变量),且不访问堆区的变量(如用alloc创建对象)时,此时block存放在代码区;
堆区:如果访问了处于栈区的变量(如局部变量)或堆区的变量(如用alloc创建的对象),此时block存放在堆区; ***需要注意
补充:
1)block内容实际是放在栈区,在ARC情况下,会自动拷贝到堆区;如果不是ARC,则存放在栈区。所以,在函数执行完毕就会释放,想在外面调用需要用copy指向他,这样就拷贝到了堆区;strong属性不会拷贝,会造成野指针错误。(需要理解ARC是一种编译器特性,即编译器在编译时在合适的地方retain、release、autorelease,不是iOS的运行时特性);
2)此外代码存放在堆区时,需要注意!!因为堆区不像代码区不变化,堆区是动态的(不断的创建销毁)。当没有强指针指向的时候就会被销毁,如果再去访问这段代码时,程序就会奔溃!所以此种情况在定义block属性时2需要制定为strong or copy。block是一段代码,是不可变的,所以使用copy也不会深拷贝;
简单记忆:
补充:
- Block如果没有引用外部变量
保存在全局区
(MRC/ARC一样)- Block如果引用外部变量
ARC保存在堆区
; MRC保存在栈区
必须用copy修饰block;1.被block捕获的外界变量不能被随意修改,需要使用__block修饰变量才能达到修改的目的。
2.__NSGlobalBlock__ 从程序启动一直存在于全局区,且并不像__NSMallocBlock__会强引用捕获的变量
3.__MallocBlock造成的强引用循环可以通过 置nil 破解
- ios block
- IOS BLOCK
- ios block
- ios block
- ios block
- IOS BLOCK
- ios block
- iOS Block
- ios block
- IOS block
- iOS Block
- IOS block
- iOS BLOCK
- iOS Block
- IOS Block
- IOS block
- IOS Block
- IOS -BLOCK
- Servlet3中的AsyncContext异步和多线程异步有什么区别
- iOS UIWebView + JS交互 总结
- 美团点评CodeM编程大赛-题二
- [Codeforces]Fox Dividing Cheese
- 利用Maven打War包引入本地Jar包
- ios block
- 三轮移动机器人在ros indigo下的定位、导航与轨迹规划构想
- Elipse clean的作用
- 【Unity】内存泄漏危害及处理方式(腾讯WeTest分析使用)
- AsyncTask的使用及原理
- 数据库事务隔离级别,ACID,spring事务传播性
- date时间格式化 只想要年月日
- 跨浏览器的事件处理(套装)
- MySQL索引及查询优化总结