Avoid strong reference cycles
6289 단어 reference
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.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Javascript Primitive type vs Reference type (원시자료형 vs 참조자료형)?? 뭔데??Javascript 자료형은 크게 두 가지 데이터 타입으로 나뉜다!! 그것이 오늘 공부한 Primitive와 Reference type이다 => 두 타입 모두 선언, 할당 과정을 거친다는 점에서는 동일하다. 원시자료...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.