当添加到容器(NSDictionary,NSArray)时,您能帮助我理解块类型吗? [英] Could you help me to understand block types when added to containers (NSDictionary, NSArray)?

本文介绍了当添加到容器(NSDictionary,NSArray)时,您能帮助我理解块类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,块可以是3种类型:NSGlobalBlock,NSStackBlock,NSMallocBlock.让我们以以下示例为例:

Normally blocks can be of 3 types: NSGlobalBlock, NSStackBlock, NSMallocBlock. Lets take the following example:

    void (^aBlock)(NSString *someString) = ^(NSString *someString){
        NSLog(@"Block was executed. %@", someString);
    };
    NSDictionary *dictionary = [NSDictionary dictionaryWithObject:aBlock forKey:@"aBlock"];

因为如果我做 po字典,我会得到

Because aBlock doesn't capture surrounding scope if I do po dictionary I get

aBlock =< NSGlobalBlock :0x165dde60>,这是正确的

aBlock = <NSGlobalBlock:0x165dde60> and this is correct

如果我再这样做:

    NSString *string = @"Test";
    void (^aBlock)(NSString *someString) = ^(NSString *someString){
        NSLog(@"Block was executed. %@ %@", someString, string);
    };
    NSDictionary *dictionary = [NSDictionary dictionaryWithObject:aBlock forKey:@"aBlock"];

然后是 po字典,我得到:

aBlock =< NSMallocBlock :0x165dde60> 这就是令我困惑的

aBlock = <NSMallocBlock:0x165dde60> and this is what confuses me

这不是 NSStackBlock ,而是在执行以下操作时仅成为 NSMallocBlock :

Shouldn't this be a NSStackBlock and only become a NSMallocBlock when I do:

 NSDictionary *dictionary = [NSDictionary dictionaryWithObject:[aBlock copy] forKey:@"aBlock"];

我在使用ARC的iOS 7.1上,据我所知,在向下传递堆栈时,默认情况下不应在ARC中复制块,而应仅在向上传递堆栈(从函数返回)时才复制它们.

I am on iOS 7.1 using ARC and as far as I know blocks should not be copied by default in ARC when passed down the stack and they should be copied only when passed up the stack (returning from a function).

我在这里想念什么?

推荐答案

在这些行上,字典中块对象的类型已经是NSMallocBlock,而不是通过NSDictionary + dictionaryWithObject:forKey:方法复制的.

The type of the block object in the dictionary was already NSMallocBlock on these lines, not from copied by NSDictionary +dictionaryWithObject:forKey: method.

void (^aBlock)(NSString *someString) = ^(NSString *someString){
    NSLog(@"Block was executed. %@ %@", someString, string);
};

在ARC编译环境下,默认情况下,此aBlock变量为__strong.

This aBlock variable is __strong by the default under ARC compilation environment.

__strong void (^aBlock)(NSString *someString) = ^(NSString *someString){
...

因此,块对象由aBlock变量保留.实际上,根据LLVM源代码,编译器发出了 retain 代码,用于将对象存储到该行的__strong变量中.

So the block object was retained by the aBlock variable. Actually, according to LLVM source code, the compiler emitted retain code for storing the object into __strong variable on the line.

  1. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2091
  2. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2109
  3. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1920
  4. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1944
  1. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2091
  2. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2109
  3. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1920
  4. https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1944

EmitARCRetainBlock:

EmitARCRetainBlock:

llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value, bool mandatory) {
    llvm::Value *result = emitARCValueOperation(*this, value,
        CGM.getARCEntrypoints().objc_retainBlock, "objc_retainBlock");

objc_retainBlock 是objc4中的运行时函数.

This objc_retainBlock is a runtime function in objc4.

http://opensource.apple.com/source/objc4/objc4-551.1/runtime/NSObject.mm

id objc_retainBlock(id x) {
    return (id)_Block_copy(x);
}

因此,此_Block_copy将块对象从堆栈复制到堆.

Thus, the block object was copied from stack to heap by this _Block_copy.

除此之外,您还可以使用 __ weak 来查看块对象的 __ NSStackBlock __ 类型.

In addition to this, you can see __NSStackBlock__ type for the block object using __weak.

__weak void (^aBlock)(NSString *someString) = ^(NSString *someString){
    NSLog(@"Block was executed. %@ %@", someString, string);
};

在这种情况下,aBlock变量未保留该块对象,并且该块对象不是普通的Objective-C对象,因此该块对象可以存在于堆栈中.是的,它是 __ NSStackBlock __ 对象.在存储到NSMutableDictionary中之前,可能需要先调用 copy Block_copy .

In this case, the block object was not retained by the aBlock variable, and the block object is not an ordinary Objective-C object, so the block object can exist on stack. Yes, it is __NSStackBlock__ object. You may need to call copy or Block_copy for it ahead of storing into NSMutableDictionary.

这篇关于当添加到容器(NSDictionary,NSArray)时,您能帮助我理解块类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆