Objective-C - слабое свойство - авто-релизы геттера (автоматический подсчет ссылок) - PullRequest
4 голосов
/ 16 ноября 2011

У меня есть сомнения относительно weak свойства в ARC (автоматический подсчет ссылок)

Мое понимание (поправьте меня, если я ошибаюсь):

weak свойство ведет себя подобно свойству assign, за исключением того, что когда экземпляр, на который указывало свойство, уничтожается, ивару присваивается значение nil.

Вопрос:

  1. Я просто чувствую, что получатель свойства weak сохраняет и автоматически выпускает.Разве это не значит, что он ведет себя как получатель свойства assign, когда получатель не сохраняет и автоматически выпускает (пожалуйста, обратитесь к программе)

Программа:

Ниже приведена программа с фактическим и ожидаемым результатом.

Примечание - Когда я изменяю свойство с weak на assign мойожидаемый результат достигнут

#import<Foundation/Foundation.h>

@interface A : NSObject
- (void) dealloc;
@end

@implementation A
- (void) dealloc
{
    printf("\tinstance of A deallocated = %p\n", self);
}
@end

@interface B : NSObject
@property (weak) A* xa1;
- (void) dealloc;
@end

@implementation B
@synthesize xa1;
- (void) dealloc
{
    printf("\tinstance of B deallocated = %p\n", self);
}
@end


int main()
{
    B* b1 = [[B alloc] init];

    @autoreleasepool                        //autoreleasepool 1
    {   
        {                                   //block 1
            A* a1 = [[A alloc] init];
            printf("\ta1 = %p\n", a1);

            b1.xa1 = a1; 

            A* a3 = b1.xa1;

            printf("--- end of block 1\n");
        }                                       //at this point i expected instance pointed by a1 to be destroyed

        printf("--- end of autoreleasepool 1\n");
    }   

    printf("---- end of main\n");

    return(0);
}

Фактический результат:

    a1 = 0x10d713f50
--- end of block 1
--- end of autoreleasepool 1
    instance of A deallocated = 0x10d713f50
---- end of main
    instance of B deallocated = 0x10d713d30

Мой ожидаемый результат:

    a1 = 0x10d713f50
--- end of block 1
    instance of A deallocated = 0x10d713f50
--- end of autoreleasepool 1
---- end of main
    instance of B deallocated = 0x10d713d30

Спасибо

Ответы [ 2 ]

4 голосов
/ 16 ноября 2011

Предоставление weak для свойства предполагает владение __weak для ивара, т.е. это просто инструкция для @synthesize.

Согласно http://clang.llvm.org/docs/AutomaticReferenceCounting.html §4.2, чтение переменной __weak требует сохранения объекта (и, разумеется, после):

Чтение происходит при выполнении lvalueПреобразование -в-значение в объекте lvalue.

  • Для слабых объектов текущий указатель сохраняется и затем освобождается в конце текущего полного выражения.Это должно выполняться атомарно в отношении назначений и окончательного освобождения pointee.
  • Для всех других объектов lvalue загружается примитивной семантикой.

Это делаетне говорите почему, но подумайте, что произойдет, если объект, который вы получили из переменной __weak, умирает еще до того, как вы начали его использовать.Цель слабого указателя - убедиться, что у вас есть либо nil, либо действительный объект с известным временем жизни, поэтому чтение его значения подразумевает сохранение pointee (а затем getter свойства возвращает его автоматически освобожденным).

Это не уникально для Obj-C, это общая идиома для всех реализаций слабых указателей (как пересчитанных, так и сборщиков мусора).Слабые указатели не могут напрямую выдавать значение указателя, они должны создать сильный указатель, чтобы «удерживать» объект, чтобы убедиться, что он не умрет до того, как вызывающий объект даже начал его использовать.В Obj-C это retain-autorelease;в C ++ слабый_прием сначала создает shared_ptr, в средах со сборщиком мусора возвращается сильная ссылка и время жизни объекта молча продлевается.

0 голосов
/ 12 ноября 2014

Getter для x1 выглядит следующим образом:

function -[B xa1] {
    var_8 = rdi;
    var_0 = rsi;
    rdi = objc_loadWeakRetained(var_8 + *_OBJC_IVAR_$_B.xa1);
    rax = [rdi autorelease];
    return rax;
}

Так что, когда вы получаете свойство в

A* a3 = b1.xa1;

a1 == b1.xa1, вы получаете вызов autorelease и сохраняются в autoreleasepool

...