Avoid strong reference cycles

转自:http://masteringios.com/blog/2014/03/06/avoid-strong-reference-cycles/

With the introduction of ARC, memory management became easier. However, even though you don’t have to worry about when to retain and release, there are still a few rules you need to know in order to avoid memory problems. In this post we’re going to talk about strong reference cycles.

What exactly is a strong reference cycle? Let’s assume that you have two objects, object A and object B. If object A holds a strong reference to object B and object B has a strong reference to object A then we have a strong reference cycle. We’re going to talk about two very common situations where you need to be careful about reference cycles: blocks and delegates.

1. Delegates

Delegation is a commonly used pattern in Objective C. In this case one object acts on behalf of or in coordination with another object. The delegating object keeps a reference to the other object (the delegate) and at the appropriate time it sends a message to it. The delegate is the able to respond by updating the appearance or the state of the application.

One example from the API is the UITableView and its delegate. In this example the table view has a reference to its delegate and the delegate has a reference back to the table view. This means that each one is keeping the other alive so even if there are no other objects pointing to the delegate or the table view, the memory doesn’t get deallocated.

Let’s consider a custom example:

#import 

@class ClassA;

@protocol ClassADelegate 

-(void)classA:(ClassA *)classAObject didSomething:(NSString *)something;

@end

@interface ClassA : NSObject

@property (nonatomic, strong) id delegate;

@end

This will generate a retain cycle in an ARC world. To prevent this all we need to do is change the reference to our delegate to be weak:

@property (nonatomic, weak) id delegate;

A weak reference does not imply ownership or responsibility between two objects and does not keep an object alive. If there are no other objects pointing to the delegate and the delegating object, then first the delegate will get deallocated and so it will release its strong reference to the delegating object. With nobody pointing to it the delegating object will also get released.

2. Blocks

Blocks are chunks of code, similar to C functions, but in addition to executable code they may contain variable bindings to stack or heap memory. A block can therefore maintain a set of data that it can use to impact behaviour when executed. Because blocks maintain the data needed for execution of the code, they are particularly useful as callbacks.

Blocks are Objective C objects, however there are some memory management rules that only applies to blocks, no other Objective C objects.

Blocks maintain strong references to any captured objects, including self, so it’s very easy to end up with a strong reference cycle. If a class has a property for a block like this:

@property (copy) void (^block)(void);

And in its implementation you have a method like this:

- (void)methodA {

    self.block = ^{

        [self methodB];
    };
}

then you’ve got yourself a strong reference cycle: the object (self) has a strong reference to the block and the block just captured a strong reference to self.

Note:  For block properties its a good practice to use copy, because a block needs to be copied to keep track of its captured state outside of the original scope.

In order to avoid this strong reference cycle we need to use weak references again. This is how the code would look like:

- (void)methodA {

    ClassB * __weak weakSelf = self;

    self.block = ^{

        [weakSelf methodB];
    };
}

By capturing the weak reference to self, the block won’t maintain a strong relationship to the object. If the object is deallocated before the block is called the weakSelf pointer will simply be set to nil. While this is great because there won’t be a memory problem, if the pointer is nil then our method inside the block won’t get called and so the block won’t  have the expected behaviour. To avoid this, we’re going to alter our example a bit further:

- (void)methodA {

    __weak ClassB *weakSelf = self;

    self.block = ^{

        __strong ClassB *strongSelf = weakSelf;

        if (strongSelf) {

            [strongSelf methodB];
        }
    };
}

We are creating a strong self reference inside the block. This reference will belong to the block and it will be alive for as long as the block is. It won’t prevent the self object for being deallocated so we are still avoiding the strong reference cycle.

Not all strong reference cycles are as easy to see as the one in my example so you might consider using a weak reference whenever your block code gets a bit more complicated.

These are two common patterns where strong reference cycles can appear.  As seen, it’s very easy to break these cycles with weak reference as long as you can correctly identify them. You need to be mindful of memory management even if ARC made is easier for all of us.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值