- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
以下代码由于EXC_BAD_ACCESS
而崩溃
typedef void(^myBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *tmp = [self getBlockArray];
myBlock block = tmp[0];
block();
}
- (id)getBlockArray {
int val = 10;
//crash version
return [[NSArray alloc] initWithObjects:
^{NSLog(@"blk0:%d", val);},
^{NSLog(@"blk1:%d", val);}, nil];
//won't crash version
// return @[^{NSLog(@"block0: %d", val);}, ^{NSLog(@"block1: %d", val);}];
}
po tmp
在lldb中找到
(lldb) po tmp
<__NSArrayI 0x7fa0f1546330>(
<__NSMallocBlock__: 0x7fa0f15a0fd0>,
<__NSStackBlock__: 0x7fff524e2b60>
)
(lldb) po tmp
<__NSArrayI 0x7f9db481e6a0>(
<__NSMallocBlock__: 0x7f9db27e09a0>,
<__NSMallocBlock__: 0x7f9db2718f50>
)
最佳答案
首先,您需要了解,如果要存储超出声明范围的块,则需要复制该块并存储该副本。
这样做的原因是由于优化,捕获变量的块最初位于堆栈上,而不是像常规对象那样动态分配。 (让我们忽略当前暂时不捕获变量的块,因为它们可以作为全局实例实现。)因此,当您编写块文字(如foo = ^{ ...};
)时,实际上就像为foo
分配了指向已声明的隐藏局部变量的指针一样在相同的作用域中,类似于some_block_object_t hiddenVariable; foo = &hiddenVariable;
这样的优化在许多情况下可以减少对象分配的数量,这些情况是同步使用块的,并且永远不会超过创建它的作用域。
就像指向局部变量的指针一样,如果将指针移出它所指向的对象的范围之外,则将有一个悬空的指针,对其取消引用会导致未定义的行为。在块上执行复制会在必要时将堆栈移动到堆,与其他所有Objective-C对象一样,在此处对其进行内存管理,并返回指向堆副本的指针(并且如果该块已经是堆块或全局块, ,它只是返回相同的指针)。
特定的编译器是否在特定情况下使用此优化是实现细节,但是您不能假设其实现方式,因此,如果将块指针存储在比当前作用域更长的位置,则必须始终进行复制(例如,在实例或全局变量中,或者在可能超出范围的数据结构中)。即使您知道它是如何实现的,并且知道在特定情况下也不需要复制(例如,它是一个不捕获变量的块,或者必须已经完成复制),您也不应依赖它,并且好的做法是,在将其存储在比当前范围更长的位置时,仍应始终进行复制。
将块作为参数传递给函数或方法有点复杂。如果将块指针作为参数传递给函数参数,该函数参数的声明编译时类型为块指针类型,则该函数将负责复制它,如果它的作用域超出其范围。因此,在这种情况下,您无需担心复制它,而无需知道函数的功能。
另一方面,如果将块指针作为参数传递给声明为编译时类型为非块对象指针类型的函数参数,则该函数将不承担任何块复制责任,因为它所知道的只是一个常规对象,如果将其存储在超出当前范围的地方,则只需保留该对象即可。在这种情况下,如果您认为函数可能在调用结束后存储了该值,则应在传递该块之前复制该块,然后传递该副本。
顺便说一句,在将块指针类型分配或转换为常规对象指针类型的任何其他情况下也是如此。应该复制该块并分配副本,因为不会期望获得常规对象指针值的任何人进行任何块复制注意事项。
ARC使情况变得有些复杂。 ARC规范specifies在某些情况下隐式复制了块。例如,当存储到编译时块指针类型的变量(或ARC需要保留编译时块指针类型的值的任何其他地方)时,ARC要求复制输入值而不是保留,因此程序员在这种情况下不必担心显式复制块。
除了保留是初始化a的一部分
每当有__strong
参数变量或读取__weak
变量
这些语义要求保留块指针类型的值,
具有Block_copy
的效果。
但是,作为例外,ARC规范不保证复制仅作为参数传递的块。
当优化程序看到结果是
仅用作呼叫的参数。
因此,是否要显式复制作为参数传递给函数的块仍然是程序员必须考虑的事情。
现在,Apple Clang编译器的最新版本中的ARC实现具有一个未记录的功能,即使ARC规范不需要它,它也会在将块作为参数传递的某些位置添加隐式块副本。 (“undocumented”(因为未找到任何实现此目的的Clang文档。)尤其是,当将块指针类型的表达式传递给非块对象指针类型的参数时,它似乎总是在防御性地添加隐式副本。实际上,正如CRD所演示的那样,当从块指针类型转换为常规对象指针类型时,它还会添加一个隐式副本,因此这是更通用的行为(因为它包括参数传递的大小写)。
但是,当将块指针类型的值作为varargs传递时,当前版本的Clang编译器似乎未添加隐式副本。 C varargs不是类型安全的,调用者不可能知道函数期望的类型。可以说,如果Apple要在安全方面犯错误,由于无法知道功能的期望,因此在这种情况下,他们也应始终添加隐式副本。但是,由于整件事都是未记录的功能,因此我不会说这是一个错误。我认为,程序员永远不要依赖仅作为隐式复制的参数传递的块。
关于ios - 了解objc中 block 存储管理的一种极端情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35822645/
我的 blockly.js 文件中有以下代码 Blockly.Blocks['account_number'] = { // Other type. init: function() {
首先抱歉我的英语不好,我正在开发 Image Splitter 应用程序并且已经完成,但是现在的要求是当图像被分割(分成几 block /chunks)那么图像 block 的每一 block (ch
#value: 消息的返回值,当发送到一个 block 时,是该 block 中最后一句话的值。所以 [ 1 + 2. 3 + 4. ] value 计算结果为 7。我发现有时很难使用。有没有办法显式
我想构建一个包含 3 div 的响应式导航栏相同的 width和 height . 我申请了 inline-block到每个 block ,我得到一个我不理解的行为。 问题是,第三 block 由 2
我希望使用 Blockly 来允许非技术人员用户指定测试脚本。 它的一部分需要一个文件选择器,但是,我看不到 Blockly 有一个。是吗? 实际上,我找不到完整的标准 block 列表。谁有网址?
仅当您位于父 block 内部时,父 block 的 props.isSelected 才为 true,但当您在该 block 的 innerBlocks 内进行编辑时则不然。 如何从父 block
仅当您位于父 block 内部时,父 block 的 props.isSelected 才为 true,但当您在该 block 的 innerBlocks 内进行编辑时则不然。 如何从父 block
我想创建一个具有不同背景颜色 block 和不同悬停颜色 block 的导航栏 block 。我可以分别创建不同的悬停颜色 block 或不同的背景颜色 block ,但不能一起创建。所以请告诉我如何
我正在使用看到的代码 here定期执行代码: #define DELAY_IN_MS 1000 __block dispatch_time_t next = dispatch_time(DISPATC
为什么 block 必须被复制而不是保留?两者在引擎盖下有什么区别?在什么情况下不需要复制 block (如果有)? 最佳答案 通常,当您分配一个类的实例时,它会进入堆并一直存在,直到它被释放。但是,
我想弄清楚我这样做是否正确: 如果我有一个 block ,我会这样做: __weak MyClass *weakSelf = self; [self performBlock:^{
我想制作一个 4 block 导航菜单,虽然我已经显示了一个 block ,然后单击打开第二个 block ,从第二个开始选择并再次单击出现第三个 block ,第四个 block 相同...这是我的
例如,这样更好吗? try { synchronized (bean) { // Write something } } catch (Int
我想让一只乌龟检查前方小块的颜色并决定移动到哪里。如果前面的补丁不是白色的,那么乌龟向左或向右旋转并移动。我的 If 决策结构中出现错误,显示“此处应为 TRUE?FALSE,而不是 block 列表
我想创建一个 block 对角矩阵,其中对角 block 重复一定次数,非对角 block 都是零矩阵。例如,假设我们从一个矩阵开始: > diag.matrix [,1] [,2] [
我是区 block 链新手。突然我有一个问题,我们是否可以通过区 block 号来访问以太坊区 block 链上之前的区 block 数据。 例如我创建了一个block1、block2。 block
我是区 block 链新手。突然我有一个问题,我们是否可以通过区 block 号来访问以太坊区 block 链上之前的区 block 数据。 例如我创建了一个block1、block2。 block
我创建了一个等距环境,全部使用 Javascript 和 HTML5 (2D Canvas),大部分情况下工作正常。我面临的问题是使用不同高度的图 block ,然后对图 block 上的对象索引进行
这是令我困惑的代码: public Integer getInteger(BlockingQueue queue) { boolean interrupted = false; try
我有一个基于 TPL 数据流的应用程序,它仅使用批处理 block 和操作 block 就可以正常工作。 我已经添加了一个 TransformBlock 以尝试在发布到批处理 block 之前从源中转
我是一名优秀的程序员,十分优秀!