2012-09-11 80 views
3

只是試圖完全理解ARC。arc,強和弱的實例變量

MyView *testView = [[MyView alloc] init]; 

__weak MyView *weakView = testView; 

[weakView addObserver:self forKeyPath:@"alpha" options:0 context:nil]; 

testView = nil; 

if(weakView) { 
    NSLog(@"WeakView exists!"); 
} 

我不明白爲什麼我的NSLog語句打印。由於weakView是testView的弱引用,它不應該指向nil一旦testView設置爲nil ???

謝謝!

回答

7

addObserver方法好像是retainautorelease的說法。這就是爲什麼在初始引用被刪除後,弱引用沒有被清零。只需在調試器中運行此代碼:

UIView *testView = [[UIView alloc] init]; 

__weak UIView *weakView = testView; 

@autoreleasepool { 
    [weakView addObserver:self forKeyPath:@"alpha" options:0 context:nil]; 
} 

testView = nil; 

if(weakView) { 
    NSLog(@"WeakView exists!"); 
} 
1

它可能會也可能不會。當對象被釋放時它會變爲零。事實上,您將testView設置爲零隻意味着您釋放該對象。但該對象不保證立即被釋放。

這裏的問題是,您假設保留計數的給定值。您認爲alloc + init序列爲您提供了一個計數爲1的對象,因此當您將testView設置爲零時,它將變爲0,並且對象被釋放。

你應該從來沒有假設一個給定的保留數。你應該總是考慮相對保留數量。 alloc + init序列返回一個+1對象(不是1但是+1)。當您將設置testView設置爲無ARC調用release並將其設置爲+0對象(不是0,但是爲+0)時。這意味着你不能保證它仍然可以訪問。你的弱點可能有效,也可能不是有效的。

實際發生的事情是,在init方法的內部(或父母的鏈接初始化方法),有一個調用autorelease因此你的對象還沒有一個0.它的refcount它會得到它(並在下一個游泳池流失時被釋放)。

編輯:

亞當在他的答覆中所說的是正確的。

+1

'init'方法不會向對象發送'autorelease'。它創建保留計數爲1的對象。無論是否使用ARC,它都是相同的。 – Adam

+0

一些init方法可以,其他方法則不行。有一些init方法返回具有無限保留計數的對象。有一些init方法返回一個不是您分配的對象的對象。你應該**從不**依靠init方法返回一個計數爲1的對象(或任何方法。實際上,即使alloc也不應該考慮返回保證計數爲1的對象)。 –

+0

[基本規則](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH)是:您擁有使用名稱以「alloc」,「new」,「copy」或「mutableCopy」開頭的方法創建的任何對象。這意味着當你完成它時,你必須「釋放」或「自動釋放」它。不保證保留數爲1,但這些方法至少爲1。確切地說, – Adam

0

您的testView是局部變量,ARC下的局部變量沒有精確的生命週期語義。閱讀6.1在:

http://clang.llvm.org/docs/AutomaticReferenceCounting.html#optimization.precise

是什麼意思?這意味着編譯器可以做任何想做的事情。

當前實現版本testView該方法結束時的對象。但是如果優化器(現在,將來,...)決定生命週期結束並且它會在方法結束之前更早釋放它呢?

換句話說,你試圖依賴未定義的行爲。不要這樣做,不要依賴這個。在這種情況下,你永遠不知道對象何時被釋放=弱引用被歸零。