Łukasz Sromek Łukasz Sromek - 1 month ago 9
Objective-C Question

NSPointerArray weird compaction

I have a weak

NSPointerArray
with some
NSObject
that has been released. Before calling
compact
what I see is:

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

)


That makes sense, but what is really weird is that when I call
compact
on that array I see the same values! Count still returns 1 and
pointerAtIndex:0
is
nil
.

Why the nil hasn't been removed?

EDIT

Here's the full code (yeah it's XCTesting framework):

- (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]);
}


and logs:

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)


Why the
compact
method does not delete the first pointer? It's clearly a
nil
before calling
compact
.

Answer

I've seen this same behavior. Here is an open radar bug report: http://www.openradar.me/15396578

Comments