当前位置: 首页 > wzjs >正文

云南网站建设seo自学教程seo免费教程

云南网站建设,seo自学教程seo免费教程,深圳市中农网是专业农产品营销网站,app商城开发网站建设前言 笔者在学习过程中经常遇到使用Block的地方,不太理解,因此来学习了Block的内容 回调 回调是编程中一种延迟执行的机制,允许代码在特定时间发生或任务完成后执行特定的逻辑 回调的本质:控制反转 传统调用流程;…

前言

笔者在学习过程中经常遇到使用Block的地方,不太理解,因此来学习了Block的内容

回调

回调是编程中一种延迟执行的机制,允许代码在特定时间发生或任务完成后执行特定的逻辑

回调的本质:控制反转

传统调用流程;

调用方->被调用方->执行完成->返回结果给调用方

回调调用流程:

调用方->被调用方->执行完成->触发回调->执行调用方法的逻辑

核心思想:

将下一步做什么的决策权从被调用方交给调用方

解耦:被调用方无需关心具体的后续逻辑,只负责在特定时机出发回调

四种主要的回调方式

还没学到这里,笔者后面会补充的

Block

Block的定义

  1. 在iOS开发中,Block是一种闭包(Closure)的概念,可以将一段代码作为一个对象进行传递和存储,类似于函数的指针。Block可以捕获其定义时所在范围内的变量,并在需要时执行这段代码块,Block的使用可以方便的实现回调、异步操作、事件处理等功能

  1. Block的本质也是对象,第一段代码块,iOS之所以引入Block,是因为使用Block可以精简代码,减少耦合

Block的用法

  • 作为变量使用

// 返回值类型(^变量名)(参数列表)
int (^multiply)(int, int) = ^(int a, int b) {return a * b; 
}
//调用Block
int result = multiply(3, 5);
  • 作为方法参数

- (void)performOperationWithBlock:(void(^)(void))block {block();
}
[self performOperationWithBlock:^{NSLpg(@"执行Block");
}]
  • 作为属性或者实例变量

@property (nonatomic, copy) void (^completionBlock)(void);
self.completionBlock = ^{NSLog(@"执行操作");
}

Block与外部变量

在iOS开发中,Block可以捕获其定义时所在范围内的外部变量,这种特性称之为变量捕获(Variable Capture),当Block内部引用外部变量时,Block会自动捕获这些变量的值或引用,以便在Block执行时使用,在Block中使用外部变量可以实现数据共享与传递(确保Block在脱离于原始作用域后仍能正确访问外部变量)

变量类型类型捕获到block内部访问方式
局部变量auto可以值传递
局部变量static可以指针传递
全局变量不可以直接访问
  • 局部变量auto(自动变量),平时我们写的局部变量,默认就有auto,离开作用域就销毁

int age = 20; //等价于 auto int age = 20;
  • 局部变量static:修饰局部变量,不会被销毁,由于下面代码可以看得出来Block外部修改static修饰的局部变量,依然可以影响Block内部的值

static int height = 30;
int age = 20 ;
void (^block)(void) = ^{NSLog(@"age us %d height = %d", age, height);
};
age = 25;
height = 35;
block();
//运行后发现是结果为 20  35

解释:

  1. 对于auto类型的局部变量,闭包会拷贝变量的值到闭包内部,形成值捕获(当闭包定义时,会保存这个值的副本)

  1. 对于static修饰的静态变量,闭包会引用静态变量的地址,形成引用捕获(静态变量存储在全局静态区,闭包保存的是他的内存地址,当执行修改变量的值时,是修改静态区的值,闭包通过地址访问到新值35)

  • 全局变量:全局变量不能也无需捕获到Block内部,因为全局变量是存放在全局静态区的区,直接访问即可,缺点就是内存开销大

在Block内部如何修改Block外部变量?

通常需要_block关键字来声明外部变量,以便于在Block内部对外部变量进行修改,使用这个关键字可以使外部变量在Block内部变为可变,允许对其进赋值操作

在使用_block关键字声明外部变量时,需要注意内存管理的问题,特别是在ARC环境下,避免出现循环引用或者内存泄露的情况,要在适当的时候解除对Block的强引用,以避免出现循环引用的问题,实现代码的正确性和稳定性

捕获的底层原理

1.对于auto类型的局部变量,底层会生成一个结构体,包含变量的副本,闭包被定义时age = 20被拷贝到结构体中,后续修改外部age不影响结构体中的值

struct BlockStruct {int age;//保存捕获的age的值void (*invoke)(struct BlockStruct *self);
}

2.对于static修饰的静态变量,底层生成的结构体不会拷贝副本,直接使用全局地址,闭包通过地址height访问全局静态区的值,修改后闭包能开到最新的值

struct BlockStruct {int* height;void (*invoke)(struct BlockStruct* self);
};
  • 如何让局部变量被引用捕获?

如果希望局部变量同样被引用捕获,可以使用_block关键字

_block int age = 20;

Block的分类

根据存储位置分类

  • 栈上的Block:默认情况下,存储在栈上,当Block离开作用域时会被销毁

  • 堆上的Block:通过调用copy方法,可以将栈上的Block复制到堆上,以延长Block的使用周期

栈上的Block

  1. 特点

    • 默认情况下,Block储存在栈上

    • 栈上的Block在定义他的作用域内有效,当作用域结束时,Block会被销毁

    • 栈上的Block不可以跨作用域使用

  1. 内存管理

    • 栈上的Block不需要手动管理内存,由系统自动管理

    • 当Block被复制到堆上时,系统会自动将其从栈上复制到堆上,以延长Block的生命周期

  2. 注意:将栈上的Block传递给异步执行的方法时,需要注意避免在Block执行过程中访问已经释放的栈上变量,可以通过将Block复制到堆上来避免此问题。(只要Block的执行时机可能晚于其定义所在的函数作用域,可就必须将其复制到栈上,避免访问已经释放的Block)

堆上的Block

  1. 特点

    • 通过调用copy方法,可以将栈上的Block复制到堆上

    • 堆上Block的生命周期可以延长,不会受到作用域的限制

    • 堆上的Block可以在不同的作用域中传递和使用,不会因为作用域结束而失效

  2. 内存管理

    • 堆上的Block需要手动管理内存,需要在不使用Block时手动释放

    • 在ARC环境下,系统会管理Block的内存,无需手动调用copy和release

  3. 当Block捕获外部变量时,如果Block存储在堆上,需要注意循环引用问题,可以使用_weak修饰符来避免循环引用

总的来说,栈上的Block在作用域内有效,适合用于临时的、局部的逻辑处理;而堆上的Block可以延长生命周期,适合在不同作用域中传递和复用。

Block的三种类型(底层)

  1. NSGlobalBlock:存储在全局区,Block不捕获任何外部变量时自动生成,无需copy,生命周期与程序一致

  1. NSStackBlock:存储在栈区(随函数返回自动销毁),Block捕获外部变量时默认生产

  2. NSMallocBlock:存储在堆区(需要手动管理内存或依赖ARC),通过copy将NSStackBlock复制到堆上

区分栈上和堆上的Block

  1. 使用NSLog打印Block的地址

  1. 使用_block变量

    • 栈上的block捕获block变量时,变量的值会被Block捕获,但是在作用域结束之后,block的值会被更新为Block执行时的值

    • 堆上的Block捕获_block时,变量的值会复制到堆上的Block中,作用域结束后 _block的值不会被更新

    _block的双重存储:当 _block被堆上的block捕获时,变量的初始值会被复制到堆上的Block中(就是一个副本)

  1. 使用Block_copy函数:

    • 栈:对于栈上的Block使用Block_copy函数会将其复制到堆上,返回一个新的堆上

    • 堆:仍会返回一个新的堆上的Block,地址不同

  2. 使用_weak修饰符

    • 栈上的Block捕获到_weak变量时,变量会被自动置为nil,因为栈上的block不会强因为用 _weak变量

    • 堆上的Block捕获到-weak变量时,变量会正常工作,因为堆上的Block会强引用_weak变量

Block的循环引用

循环引用是指两个或者多个对象之间相互持有对方的强引用,导致他们无法被释放从而造成内存泄漏,特别是在Block中捕获了外部的对象并且外部的对象又持有了block

示例:

@interface ViewController : UIViewController
@property (nonatomic, copy) void(^myBlock)(void);
@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.myBlock = ^ {//Block中捕获了self,导致循环引用[self doSomething];}
}
​
- (void)doSomething {NSLog(@"ppppp");
}

在上面代码中,ViewController的实例持有了一个Block,并且在Block中捕获了self,导致了循环引用

解决办法:

1.使用_weak修饰符

_weak typedef(self) weakSelf = self;
self.myblock = ^{[weakSelf doSomthing];
}

2.使用_block修饰符,可以让Block持有一个弱引用指针

什么是异步执行?

异步执行方法是一种程序执行模式,指方法或函数的调用不会阻塞当前线程的后续操作,而是在另一个线程或队列中独立执行。

其实笔者还没学到多线程的内容等后面学了讲解

http://www.dtcms.com/wzjs/501981.html

相关文章:

  • 网站建设 资讯动态代写文章接单平台
  • 湖南网站建设的公司排名北京网站优化服务商
  • 视觉冲击力的网站设计企业网站优化外包
  • 大庆百度做网站多少钱seo服务的内容
  • 做网站需要注册什么公司成品视频直播软件推荐哪个好一点
  • 外贸网站建设 推广网站统计数据分析
  • 网站开发mvc架构公众号推广引流
  • 网站建设技术代码手机百度seo怎么优化
  • 海山免费网站建设app网络推广方案
  • 医院网站php源码营销网页设计公司
  • 网站背景视频是怎么做的高端网站建设专业公司
  • 雕塑网站源码全国疫情高峰感染高峰进度
  • 如何做网站title小标图惠州网站营销推广
  • 广州大型网站建设公司排名百度指数入口
  • 中国建设银行海南省分行网站网络营销课程设计
  • 本地网站怎么做网络营销是什么工作主要干啥
  • 北京 科技网站建设windows7优化大师
  • 大连发现2例阳性企业网站seo排名
  • 网页报价表强强seo博客
  • 用模板做企业网站seo快速排名上首页
  • 重庆顶呱呱网站建设国内优秀网页设计赏析
  • 做网站首先必须切割图片吗网站设计用什么软件
  • 抚顺网站建设7113活动推广方案策划
  • 深圳网站开发的公司站长工具在线查询
  • 如何做隐藏网站的二维码百度推广话术全流程
  • 未来做那些网站能致富码迷seo
  • 房产网站建设推广谷歌浏览器搜索入口
  • 铜川做网站的公司电话济南网站制作平台
  • 如何在凡科上做网站昆明排名优化
  • 网站如何做品牌营销品牌营销平台