Retain Cycles and Weak References

来源:互联网 发布:江西广电网络好用吗 编辑:程序博客网 时间:2024/06/11 09:47

ARC’s behavior is automatic and mindless; it knows nothing of the logic of the relationships between objects in your app. Sometimes, you have to provide ARC with further instructions to prevent it from doing something detrimental. One such detrimental thing is the creation of a retain cycle.

A retain cycle is a situation in which Object A and Object B are each retaining one another. Such a situation, if allowed to persist, will result in a leak of both objects, as neither object’s retain count can decrement to zero.Another way of looking at it is to say that Object A, by retaining Object B, is also retaining itself, and thus preventing its own destruction.

A retain cycle can arise quite innocently, because relationships in an object graph can run both ways. For example, in a system of orders and items, an order needs to know what its items are and an item might need to know what orders it is a part of, so you might be tempted to let it be the case both that an order retains its itemsand that an item retains its orders. That’s a retain cycle.

To illustrate the problem, I’ll suppose a simple class MyClass with a single ivar _thing and a single public setter setThing:, with logging in dealloc, like this:

@implementation MyClass {

    id _thing;

}

- (void) setThing: (id) what {

    self->_thing = what;

}

-(void)dealloc {

    NSLog(@"%@", @"dealloc");

}

@end

We now run this code:

MyClass* m1 = [MyClass new];

MyClass* m2 = [MyClass new];

m1.thing = m2;

m2.thing = m1;

m1 and m2 are now retaining one another, because ARC retains on assignment by default. When the code runs, dealloc is never called for either of our MyClass instances, even after the automatic pointer variables m1 and m2 have gone out of scope and have been destroyed. The two MyClass objects themselves have leaked.

You can prevent an instance variable from retaining the object assigned to it by specifying that the instance variable should be aweak reference. You can do this with the __weak qualifier in the instance variable’s declaration:

@implementation MyClass {

    __weak id _thing;

}

Now there is no retain cycle. In our example, there will be no leak; the two MyClass objects will go out of existence after our code finishes running, because ARC sent them each a release message as the automatic variables m1 and m2 went out of scope (to balance the new calls that created them), and no one else is retaining them


In ARC, a reference not explicitly declared weak is a strong reference. Thus, a strong reference is one where ARC retains as it assigns. There is in fact a __strong qualifier, but in practice you’ll never use it, as it is the default. (There are also two additional but rarely needed qualifiers, __unsafe_unretained and __autoreleasing.)




In real life, a weak reference is most commonly used to connect an object to its delegate (Chapter 11). A delegate is an independent entity; there is usually no reason why an object needs to claim ownership of its delegate, and indeed an object is usually its delegate’s servant, not its owner. Ownership, if there is any, often runs the other way; Object A might create and retain Object B, and make itself Object B’s delegate. That’s potentially a retain cycle. Therefore, most delegates should be declared as weak references.



For example, in a project created from Xcode’s Utility Application project template, you’ll find this line:

@property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate;

The keyword weak in the property declaration, as I’ll explain more fully later in this chapter, is equivalent to declaring the _delegate instance variable as __weak.

In non-ARC code, a reference can be prevented from causing a retain cycle merely by not retaining when assigning to that reference in the first place; the reference simply isn’t memory-managed at all. You may see this referred to as a weak reference; it is not, however, quite the same thing as an ARC weak reference. A non-ARC weak reference risks turning into a dangling pointer when the instance to which it points is released (by someother object thatwas retaining it) and is destroyed. Thus it is possible for the reference to be non-nil and pointing to garbage, so that a message sent to it can have mysteriouslydisastrousconsequences.

Amazingly, however, this cannot happen with an ARC weak reference. When an instance’s retain count reaches zero and the instance is about to vanish, any ARC weak reference that was pointing to it is automatically set to nil! (This amazing feat is accomplished by some behind-the-scenes bookkeeping: when an object is assigned to a weak reference, ARC in effect notes this fact on ascratchpad list.) This is yetanother reason for preferring to use ARC wherever possible. ARC sometimes refers to non-ARC weak references,disdainfully but accurately, as “unsafe.” (Non-ARC weak references are in fact the __unsafe_unretained references I mentioned a moment ago.)

Unfortunately, large parts of Cocoa itself don’t use ARC. Cocoa’s memory management is carefully written, so that in general its retains and releases are balanced and it shouldn’t cause any memory leaks. Nevertheless, properties of built-in Cocoa classes that keep weak references are non-ARC weak references (because they are old and backwards-compatible, whereas ARC is new). Such properties are declared using the keyword assign. For example, UINavigationController’s delegate property is declared like this:

@property(nonatomic, assign) id<UINavigationControllerDelegate> delegate

Thus, even though your code is using ARC, the fact that Cocoa’s code isnot using ARC means that memory management mistakes can still occur. A reference such as a UINavigationController’s delegate can end up as a dangling pointer, pointing at garbage, if the object to which that reference was pointing has gone out of existence. If anyone (you or Cocoa) tries to send a message by way of such a reference, the app will then crash — and, since this typically happens long after the point where the real mistake occurred, figuring out the cause of the crash can be quite difficult. The typical signs of such a crash are that it takes place in Apple’s method objc_retain and mentions EXC_BAD_ACCESS (Figure 12-1). This is the sort of situation in which you might need to turn on zombies in order to debug, as described earlier in this chapter.


Defending against this kind of situation is up to you. If you assign some object to a non-ARC weak reference, such as a UINavigationController’s delegate, and if that object is about to go out of existence at a time when this reference still exists, you have a duty to assign nil (or some other object) to that reference, thus rendering it harmless.


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 运满满有了差评怎么办 房贷款还清后该怎么办 身份证被偷了怎么办啊 苹果手机wifi速度慢怎么办 电脑桌面上的图标不见了怎么办 夏天手机没地方放怎么办 上班手机没地方放怎么办 京东退款未到账怎么办 京东退款失败后怎么办 在京东申请退款怎么办 微信退款没收到钱怎么办 在拼多多不发货怎么办 扫二维码群发微信骗局怎么办 电脑高清晰音频管理器打不开怎么办 吃鸡耳机有杂音怎么办 分期付款车被朋友卖了怎么办 网上购物付款显示繁忙怎么办 同行招牌高于我的招牌怎么办 拼多多刷手退款怎么办 网银卡在手机上卸载了怎么办 企业网银密码忘了怎么办 网银钱转错了怎么办 民生百货购物卡过期了怎么办 新办卡注册过支付宝账号怎么办 床上用品专卖店没人进店怎么办 红蚂蚁咬了红肿痒怎么办 碎纸机轮不转了怎么办 轮滑鞋刀架螺丝圆了了怎么办 万朋商城2018年怎么办 超市盘点少了烟怎么办 歌华有线电视费用欠费好久怎么办 租房到期房东不退押金怎么办 个税申报错税局查出来怎么办 苹果手表抬腕唤醒失灵怎么办 在京东充电费充错了怎么办 进去了微商传销怎么办 喝完酒四肢酸痛睡不着怎么办 喝多了全身痛怎么办 喝完酒第二天浑身酸痛怎么办 鑫和陌车骗我钱怎么办 社会人加你qq怎么办