Подтвердить что ты не робот

Почему моя слабая ссылка не была очищена сразу после того, как сильные исчезли?

Я немного упрям, но я хочу хорошо понимать слабые и сильные ссылки, поэтому я снова спрашиваю вас.

Рассмотрим это:

__weak NSString* mySecondPointer = myText;   
NSLog(@"myText: %@", myText);

Результат myText: (null), и это довольно очевидно - слабое задание устанавливается равным null сразу после присвоения, потому что нет сильной ссылки на заостренный объект.

Но в этом случае:

__strong NSString* strongPtr = [[NSString alloc] initWithFormat:@"mYTeSTteXt %d"]; 
// weak pointer points to the same object as strongPtr
__weak NSString* weakPtr = strongPtr;
if(strongPtr == weakPtr) 
     NSLog(@"They are pointing to the same obj");        
NSLog(@"StrongPtr: %@", strongPtr);
NSLog(@"weakPtr: %@", weakPtr);

NSLog(@"Setting myText to different obj or nil");

// after line below, there is no strong referecene to the created object:
strongPtr = [[NSString alloc] initWithString:@"abc"];  // or myText=nil;

if(strongPtr == weakPtr) 
     NSLog(@"Are the same");
else
     NSLog(@"Are NOT the same");
NSLog(@"StrongPtr: %@", strongPtr);
// Why weak pointer does not point to nul
NSLog(@"weakPtr: %@", weakPtr);

Выход:

2013-03-07 09:20:24.141 XMLTest[20048:207] They are pointing to the same obj
2013-03-07 09:20:24.142 XMLTest[20048:207] StrongPtr: mYTeSTteXt 3
2013-03-07 09:20:24.142 XMLTest[20048:207] weakPtr: mYTeSTteXt 3
2013-03-07 09:20:24.143 XMLTest[20048:207] Setting myText to different obj or nil
2013-03-07 09:20:24.143 XMLTest[20048:207] Are NOT the same
2013-03-07 09:20:24.144 XMLTest[20048:207] StrongPtr: abc
2013-03-07 09:20:24.144 XMLTest[20048:207] weakPtr: mYTeSTteXt 3   // <== ??

Мой вопрос:

Почему после strongPtr = [[NSString alloc] initWithString:@"abc"]; значение слабого указателя не изменяется на nil (почему созданный в начале объекта все еще существует в памяти, несмотря на то, что он не имеет сильных ссылок?) или, может быть, он имеет?)


Я пробовал это: (но это не хорошо для добавления комментария, я полагаю). Я включил код, в котором я создаю strongPtr в @autorealesepool. Я не уверен, что это правильное решение, но оно работает...

 __strong NSString* strongPtr;
    __weak NSString* weakPtr;
    @autoreleasepool {


        strongPtr = [[NSString alloc] initWithFormat:@"mYTeSTteXt %d", 3];

        // weak pointer point to object create above (there is still strong ref to this obj)
        weakPtr = strongPtr;
        if(strongPtr == weakPtr) NSLog(@"They are pointing to the same obj");        

        NSLog(@"StrongPtr: %@", strongPtr);
        NSLog(@"weakPtr: %@", weakPtr);

        NSLog(@"Setting myText to different obj or nil");   

    // after line below, there is no strong referecene to the created object:
     strongPtr = [[NSString alloc] initWithString:@"abc"];  


    }

    if(strongPtr == weakPtr) 
        NSLog(@"Are the same");
    else
        NSLog(@"Are NOT the same");
    NSLog(@"StrongPtr: %@", strongPtr);
    // Why weak pointer does not point to nul
    NSLog(@"weakPtr: %@", weakPtr);

Вывод:

2013-03-07 09:58:14.601 XMLTest[20237:207] They are pointing to the same obj
2013-03-07 09:58:14.605 XMLTest[20237:207] StrongPtr: mYTeSTteXt 3
2013-03-07 09:58:14.605 XMLTest[20237:207] weakPtr: mYTeSTteXt 3
2013-03-07 09:58:14.606 XMLTest[20237:207] Setting myText to different obj or nil
2013-03-07 09:58:14.607 XMLTest[20237:207] Are NOT the same
2013-03-07 09:58:14.607 XMLTest[20237:207] StrongPtr: abc
2013-03-07 09:58:14.608 XMLTest[20237:207] weakPtr: (null)
4b9b3361

Ответ 1

Из кода сборки видно, что доступ к weakPtr вызывает вызов objc_loadWeak.

Согласно документации Clang, objc_loadWeak сохраняет и автореализовывает объект и эквивалентен

id objc_loadWeak(id *object) {
  return objc_autorelease(objc_loadWeakRetained(object));
}

Это (надеюсь) объясняет, почему оба

if(strongPtr == weakPtr) ...

и

NSLog(@"weakPtr: %@", weakPtr);

создать дополнительные автореализованные ссылки.

Это не особая проблема NSString, я могу воспроизвести одно и то же поведение с обычным (простым) классом.

Ответ 2

Во-первых, не экспериментируйте со слабыми ссылками или другим поведением управления памятью на NSString, слишком много магии в этом классе. Не то, чтобы слабые ссылки не работали с NSString, просто поведение немного сложнее, чем вы ожидали, и легко приводит к неправильным выводам. См. Предыдущие вопросы:

Когда вы завершаете свой пример кода пулом автозапуска и записываете слабый указатель строки после этого, его nil действительно. Возможно, даже в случае, если вы получите подобное поведение с другими классами, отличными от NSString, вам просто не гарантируется, что слабые ссылки будут очищены в тот момент, когда вы потеряете последнюю сильную ссылку на объект. Или, может быть, вы, но трудно сказать, когда именно последняя сильная ссылка исчезает из-за пулов авторефератов в игре, как это намечено в этом примере (и хорошо объяснено ответом Мартинса).

Ответ 3

когда вы делаете

strongPtr = [[NSString alloc] initWithString: @ "abc" ]

you strongPtr указывает на новый выделенный объект, и поскольку предыдущий объект, который он указывал, тоже не освобождался, слабый указатель все еще указывает на действительный адрес.

кстати. вы можете распечатать адрес памяти с объекта с помощью

NSLog (@ "% @", [NSString stringWithFormat: @ "% p", theObject])

Ответ 4

Не уверен, что вопрос OP и/или принятый ответ все еще действительны, по крайней мере, не из результатов, которые я вижу с iOS9/Xcode7.

Здесь (слегка очищенная) версия кода OP...

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        NSString* __strong strongPtr = [[NSString alloc] initWithFormat:@"Life, Universe, Everything: %d", 42];
        NSString* __weak   weakPtr   = strongPtr;

        NSLog(strongPtr == weakPtr ? @"Same" : @"Different");
        NSLog(@"  StrongPtr: %@", strongPtr);
        NSLog(@"  weakPtr:   %@", weakPtr);

        NSLog(@"Changing strongPtr to something else...");
        // After this is set, there is no strong reference to the created object
        strongPtr = [[NSString alloc] initWithFormat:@"Drink: %@", @"Pan-galactic Gargle Blaster!"];

        NSLog(strongPtr == weakPtr ? @"Same" : @"Different");
        NSLog(@"  StrongPtr: %@", strongPtr);
        NSLog(@"  weakPtr:   %@", weakPtr);
    }

    return 0;
}

И вот результат (усеченный)...

Same
  StrongPtr: Life, Universe, Everything: 42
  weakPtr:   Life, Universe, Everything: 42

Changing strongPtr to something else...

Different
  StrongPtr: Drink: Pan-galactic Gargle Blaster!
  weakPtr:   (null)

Program ended with exit code: 0

Здесь доступ к слабым ссылкам в условных выражениях (в соответствии с принятым объяснением ответа) не поддерживает автоматически выделенную ссылку вокруг, как вы можете видеть по (нулевой) на выходе.

... или я случайно изменил вопрос ОП до такой степени, что я спрятал то, что он видел? Или возможно, потому что теперь ARC включен по умолчанию?