自动引用计数:快速枚举出错

13

在将以下代码更新为iOS 5的自动引用计数时,当尝试执行快速枚举以便使用“foreach”循环遍历实现类时,发生了一个错误,即在将缓冲区分配给“state->itemPtr”时发生错误。我遇到的错误是“将'__autoreleasing id *'分配给'__unsafe_unretained id *'更改了指针的保留/释放属性”。请参见带有注释的代码行。

/*
 * @see http://cocoawithlove.com/2008/05/implementing-countbyenumeratingwithstat.html
 * @see http://www.mikeash.com/pyblog/friday-qa-2010-04-16-implementing-fast-enumeration.html
 */
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state objects: (id *)buffer count: (NSUInteger)bufferSize {
    NSUInteger arrayIndex = (NSUInteger)state->state;
    NSUInteger arraySize = [_tuples count];
    NSUInteger bufferIndex = 0;

    while ((arrayIndex < arraySize) && (bufferIndex < bufferSize)) {
        buffer[bufferIndex] = [_tuples objectAtIndex: arrayIndex];
        arrayIndex++;
        bufferIndex++;
    }

    state->state = (unsigned long)arrayIndex;
    state->itemsPtr = buffer; // Assigning '__autoreleasing id *' to '__unsafe_unretained id*' changes retain/release properties of pointer
    state->mutationsPtr = (unsigned long *)self;

    return bufferIndex;
}
在这个例子中,_tuples变量是类型为NSMutableArray的实例变量。 我该如何解决这个错误?
2个回答

15

您需要将缓冲区更改为__unsafe_unretained

- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state
                                   objects: (id __unsafe_unretained *)buffer
                                     count: (NSUInteger)bufferSize

源代码

编辑:消除mutationPtr错误的简单方法:

state->mutationsPtr = &state->extra[0];

然而,在我执行了“转换为Objective-C ARC”之后,Xcode将“state->mutationsPtr = (unsigned long )self;”更改为“state->mutationsPtr = (__bridge unsigned long *)self;”。现在这导致了另一个错误,错误提示为“使用__bridge强制类型转换将const __strong类型转换为unsigned long不兼容”。有什么建议吗? - Ziminji
1
state->mutationsPtr 不应该用于存储 self,它应该指向额外的字段(简单方式)以便不使用,或者指向您的类中某种在集合更改时发生变化的内部值(困难方式)。我将编辑答案以包括简单的方法。 - Daniel
1
这真的有效吗?不同地定义“objects”参数?在我的系统上会导致编译器错误 - 它与声明不匹配。 - Todd Lehman
NSEnumerator.h 中的定义是 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len; - Steven Fisher

1

Ziminji,

我遇到了同样的问题,这也是我看到这个问题的原因。

我通过保留objects参数的定义(例如,将其保留为id *),并使用空指针进行双重转换来解决了这个问题。

因此,虽然这对我产生了错误:

state->itemsPtr = (__unsafe_unretained id *)buffer  // Error

这个工作得非常好:

state->itemsPtr = (__unsafe_unretained id *)(void *)buffer  // No error

免责声明:我不是ARC专家,不能保证这不会导致引用计数问题。但是,在我的测试中它似乎能够正确工作,并且编译时没有警告。

顺便说一下,我发现这篇两部分的博客深入介绍了快速枚举:

还有这篇关于__unsafe_unretained的博客:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接