проблемы с дугой и отсутствием дуги

#ios #objective-c #automatic-ref-counting

#iOS #objective-c #автоматический подсчет ссылок

Вопрос:

Это мой код

 __weak KDObject *obj = [KDObject fetchObj] ;
NSLog(@"%@", obj) ; // I think it should be nil, but it is not
obj.i = 10 ;
NSLog(@"%d", obj.i) ;
  

В KDObject.m

 @implementation KDObject    
  (instancetype)fetchObj
{
    return [[self alloc] init] ;
}
@end
  

результат один и тот же, независимо от того, скомпилирован KDOjbect.m с -fno-objc-arc флагом или без -fno-objc-arc флага

У кого-нибудь есть идеи, почему obj не равно нулю?

Комментарии:

1. Как вы думаете, почему это должно быть nil? Вы инициализировали KDObject, который не вернет нулевой объект.

2. Потому что obj слабый, если вам нравится это __weak KDObject *o = [[KDObject alloc] init] ; , o равен нулю.

3. Но это не переменная класса, и __weak совершенно не нужен

4. В моем случае экземпляр вернул nil, как и ожидалось.

5. @trick14 Покажите мне свой код, пожалуйста.

Ответ №1:

Связанные с вашим вопросом и с вашим ответом:

-fectchObject — это метод, не принадлежащий ни к одному семейству методов с передачей права собственности. Поэтому ARC должен гарантировать, что возврат ссылки безопасен. Это означает, что потеря строгой ссылки в локальной области -fetchObject не приводит к потере последней ссылки.

Один из способов добиться этого — использовать пул автоматического выпуска. Но ARC не гарантирует, что используется ARP. Более того, он пытается не использовать ARP, потому что это решение с наибольшим объемом памяти.

Таким образом, происходящее зависит от реализации компилятора, атрибутов, установленных для метода, и того, что компилятор видит в исходном коде (особенно. реализация -fetchObject). Поэтому вам не следует полагаться на возврат в ARP.

__weak гарантированно равен нулю, если объект уничтожен. Но не гарантируется, что объект будет уничтожен в кратчайшие возможные сроки. Это подлежит оптимизации.

Комментарии:

1. Теперь я в замешательстве. __weak не увеличит количество сохранений. верно? Это означает, что __слабый KDObject *obj = [KDObject fetchObj] ; будет выпущен сразу после создания экземпляра. Я тестировал с аналогичным кодом, заданным KudoCC, и экземпляры вернули ноль. Также было предупреждение о том, что объект будет освобожден после назначения.

2. @KudoCC Кстати, ARC возвращает ссылку из -fetchObject — это детали реализации. Вы не можете предположить, что это сделано в ARP или что оно выпущено немедленно. ARC пытается сделать это раньше (т. Е. в конце полного выражения), но не может гарантировать, используется ли ARP или при каких обстоятельствах (= более поздний выпуск).)

3. Из документов: «При возврате из такой функции или метода ARC сохраняет значение в точке оценки оператора return, затем покидает все локальные области, а затем балансирует сохранение, гарантируя, что значение сохраняется за пределами границы вызова. В худшем случае это может быть связано с авторелизом , но вызывающие устройства не должны предполагать , что значение действительно находится в пуле авторелиза. »

Ответ №2:

Из документов о __weak

__weak указывает ссылку, которая не поддерживает работу ссылочного объекта. Слабой ссылке присваивается значение nil, когда нет сильных ссылок на объект.

Независимо от того, является ли это __слабым или нет, KDObject *o = [[KDObject alloc] init] создает объект, поэтому o не равен нулю.

__weak — это нечто, связанное с управлением памятью. Если ни один из сильных объектов не указывает на weak объект, он будет удален из памяти.

Комментарии:

1. вы пробовали код? Вы можете попробовать это с __weak UIView *v = [[UIView alloc] init] ; , и v, без сомнения, равен нулю.

2. Это потому, что вы присваиваете сохраненный объект слабой переменной. Он освобождается после назначения.

3. Смешно! Вы имеете в виду, что он отправит выпуск экземпляра, когда я назначу его слабой переменной?

4. Да, просто введите вышеуказанную строку в XCode и увидите предупреждение, которое выдает XCode. Здесь говорится то же самое.

5. Если это так, v будет выпущен после присвоения версии v2, но это не так. UIView *v = [[UIView alloc] init] ; __weak UIView *v2 = v ;

Ответ №3:

 - (void)loadView
{
 [super loadView];

    TestObject *obj_ = [[TestObject alloc] init];
    pObj = obj_;
    if(pObj == nil)
    {
        NSLog(@"pObj_ is not nil");
    }

    __weak TestObject *obj2_ = [[TestObject alloc] init];
    if(obj2_ == nil)
    {
        NSLog(@"obj2_ is nil");
    }

    __weak TestObject *obj3_ = [TestObject createInstance];
    if(obj3_ == nil)
    {
        NSLog(@"obj3_ is nil");
    }
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if(pObj == nil)
    {
        NSLog(@"pObj is nil");
    }
}
  

KudoCC запросил этот код. Я использовал LLVM5.1. Если я использую -fno-objc-arc для TestObject.h, objc3_ стал не нулевым.

Комментарии:

1. creteInstance такой же, как у вашего fetchObj()

2. obj3_ равен нулю? Это странно… Можете ли вы попытаться скомпилировать KDOjbect.m с флагом -fno-objc-arc?

3. Какая версия вашего компилятора? У меня это LLVM 5.1.

4. Использование только фрагмента кода здесь считается плохим отношением. Добавьте некоторые пояснения и т.д. Ваш ответ был помечен как некачественный и подлежит удалению. Пожалуйста, улучшите его, чтобы предотвратить удаление.

5. Извините за это. Код, который я добавил, был тем, что запросил KudoCC. Это было слишком долго, чтобы добавлять в качестве комментария.