Почему NSSet objectEnumerator увеличивает счетчик сохранения?

После получения objectEnumerator в следующем коде счетчик сохранения set1 становится равным 3. Я был удивлен, увидев это, потому что не ожидал, что он изменится. Я искал документация и не может найти, где объясняется этот эффект.

Я предполагаю, что дополнительные удержания, вероятно, настроены на автоматическое освобождение логикой перечисления Cocoa и не будут иметь никакого эффекта в текущем цикле событий. Имеет смысл, чтобы логика objectEnumerator нуждалась в ссылке на set1, но я хотел бы знать, почему они были созданы. Вот причина: если я предполагаю, что set1 сохранил нулевой счетчик после выпуска в коде, я мог бы попытаться повторно использовать его в другом новом наборе. Не вызовет ли это проблем, поскольку set1 теперь указывает на совершенно другой объект/адрес?

Что касается «бонусных» баллов, есть ли способ перечислить пул автовыпуска, чтобы увидеть, что он на самом деле содержит? ТИА

#import <Foundation/NSObject.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSString.h>

#import <stdio.h>;

// macro to create an integer number:
#define INTOBJ(v) [NSNumber numberWithInt: v]

int main (int argc, char *argv[])
{
    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    //Make set
    NSMutableSet *set1 = [[NSMutableSet alloc] initWithObjects:
        INTOBJ(1), INTOBJ(2), INTOBJ(5), INTOBJ(10), nil];

    printf("set1 #%lu\n", [set1 retainCount]);

    //Get enumerator of the set. This is where the retain count goes to 3:
    NSEnumerator *setEnum = [set1 objectEnumerator];
    printf("setEnum #%lu\n", [setEnum retainCount]);
    printf("set1 #%lu\n", [set1 retainCount]);

    //Iterate through the collection:
    printf("[");

    NSNumber *element;
    while ((element = [setEnum nextObject]) != nil)
        //do some this with item. printf is just for debugging:
        printf(" %i ", [element intValue]);

    printf("]\n");
    printf("set1 #%lu\n", [set1 retainCount]);

    [set1 release];
    printf("set1 after release #%lu\n", [set1 retainCount]);

    //More logic could go here reusing variable set1 since I assumed retain count = 0

    [pool release];

    return 0;
}

person Sixto Saez    schedule 01.12.2008    source источник


Ответы (3)


Как правило, не рекомендуется полагаться на количество сохраняемых объектов, так как это внутренняя деталь фреймворка. Вместо этого убедитесь, что ваш код соответствует принципам управления памятью, в частности, убедитесь, что сохранение/новое/копирование и выпуск/автоматическое освобождение сбалансированы.

person Community    schedule 01.12.2008
comment
Я один из немытых разработчиков .NET, которые занимаются Obj-C, поэтому я скучаю по управляемому сборщику мусора. Благодаря таким людям, как вы, я научился обрабатывать подсчеты удержания. В .NET переменные освобождаются, когда они выходят за пределы области видимости, и на них не ссылаются. Что вы думаете об этом сообщении: kickingbear.com/blog/?p=17 - person Sixto Saez; 01.12.2008
comment
Я могу понять, почему вы определили эти макросы, но они чертовски запутают меня в код-ревью ;-) - person ; 02.12.2008

Предположительно, перечислитель сохраняет коллекцию, чтобы она не освобождалась во время перечисления. Перечислитель без действительной коллекции для перечисления не будет работать очень хорошо. На самом деле, единственный способ для перечислителя быть уверенным в том, что он будет работать, — это сохранить перечисляемую им коллекцию.

Тем не менее, нет никакой причины когда-либо смотреть на счетчик сохранения любого объекта, кроме для отладки проблемы с утечкой памяти/двойным освобождением. Пока вы следуете соглашениям об управлении памятью, вам никогда не придется беспокоиться о количестве удерживаемых объектов.

person Alex    schedule 01.12.2008

Повторное использование set1 после выпуска не вызовет проблем, потому что счетчик сохранения относится к объекту, на который ссылается переменная set1, а не к самой переменной.

person Darron    schedule 01.12.2008