NSPointerArray奇怪的压缩

14

我有一个弱 NSPointerArray,其中包含一些已经被释放的 NSObject。在调用 compact 之前,我看到的是:

(lldb) po [currentArray count]
1
(lldb) po [currentArray pointerAtIndex:0]
<nil>
(lldb) po [currentArray allObjects]
<__NSArrayM 0x16f04f00>(

)

听起来很有道理,但真正奇怪的是,当我在那个数组上调用compact时,我看到的值仍然相同!计数仍然返回1,而pointerAtIndex:0nil

为什么nil没有被移除呢?

编辑

这是完整代码(是的,它是XCTest框架):

- (void)testCompaction {
    __weak id testingPointer = nil;

    NSPointerArray *weakArray = [NSPointerArray weakObjectsPointerArray];

    @autoreleasepool {

        NSObject *someObj = [[NSObject alloc] init];

        testingPointer = someObj;

        [weakArray addPointer:(__bridge void*)testingPointer];

        NSLog(@"before compaction inside autorelease: testingPointer = %@ count = %d, allObjects = %@, pointerAtIndex:0 = %@, pointerAtIndex:0 class = %@", testingPointer, [weakArray count], [weakArray allObjects], [weakArray pointerAtIndex:0], [(id)[weakArray pointerAtIndex:0] class]);

        someObj = nil;
    }

    NSLog(@"before compaction outside autorelease: testingPointer = %@ count = %d, allObjects = %@, pointerAtIndex:0 = %@, pointerAtIndex:0 class = %@", testingPointer, [weakArray count], [weakArray allObjects], [weakArray pointerAtIndex:0], [(id)[weakArray pointerAtIndex:0] class]);

    [weakArray compact];

    NSLog(@"after compaction outside autorelease: testingPointer = %@ count = %d, allObjects = %@, pointerAtIndex:0 = %@, pointerAtIndex:0 class = %@", testingPointer, [weakArray count], [weakArray allObjects], [weakArray pointerAtIndex:0], [(id)[weakArray pointerAtIndex:0] class]);
}

以及日志:

  before compaction inside autorelease: testingPointer = <NSObject: 0x7de7ff80> count = 1, allObjects = (
    "<NSObject: 0x7de7ff80>"
), pointerAtIndex:0 = <NSObject: 0x7de7ff80>, pointerAtIndex:0 class = NSObject
2015-07-20 14:27:14.062 AppetizeSuite copy[54144:9019054] before compaction outside autorelease: testingPointer = (null) count = 1, allObjects = (
), pointerAtIndex:0 = (null), pointerAtIndex:0 class = (null)
2015-07-20 14:27:22.615 AppetizeSuite copy[54144:9019054] after compaction outside autorelease: testingPointer = (null) count = 1, allObjects = (
), pointerAtIndex:0 = (null), pointerAtIndex:0 class = (null)   

为什么compact方法不删除第一个指针?在调用compact之前,这显然是nil


你是如何将已释放的 NSObject 添加到指针数组中的?你是否正在使用 weakObjectsPointerArray - Kazuki Sakamoto
@KazukiSakamoto,你能否请看一下我上面更新的问题? - Łukasz Sromek
3个回答

23

出现这种情况的原因是 -compact 首先检查内部标志位 'needsCompaction' 是否被设置。如果没有设置,它就会直接退出。该标志位只在通过公共接口将空指针直接插入数组时设置。如果弱引用对象被释放(并且指针被清零)后将指针插入数组,则不会设置该标志位。

解决此行为的一个方法是在调用 -compact 之前故意向数组中添加一个空指针。虽然不理想,但可以解决问题。

[pa addPointer:nil]; // forces the pointer array to do compaction next time
[pa compact];

谢谢您的回答。对我来说非常有用。 - Nick Moore

5

0

已经过了几年,使用示例代码没有任何变化。

不过,当使用方法-replacePointerAtIndex:withPointer:执行指针更新时,-compact运行得非常完美。

在上述代码中,替换

someObj = nil;

 [weakArray replacePointerAtIndex:0 withPointer:nil];

[weakArray compact];之后提供了预期的结果,但代码将在最后一个NSLog处崩溃


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