iOS中Block介绍(二)内存管理与其他特性

news/2024/7/20 13:40:14 标签: 内存管理

为什么80%的码农都做不了架构师?>>>   hot3.png

一、block放在哪里

我们针对不同情况来讨论block的存放位置:

1.栈和堆

以下情况中的block位于堆中:

void foo()  {      __block int i = 1024;      int j = 1;      void (^blk)(void);      void (^blkInHeap)(void);      blk = ^{ printf("%d, %d\n", i, j);};//blk在栈里      blkInHeap = Block_copy(blk);//blkInHeap在堆里  }     - (void)fooBar  {      _oi = 1;      OBJ1* oj = self;      void (^oblk)(void) = ^{ printf("%d\n", oj.oi);};      void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中  }

2.全局区

以下情况中的block位于全局区:

static int(^maxIntBlock)(int, int) = ^(int a, int b){return a>b?a:b;};  - (void)fooBar  {       int(^maxIntBlockCopied)(int, int) =[maxIntBlock copy];  }  void foo()  {       int(^maxIntBlockCopied)(int, int) = Block_copy(maxIntBlock);  }

需要注意的是,这里复制过后的block依旧位于全局区,实际上,复制操作是直接返回了原block对象。

二、block引用的变量在哪里

 1.全局区

全局区的变量存储位置与block无关:

static int gVar = 0;  //__block static int gMVar = 1;  void foo()  {      static int stackVar = 0;  //    __block static int stackMVar = 0;  }

注意:static变量是不允许添加__block标记的

2.堆栈

此时,你可能会问,当函数foo返回后,栈上的j已经回收,那么blkInHeap怎么能继续使用它?这是因为没有__block标记的变量,会被当做实参传入block的底层实现函数中,当block中的代码被执行时,j已经不是原来的j了,所谓物是人非就是这样吧~

另外,如果使用到变量j的所有block都没有被复制至heap,那么这个变量j也不会被复制至heap。

因此,即使将j++这一句放到blk()这句之前,这段代码执行后,控制台打印结果也是:1024, 1。而不是1024, 2

三、其他特性

1.复制的行为

对block调用复制,有以下几种情况:

1.对全局区的block调用copy,会返回原指针,并且这期间不处理任何东西(至少目前的内部实现是这样);

2.对栈上的block调用copy,每次会返回新复制到堆上的block的指针,同时,所有__block变量都会被复制至堆一份(多次拷贝,只会生成一份)。

3.对已经位于heap上的block,再次调用copy,只会增加block的引用计数。

为什么我们不讨论retian的行为?原因是并没有Block_retain()这样的函数,而且objc里面的retain消息发送给block对象后,其内部实现是什么都不做。

2.objc类中的block复制

objc类实例方法中的block如果被复制至heap,那么当前实例会被增加引用计数,当这个block被释放时,此实例会被减少引用计数。

但如果这个block没有使用当前实例的任何成员,那么当前实例不会被增加引用计数。这也是很自然的道理,我既然没有用到这个instance的任何东西,那么我干嘛要retian它?

我们要注意的一点是,我看到网上有很多人说block引起了实例与block之间的循环引用(retain-cycle),并且给出解决方案:不直接使用self而先将self赋值给一个临时变量,然后再使用这个临时变量。

但是,大家注意,我们一定要为这个临时变量增加__block标记


转载于:https://my.oschina.net/jilin/blog/402358


http://www.niftyadmin.cn/n/1594231.html

相关文章

Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台

以上代码,通过分布式锁过期时间有效期10s来保障业务逻辑有足够的执行时间;采用try-finally语句块保证锁一定会及时释放。业务代码内部也对库存进行了校验。看起来很安全啊~ 别急,继续分析。。。 需要更多大厂面试资料的话也可以[点击直接进入…

python简单程序设计题_Python程序设计习题与答案

《Python程序设计》习题与参考答案第1章 基础知识简单说明如何选择正确的Python版本。 答:在选择Python的时候,一定要先考虑清楚自己学习Python的目的是什么,打算做哪方面的开发,有哪些扩展库可用,这些扩展库最高反复安…

常见职位的英文简称_各种职位的英文简称都是什么?

展开全部1、HRhuman resource英[ˈhju:mən riˈsɔ:s] 美[ˈhjumən ˈriˌsɔrs][词典] [计] 人的资源;[例句]Human Resource Management is the strategic and coherent approach to the management of an organisations human capital.人力资源管理是战略和一致的方法…

iOS8 运行时机制 objc_msgSend 报错解决方案

iOS8 运行时机制 objc_msgSend 报错解决方案最近几天用了一些第三方开发的类库,在Swift语言和OC 语言下也碰到了各种问题,这不昨天又报错了总体是我objc_msgSend 这个方法出现错误错误代码:objc_msgSend(self.beginRefreshingTaget, self.beg…

Redis持久化方式RDB技术原理?一文带你从底层彻底吃透

Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中以某种形式同步到硬盘中,这一过程就是持久化。 我们知道redis中缓存的数据都存放在内存中,一旦服务故…

java mutex_JAVA互斥锁(synchronizedLock):行为分析及源码

JVM中有这样一段注释:// The base-class, PlatformEvent, is platform-specific while the ParkEvent is// platform-independent. PlatformEvent provides park(), unpark(), etc., and// is abstract -- that is, a PlatformEvent should never be instantiated e…

Android如何自定义头像控件

2019独角兽企业重金招聘Python工程师标准>>> 如上图效果: 效果分析 根据上面的效果,我们目测需要自定义两个控件,一个就是我们的可自由缩放移动的ImageView,一个就是那个白色的边框;然后一起放置到一个Rela…

Redis高频面试题汇总(2021最新版)

这个我的理解大致是这样的面试官!! Redis有5种基本数据类型它们分别是String、List、Hash、Set、ZSet;此外还有三种特殊数据类型Bitmaps、Geospatial、HyperLogLog | 数据类型 | 简单描述 | 使用场景 | | — | — | — | | String | stri…