#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. Это было слишком долго, чтобы добавлять в качестве комментария.