3

我在 Objective-C 中使用 ^blocks 时遇到了一些问题。我正在尝试从一个块中设置一个实例变量 - 我已经阅读了一些关于该主题的 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

上面的代码给出了以下输出: ( "This is a string." ) (null)

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

如何从块内成功设置文件名对象?提前致谢。

4

1 回答 1

4

预选赛的作用:

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

__weak是对阻止对象被释放的对象的引用。

__strong是对阻止对象被释放的对象的引用。

你需要做什么:

__weak不会做你想做的事,因为它不会阻止你的数组在当前范围结束后被解除分配。由于您正在进行异步调用,因此没有什么可以阻止运行时在执行块之前回收数组使用的内存。

__strong将在当前范围结束后保留​​对象。这就是你想要的。

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

在引用计数环境中,默认情况下,当您在块中引用 Objective-C 对象时,它会被保留。即使您只是引用对象的实例变量也是如此。但是,使用 __block 存储类型修饰符标记的对象变量不会被保留。

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

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

我认为您的问题出在此处(相关部分以粗体表示):

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

__block 变量存在于变量的词法范围和在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。因此,如果在帧中声明的块的任何副本在帧结束后仍然存在(例如,通过在某处排队以供稍后执行),则存储将在堆栈帧的破坏中幸存下来。给定词法范围内的多个块可以同时使用一个共享变量。

作为一种优化,块存储从堆栈开始——就像块本身一样。如果块是使用 Block_copy 复制的(或者在 Objective-C 中,当块被发送一个副本时),变量被复制到堆中。因此,__block 变量的地址会随着时间而改变。

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

而不是一个NSMutableArray,尝试使用一个普通的NSArrayusing

+ (id)arrayWithObject:(id)anObject.

于 2012-04-09T15:44:11.607 回答