ARC下僅僅__strong是不能解決所有問題的,例如循環(huán)引用(應(yīng)當(dāng)廢棄的對象在超出其生存周期后繼續(xù)存在)
A對象持有B對象的強(qiáng)引用,B對象持有A對象的強(qiáng)引用,相互強(qiáng)引用,發(fā)生內(nèi)存泄漏
上面通常以對象與其成員變量的形式發(fā)生,當(dāng)然還有三者之間循環(huán)引用的場景等待
@interface Person : NSObject
@property(nonatomic, retain(MRC)/strong(ARC))Dog *dog;
@end
@interface Dog : NSObject
@property(nonatomic, retain(MRC)/strong(ARC))Person *owner;
@end
Person *p = [Person new];//p = 1
Dog *d = [Dog new];//d = 1
p.dog = d; //???d = 2
d.owner = p; //??p = 2
MRC:
[p release]; // p = 1
[d release]; // d = 1
ARC:
自動(dòng)變量p與d出作用域后對對象的強(qiáng)引用失效后,兩對象以循環(huán)引用的形式依然存在
MRC下使用assign,ARC下使用weak可以解決
@interface Person : NSObject
@property(nonatomic, retain(MRC)/strong(ARC))Dog *dog;
@end
@interface Dog : NSObject
@property(nonatomic, assign(MRC)/weak(ARC))Person *owner;
@end
Person *p = [Person new];//p = 1
Dog *d = [Dog new];//d = 1
p.dog = d; //???d = 2
d.owner = p; //??p = 1
MRC
[p release]; // p = 0 d= 1
[d release]; // d = 0
ARC
p,d出了作用域強(qiáng)引用失效,p引用的對象的廢棄,Person對象成員變量_dog也被廢棄,d引用的對象廢棄
前面說過setter方法的實(shí)現(xiàn),還是setter方法內(nèi)的內(nèi)存管理導(dǎo)致
MRC下assgin只是簡單的賦值,因此不會導(dǎo)致循環(huán)引用
ARC下
{
Person __weak *owner;
}
- (void)setOwner:(Person __strong *)owner;
__weak修飾符只能用于iOS5以上的版本,在iOS4中可使用__unsafe_unretained修飾符來代替
__unsafe_unretained如其名unsafe,是不安全的所有權(quán)修飾符,盡管ARC 內(nèi)存管理是編譯器的工作,但附有__unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對象
id __unsafe_unretained obj = [[NSObject alloc] init];
__unsafe_unretained同__weak一樣,不能強(qiáng)引用,對象生成就被釋放。如果使用__weak,obj == nil,而使用__unsafe_unretained obj指向被廢棄的內(nèi)存,如果訪問,會發(fā)生壞內(nèi)存訪問錯(cuò)誤
assign類似類似__unsafe_unretained
__weak與__strong修飾符相反,提供弱引用,弱引用不能持有對象實(shí)例。類似MRC下的,p2 = p1;
id __weak obj = [[NSObject alloc] init];
編譯器會給出警告,上述代碼將自己生成并持有的對象賦值給__weak修飾的變量obj,生成的對象不存在強(qiáng)引用,生成立即被釋放,編譯器對此給出警告。如果像下面這樣
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
將對象賦值給附有__strong修飾符的變量,之后再賦值給附有__weak修飾符的變量,就不會發(fā)生警告了。此時(shí)對象存在obj0的強(qiáng)引用,obj1的弱引用。生成不會立即釋放