Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSHashTable weakObjectsHashTable – added object is not zeroed

I'm trying to understand how ARC and NSHashTable weakObjectsHashTable works. The objects I add to the hash table should be removed/zeroed or whatever they become once the object has been deallocated. The code example below in its NSLog shows that the object still exists in the hash table. What am I doing wrong?

#import <Foundation/Foundation.h>

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        NSHashTable *hashTable = [NSHashTable weakObjectsHashTable];

        @autoreleasepool
        {
            NSString *str = @"Hello World!";
            [hashTable addObject:str];
            str = nil;
        }

        NSLog(@"hashTable:%@", [hashTable allObjects]);
        // prints: hashTable:("Hello World!") – but should be empty?
    }
}
like image 410
StackUnderflow Avatar asked Dec 12 '25 11:12

StackUnderflow


2 Answers

To assign nil object it does not affect the result. NSString *str = @"Hello World!"; object reference is not weak! Apple's documents says: If there are no strong references to objects within such a hash table, those objects are deallocated.

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Collections/Articles/Sets.html#//apple_ref/doc/uid/20000136-CJBDHAJD

like image 125
anarchist Avatar answered Dec 14 '25 01:12

anarchist


Try this piece of code for OS X console application:

//
//  main.m
//  

#import <Foundation/Foundation.h>

uint objectsAlive = 0;
uint totalObjects = 0;

@interface TestObject : NSObject
@end

@implementation TestObject
{
    uint myIx;
}

- (id)init
{
    // NSAssert([NSThread currentThread] == [NSThread mainThread], @"Not on the main thread");

    self = [super init];
    if (self)
    {
        objectsAlive++;
        totalObjects++;

        myIx = totalObjects;

        NSLog(@"Object with id=%u created; alive objects %u", myIx, objectsAlive);
    }

    return self;
}

- (void)dealloc
{
    objectsAlive--;
    NSLog(@"Object  with id=%u is being destroyed by ARC; alive objects will become %u", myIx,objectsAlive);
}

@end

int main(int argc, const char * argv[]) {

    // default global autorelease pool
    @autoreleasepool {

        NSHashTable * testHashMap = [NSHashTable weakObjectsHashTable];
        // weakObjectsHashTable - according to Apple docs, entries are not necessarily purged right away when the weak object is reclaimed, and we can observe this behavior here - some entries stay alive until last autorelease

        // comment out the line above and uncomment the line below to observe different behavior with strong references in NSHashTable
        // NSHashTable * testHashMap = [[NSHashTable alloc] init];

        // nested autoreleasepool to ensure that the objects added to the testHashMap are released by ARC
        @autoreleasepool {

            for(int i = 0; i < 10;i++) {
                TestObject * obj = [[TestObject alloc] init];
                [testHashMap addObject: obj];
                NSLog(@"Count in hash table inside additions scope is %lu",
                      (unsigned long)testHashMap.count);
            }

            NSLog(@"Count in hash table inside @autoreleasepool is %lu",
                  (unsigned long)testHashMap.count);
            NSLog(@"Objects in hash table inside of @autoreleasepool are %@",
                  testHashMap.allObjects);
            NSLog(@"Exiting inner autorelease pool...");

        }

        // objects in NSHashTable also were released, according to dealloc logs in TestObject, but count is still lagging behind (shows 2)
        NSLog(@"Count in hash table outside of @autoreleasepool is %lu",
              (unsigned long)testHashMap.count);

        // this should indeed show that NSHashTable with weakObjectsHashTable is empty, despite count=2
        NSLog(@"Objects in hash table outside of @autoreleasepool are %@",
              testHashMap.allObjects);

        NSLog(@"Exiting outer autorelease pool, ecpect all objects in strong ref NSHashTable to die...");
    }

    return 0;
}

You should see that the hashmap indeed is empty and objects get correctly destroyed right inside the for loop where their strong references are abandoned. But the problem is with .count property - it lies, telling that there are entries although allObjects return none.

like image 39
JustAMartin Avatar answered Dec 14 '25 00:12

JustAMartin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!