从^块访问属性会导致愚蠢的行为

时间:2012-04-09 15:07:36

标签: iphone objective-c block asiformdatarequest

我在Objective-C中使用^块遇到了一些问题。我正在尝试从块中设置一个实例变量 - 我已经阅读了关于该主题的一些Apple文档,我觉得我已经尝试了所有内容。

@interface MyClass
{
    // I have tried all possible combinations using __weak, __strong and __block.
    __weak __block NSMutableArray *filenames;
}

// *.m
static ASIFormDataRequest *g_request = nil;

@implementation MyClass
-(void) funnymethod
{
    filenames = [NSMutableArray array];
    [filenames addObject:@"This is a string."];
    NSLog(@"%@", filenames);

    g_request = [InitializerClass initializeRequest];
    [g_request setCompletionBlock:^
    {
        filenames = [NSMutableArray array];
        [filenames addObject:@"This is another string."];
        NSLog(@"%@", filenames);
    }];

    [g_object startASynchronous];
}
@end

上面的代码给出了以下输出:     (“这是一个字符串。”)     (空)

太糟糕了。所以,我尝试了__weak,__strong和__block的不同组合 - 其他任何东西都给出了以下输出:     (“这是一个字符串。”)     (“这是另一个字符串。”) 但!有一个巨大的但是。完成块永远不会退出。顶部栏中的活动指示器指示打开的连接保持旋转,屏幕变得无响应。

如何成功设置块内的filenames-object?提前谢谢。

1 个答案:

答案 0 :(得分:4)

限定符的作用:

__block此限定符允许闭包修改存储在给定变量中的值。

__weak是对阻止对象取消分配的对象的引用。

__strong是对 阻止对象取消分配的对象的引用。

您需要做什么:

__weak无法执行您想要的操作,因为它不会阻止您的数组在当前范围结束后被取消分配。由于您正在进行异步调用,因此没有什么能阻止运行时在执行块之前回收数组使用的内存。

__strong会将对象保留在当前范围的末尾。这就是你想要的。

__block将允许您的块修改指定的变量,但是在引用实例变量时不需要这样做,因为self将自动保留。

  

在引用计数环境中,默认情况下引用时   一个块内的Objective-C对象,它被保留。这甚至是真的   如果您只是引用对象的实例变量。宾语   但是,使用__block存储类型修饰符标记的变量是   不保留。

     

注意:在垃圾收集环境中,如果同时应用__weak和   __block修饰符到一个变量,然后该块将无法确保它保持活动状态。如果你在一个实现中使用一个块   方法,对象实例变量的内存管理规则   更微妙:

     

如果您通过引用访问实例变量,则会保留self;

我认为您的问题在于此处(粗体中的相关部分):

  

您可以通过应用__block存储类型修饰符指定导入的变量是可变的 - 即读写 - __block存储与寄存器类似,但互相排斥,自动,以及局部变量的静态存储类型。

     

__块变量存在于变量的词法范围与声明的所有块和块副本之间共享的存储中   在变量的词法范围内创建。因此,存储将   如果块的任何副本,则在堆栈帧的破坏中存活   在框架内声明超出框架的末尾(for   例如,通过在某处加入队伍以便以后执行)。多   给定词法范围内的块可以同时使用共享   变量。

     

作为优化,块存储从堆栈开始 - 就像   阻止自己做。如果使用Block_copy复制块(或在   Objective-C当块发送副本时),变量被复制到   堆。因此,__block变量的地址可以转换   时间。

     

对__block变量还有两个限制:它们不能   是可变长度数组,并且不能是包含C99的结构   可变长度数组。

而不是NSMutableArray,请尝试使用普通NSArray

+ (id)arrayWithObject:(id)anObject