2015-01-18 1 views
3

Я пытаюсь понять, как работает ARC и NSHashTable weakObjectsHashTable. Объекты, которые я добавляю в хеш-таблицу, должны быть удалены/обнулены или что бы они ни появились после того, как объект был освобожден. Пример кода, приведенный ниже в его NSLog, показывает, что объект все еще существует в хеш-таблице. Что я делаю не так?NSHashTable weakObjectsHashTable - добавленный объект не обнуляется

#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? 
    } 
} 
+1

'string' - частный случай, см. Здесь http://stackoverflow.com/questions/10922888/weak-nsstring-variable-is-not-nil-after-setting-the-only-strong-reference-to -nil и попробуйте версию с NSObject. – JustAMartin

ответ

1

Чтобы назначить нулевой объект, он не влияет на результат. NSString * str = @ "Hello World!"; ссылка на объект не слабая! В документах Apple говорится: если нет сильных ссылок на объекты в такой хэш-таблице, эти объекты освобождаются.

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

+0

Но 'str' выходит за рамки, где вызывается NSLog! Разве это не означает, что сильная ссылка (которая является 'str') была уничтожена прямо в' '' перед 'NSLog'? – JustAMartin

1

Попробуйте этот кусок кода для консольного приложения OS X:

// 
// 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; 
} 

Вы должны увидеть, что HashMap действительно пуст и объекты некорректной уничтожены прямо внутри цикла for, где их сильные ссылки заброшены. Но проблема в том, что у .count собственность - она ​​лежит, говоря, что есть записи, хотя allObjects ничего не возвращает.

0

Как отмечается в документе, сказал:

Основным вариантом является обеспечение «слабых» ссылок, которые удаляются автоматически, но в какой-то неопределенный момент в будущем.

Таким образом, точка автоматического удаления неизвестна, и это не гарантирует, что она будет удалена в следующем цикле выполнения, поэтому нельзя полагаться на AutoReleasePool.

Смежные вопросы