block引发的陷阱
block在项目的开发中使用时非常频繁的,苹果官方也极力推荐使用block。其实,究其本质,block就是指向结构体的指针(可利用运行时机制查看底层生成的c代码)。然而在使用block时会存在很多陷阱(主要是内存泄露),这些都是必须要注意的。接下来举个简单的实例:
假设一个类,拥有两个属性:block和name;
//
// SZBlocTest.h
// block引发的内存泄漏
//
// Created by mac on 14-6-17.
// Copyright (c) 2014年 shunzi. All rights reserved.
// #import <Foundation/Foundation.h> @interface SZBlocTest : NSObject @property (nonatomic, copy) void(^block)(); @property (nonatomic, copy) NSString *name; @end
在这之前,先解释下block为什么使用copy来修饰?其主要原因如下:
在普通情况下,任何block,都是存在于栈中,这也意味着,其生命周期由系统管理,不需要我们手动管理.这就存在一个问题,那就是我们如果使用block保存一段代码块,欢乐的等待被回调的时候,说不定在之前就已经被系统回收了!
那么,如何让block存储到堆中呢?方法就是使用copy来修饰,做一次复制.(如果使用retain的话,只会将其计数器加一,多做一次强引用,但不会重新分配新的内存,所以,依然存在于栈中).
此时,产生第二个问题:如果在block中调用持有它的对象(有点绕,理解下),就会产生循环引用,造成内存泄漏!例如:
//
// SZBlocTest.m
// block引发的内存泄漏
//
// Created by mac on 14-6-17.
// Copyright (c) 2014年 shunzi. All rights reserved.
//
#import "SZBlocTest.h" @implementation SZBlocTest
- (id)init
{
if (self = [super init]) {
self.block = ^{
NSLog(@"%@",_name);
NSLog(@"%@",self->_name);
NSLog(@"%@",self.name);
};
}
return self;
}
@end
以上代码中,block中使用的
15 NSLog(@"%@",_name);
16 NSLog(@"%@",self->_name);
17 NSLog(@"%@",self.name); 都会引发循环引用,其中15与16行,是等同的;为什么会引发循环引用呢?
因为,block存在于堆中,在其代码块中引用的对象都会产生一个強指针.而这时候问题就产生了,因为block本身就被其引用的对象(copy)强指针指向着.这样就造成了双方都无法释放,从而造成了内存泄漏. 解决方案如下:
- (id)init
{
if (self = [super init]) {
__unsafe_unretained SZBlocTest *temp = self;
// __weak SZBlocTest *temp = self;
self.block = ^{
NSLog(@"%@",temp->_name);
NSLog(@"%@",temp.name);
};
}
return self;
}
这时候,很多细心的人就会注意到,第五行的被注释的代码
__weak SZBlocTest *temp = self;
和上面的
__unsafe_unretained SZBlocTest *temp = self;
有什么区别呢?
简单说就是,unsafe,为什么不安全呢?因为当其所修饰的对象释放时,它并不知道,所以,其地址依然存在,不会清为nil,这样第七行代码
temp->_name
是可以访问的(在使用时也应当注意这个细节),而使用weak修饰的话,当其修饰的对象被释放时,temp会被清为nil,这样就会出现nil->_name的情况.这是不允许的.
如果想要了解
__unsafe_unretained和__weak的具体区别的话,可查阅其它资料.
block引发的陷阱的更多相关文章
- ie、firefox、chrome中关于style="display:block" 引发的页面布局错乱的解决办法
ie.firefox.chrome中关于style="display:block" 引发的页面布局错乱的解决办法: table中tr 添加style="display:b ...
- for...else: 一个程序引发的陷阱
python3菜鸟教程有一段关于for循环和else搭配的代码: for n in range(2, 10): for x in range(2, n): if n % x == 0: print(n ...
- 由ASIHttpRequest里的block引发的思考
项目发http请求,现在一般的都是用的第三方开源库,当然发异步请求时我们也会写几个回调函数来进行请求返回时的处理.不过前段时间看一个朋友写的代码,里面很用block简单的实现了回调相关的部分.比如: ...
- Foundation: NSNotificationCenter
一个NSNotificationCenter对象(通知中心)提供了在程序中广播消息的机制,它实质上就是一个通知分发表.这个分发表负责维护为各个通知注册的观察者,并在通知到达时,去查找相应的观察者,将通 ...
- 自然对数e(转)
e表示增长的极限 e=limx→+∞ (1+1/x)^x≍2.71828 假设,一根竹子,第一天是1米,第二天长了1米,然后这根柱子的长度变成了2米.相当于 (1+1/1)^1.上面这个假设,如果仔细 ...
- Python 的上下文管理器是怎么设计的?
花下猫语:最近,我在看 Python 3.10 版本的更新内容时,发现有一个关于上下文管理器的小更新,然后,突然发现上下文管理器的设计 PEP 竟然还没人翻译过!于是,我断断续续花了两周时间,终于把这 ...
- C++动态内存管理与源码剖析
引言 在本篇文章中,我们主要剖析c++中的动态内存管理,包括malloc.new expression.operator new.array new和allocator内存分配方法以及对应的内存释放方 ...
- Java 进阶6 异常处理的陷阱
Java 进阶6 异常处理的陷阱 20131113 异常处理机制是 Java语言的特色之一,尤其是 Java的Checked 异常,更是体现了 Java语言的严谨性:没有完善的错误的代码根本就不会被执 ...
- block的哪些事 --- 学习笔记十
//带有自动变量值的匿名函数 //block 与 C语言函数比只有两点不同,1.没有函数名. 2.带有"^". //类似于方法,如B中的值传给A中,在B中,一. 定义 : 二. 实 ...
随机推荐
- Matlab最短路径问题记录
利用graphshortestpath 可以求最短路径,具体用法参考MATLAB帮助 S=[1 1 2 2 3 3 4 4 4 4 5 6 6 7 8]; %起始节点向量 E=[2 3 5 4 4 6 ...
- poj 3734 矩阵快速幂+YY
题目原意:N个方块排成一列,每个方块可涂成红.蓝.绿.黄.问红方块和绿方块都是偶数的方案的个数. sol:找规律列递推式+矩阵快速幂 设已经染完了i个方块将要染第i+1个方块. a[i]=1-i方块中 ...
- POJ 1273 Drainage Ditches -dinic
dinic版本 感觉dinic算法好帅,比Edmonds-Karp算法不知高到哪里去了 Description Every time it rains on Farmer John's fields, ...
- IOS基础之 (十五)知识点
一 SEL 1. 方法的存储位置 每个类的方法地址列表都存储在类对象中. 每个方法都有一个与之对应的SEL类型的对象. 根据一个SEL对象就可以找到方法的地址,进而调用方法. Person.h #im ...
- POJ3267 The Cow Lexicon(DP+删词)
The Cow Lexicon Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9041 Accepted: 4293 D ...
- jquery------导入jquery.2.2.3.min.js
问题: 导入jquery.2.2.3.min.js后MyEclipse会提示代码有错误 方法: 选中jquery.2.2.3.min.js->右键->选择“MyEclipse”中的“Exc ...
- linux下查看当前用户的 三个命令
linux下查看当前用户的 三个命令 1,whoami; 2,id -un; 3,who -H 可以列出当前所有的 NAME (用户名) LINE (窗口列表) TIME(开启时间 ...
- cad2013
## ribbon界面? ribbon界面是一种设计ui, 可以认为是传统的 菜单和工具栏 组合. 是 用于 实时显示 + 面向结果的 设计ui 但并不是所有的程序都适合. ribbon 并不是 ...
- ASP.NET MVC学习笔记-----Bundles
在网页中,我们经常需要引用大量的javascript和css文件,在加上许多javascript库都包含debug版和经过压缩的release版(比如jquery),不仅麻烦还很容易引起混乱,所以AS ...
- js实现剪切、复制、粘贴——clipBoard.js
摘要: 最近项目上要实现一个点击按钮复制链接的功能,刚开始查找了一些资料,找了几款插件,ZeroClipboard是通过flash实现的复制功能,随着越来越多的提议废除flash,于是就想能不能通过j ...