2015-07-09 3 views
11

Ich habe eine schwache NSPointerArray mit einigen NSObject, die veröffentlicht wurde. Vor dem Aufruf von compact, was ich sehe, ist:NSPointerArray seltsame Verdichtung

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

) 

den Sinn macht, aber was seltsam ist wirklich ist, dass, wenn ich compact auf diesem Array nenne ich die gleichen Werte sehen! Count gibt immer noch 1 zurück und pointerAtIndex:0 ist nil.

Warum wurde die Null nicht entfernt?

EDIT

Hier ist der vollständige Code (ja es 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]); 
} 

und Protokolle:

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) 

Warum die compact Methode löscht nicht die ersten Zeiger? Es ist eindeutig ein nil vor dem Anruf compact.

+0

Wie haben Sie 'ein NSObject, das freigegeben wurde 'in das Pointer-Array eingefügt? Und verwenden Sie weakObjectsPointerArray? –

+0

@KazukiSakamoto könntest du bitte meine aktualisierte Frage oben betrachten? –

Antwort

9

Der Grund dafür ist, dass zuerst -compact überprüft, ob ein internes Flag 'needsCompaction' gesetzt ist. Wenn es nicht ist, ist es früh genug. Das Flag wird nur dann gesetzt, wenn ein Nullzeiger direkt über die öffentliche Schnittstelle in das Array eingefügt wird. Es wird nicht gesetzt, wenn ein schwach referenziertes Objekt nach dem Einfügen des Zeigers in das Array freigegeben wird (und der Zeiger nicht gesetzt ist).

Um dieses Verhalten zu umgehen, ist es sinnvoll, vor dem Aufruf von -compact einen Nullzeiger an das Array anzuhängen. Nicht ideal, aber es wird funktionieren.

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

Vielen Dank für diese Antwort. Es war sehr nützlich für mich. –