2016-07-14 5 views
-1

Я изучаю систему obj-c/swift. в журнале печати сохранить количество созданного экземпляра с помощью функции CFGetRetainCount.Почему экземпляр Obj-C имеет 1 счет сохранения Только что создан?

Я ожидал, что количество ссылок, как эти

let foo1 = NSObject() // foo1 retain count 1 
let foo2 = foo1  // foo1 retain count 2 
foo2 = nil    // foo1 retains count 1 
foo1 = nil    // foo1 retain count 0. release 

, но на самом деле ..

let foo1 = NSObject() // foo1 retain count 2 
let foo2 = foo1  // foo1 retain count 3 
foo2 = nil    // foo1 retain count 2 
foo1 = nil    // foo1 retain count 1. release 

и печать сохранить счетчик NSObject() непосредственно ..

print(CFGetRetainCount(NSObject())) // retain count 1 

в основном, NSObject () имеет 1 счетчик хранения. и высвободить объект, когда удерживать отсчет до достижения 2.

Я знаю, что увеличение количества удержаний при ссылке с экземпляром сильно. но только что созданный экземпляр имеет 1 экземпляр счета и освобождения, когда удержание счета становится 1 не 0. В чем причина этих явлений?

+2

Ваш код даже не * компилируется *, потому что 'foo1',' foo2' являются константами. Даже если вы объявляете их как переменные, вы не можете назначить им «nil». Что вы действительно испытали? –

+0

Я никогда не думаю, что CFGetRetainCount может показать мне информацию об удержании объекта. попробуйте простой код: var foo1: NSNumber? = NSNumber (значение: 0) print (CFGetRetainCount (foo1)). Очень много печати. ​​ – larva

+1

. Вы задаете вопрос о коде. Было бы обычной вежливостью размещать код, о котором вы просите, а не что-то, что вы только что создали на месте. – gnasher729

ответ

2

Изучаю систему obj-c/swift arc.

Вы направляетесь не в ту сторону, если попытаетесь понять, как работают ARC и сохранить счет на высоком уровне. См. here и here и here.

В чем причина этих явлений?

В компиляторе ARC - очень сложная система, лежащая в основе многих уровней оптимизации. Трудно понять фактическое значение счета удержания. Кроме того, на него влияет уровень оптимизации.

Если вы действительно хотите погрузиться глубже, это paper on ARC в Свифт.

2

TL; DR, как вы записываете могут повлиять на результаты, вы можете получить временную собственность при входе, поэтому увеличивая все ваши результаты печати на 1.

следующий ответ является упрощением, потому что вы не должно действительно беспокоиться о реальной стоимости в retainCount.

Счетчик хранения подсчитывает количество ссылок (владельцев) данного объекта. Когда создано, существует ровно один владелец, поэтому счетчик удержания устанавливается равным 1. Каждый раз, когда объект получает нового владельца (retain), счет сохранения увеличивается на единицу. Каждый раз, когда объект проигрывает и владелец (release), количество удержаний уменьшается на единицу.

Обратите внимание, что retainCount никогда не может достигнуть нуля. Если количество владельцев - 1, и вы теряете владельца, объект освобождается, тогда счетчик не уменьшается.

Для лучшего теста, я создал класс Obj-C, составленный без АРК:

@implementation TestObject 

- (instancetype)init { 
    TestObject *result = [super init]; 

    NSLog(@"Retain count after creation: %@", @(self.retainCount)); 

    return result; 
} 

- (instancetype)retain { 
    TestObject *result = [super retain]; 
    NSLog(@"Retain count after retain: %@", @(self.retainCount)); 

    return result; 
} 

- (oneway void)release { 
    NSLog(@"Retain count before release: %@", @(self.retainCount)); 

    [super release]; 
} 

- (void)dealloc { 
    NSLog(@"Retain count before dealloc: %@", @(self.retainCount)); 
    [super dealloc]; 
} 

@end 

и использовал его в Swift вместо вашего NSObject:

var foo1: TestObject? = TestObject() 
print("#") 
print(CFGetRetainCount(foo1)) 
var foo2 = foo1 
print("#") 
print(CFGetRetainCount(foo1)) 
foo2 = nil 
print("#") 
print(CFGetRetainCount(foo1)) 
foo1 = nil 

Результирующее в:

Retain count after creation: 1 
# 
Retain count after retain: 2 
2 
Retain count before release: 2 
Retain count after retain: 2 
# 
Retain count after retain: 3 
3 
Retain count before release: 3 
Retain count before release: 2 
# 
Retain count after retain: 2 
2 
Retain count before release: 2 
Retain count before release: 1 
Retain count before dealloc: 1 

Это в основном то, что вы ожидаете, но есть дополнительные удержания и выпускает около CFGetRetainCount, когда вы получаете временное владение при передаче объекта в функцию.

Это один из примеров, почему вы никогда не должны читать значение retainCount. Он не имеет отладочной стоимости, что также упоминается в documentation.

0

Вкратце: оно имеет номер, чтобы быть как минимум 1, потому что, когда значение удержания идет до 0, объект уходит (так что нет объекта, чтобы спросить, что его удерживает счет).

Более длинный ответ может быть это видео, которое я сделал для друга давным-давно: https://www.youtube.com/watch?v=cBN--I31Xjo

Но на самом деле, если вы используете ARC, вы не должны смотреть на удержания счета. ARC будет вставлять сохраненные значения по мере необходимости, и для ARC идеально подходит для сохранения объекта 5 раз в этот момент, если он позже будет выпускать его 5 раз.

Это проблема с -retainCount или CFGetRetainCount(): Поскольку вся точка сохраняющих подсчетов разделяет собственность, вы не должны заботиться, кто еще владеет ссылку, вы должны заботиться только о том, сколько ссылок код держит и что он правильно дает им за счет обеспечения отсутствия круговых ссылок.