In the 2011 WWDC, Apple mentioned that 90% of the crash were caused by memory management, and ARC ( Automatic Reference Counting
) was the solution given by Apple. With ARC enabled, developers do not need to worry about memory management, and the compiler will handle it for you (note that arc is a compiler feature, not an iOS runtime feature, not a garbage collector in other languages).
Simply put, the compiler will automatically generate the reference count code for the instance when compiling the code, helping us to complete the work that the MRC needs to do before, although it is said that the compiler will perform some optimizations.
Although arc can solve most of the memory leaks, there are still some places we need to be aware of.
Circular references
循环引用简单来说就是两个对象相互强引用了对方
, that retain the other side, which leads to the memory leaks that no one can release. For example, when declaring a delegate, you generally use weak instead of retain or strong, because once you do that, it is very likely to cause a circular reference.
This simple circular reference as long as in the process of coding more attention, generally can be found.
The solution is also very simple, usually a strong reference in the loop chain is changed to a weak reference can be resolved.
Another block-induced circular reference problem is often a problem that developers who are unfamiliar with the block principle are less likely to discover.
Circular reference caused by block
Let's take a look at the official documentation. Explanation of block invocation: Object and Block Variables
When a block was copied, it creates strong references to object variables used within the block. If you use a block within the implementation of a method:
- If You access an instance variable by reference, a strong reference are made to self;
- If You access an instance variable by value, a strong reference are made to the variable.
There are two main rules:
第一条规则,如果在block中访问了属性,那么block就会retain住self。
第二条规则,如果在block中访问了一个局部变量,那么block就会对该变量有一个强引用,即retain该局部变量。
According to these two rules, we can know the situation where the circular reference occurred:
1 2 3 4 5 6 7 8 9 10 11
|
Rule 1 Self. Myblock = ^{ [//Access member method NSLog (@ "%@", weakself//Access Properties };
Rule 2 ASIHTTPRequest *request = [ASIHTTPRequest Requestwithurl:url]; [Request setcompletionblock:^{ nsstring* string = [request responsestring]; }];
|
Object has a strong reference to the block, and inside the block there is a strong reference to the external object, which forms a closed loop and a memory leak occurs.
How to solve this kind of memory leak?
You can use the block variable to solve it, first, or to see what the official documents say:
Use Lifetime Qualifiers to Avoid strong Reference Cycles
In manual reference counting mode, with the effect of not __block id x
retaining x. In ARC mode, the __block id x
defaults to retaining X (just as all other values). To get the manual reference counting mode behavior under ARC, your could use __unsafe_unretained __block id x
;. As the name __unsafe_unretained
implies, however, having a non-retained variable are dangerous (because it can dangle) and is therefore di Scouraged. Better options __weak
is to either use (if you don't need to support IOS 4 or OS X v10.6), or set the __block
value to NI L to break the retain cycle.
The official website offers several options, let's take a look at the first, with the __block variable:
在MRC中,__block id x不会retain住x;但是在ARC中,默认是retain住x的,我们需要
使用__unsafe_unretained __block id x来达到弱引用的效果。
Then the solution is as follows:
1 2 3 4 5 6
|
Self; //MRC __unsafe_unretained __block id weakself = self; Under Arc, use this. Self. Myblock = ^{
NSLog (@ "%@", weakself };
|
Nstimer's Problem
We all know that a timer is used to execute one or more of the methods we specify at some point in the future, and then the problem comes (not the excavator, of course). How does the system ensure that the timer triggers the action when the method we specify is valid? What if receiver's not working?
答案很简单,系统会自动retain住其接收者,直到其执行我们指定的方法。
Take a look at the official documentation and suggest you write a demo test yourself.
1
|
+ (Nstimer *)repeats: (BOOL) repeats
|
Target the objectto whichToSendThe message specifiedby aselector when the timer fires. The timer maintains a strong reference to target Until it (the timer) is invalidated. (The system maintains a strong reference until the timer calls invalidated) userInfo the user info for the timer. The timer maintains a strong reference to this object until it (the timer) is invalidated. This parameter may nil.repeats If YES, the timer would repeatedly reschedule itself until invalidated. If NO, the timer would be invalidated after it fires.
It can be noted that the timer of a one-time repeats
(repeats is no) will automatically call invalidated after it is triggered, and the repetitive timer will not.
Now that's the problem again, take a look at the following code:
1 2 3 4 5
|
-(void)Dealloc { [Timer invalidate]; [Super Dealloc]; }
|
This is a very easy mistake, if the timer is a repetitive timer, then the self
object will be a timer to retain
live, this time do not call invalidate
, the self
object's reference count will be greater than 1, dealloc
never call to, This will happen if the memory leaks.
timer都会对它的target进行retain,我们需要小心对待这个target的生命周期问题,尤其是重复性的timer,同时需要注意在dealloc之前调用invalidate。
There are quite a few things that can be researched about the timer, such as it must be in the runloop, such as its time is certain? These are not related to the topic of this chapter, and we will not talk about it for the time being.
Questions about the Performselector:afterdelay
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
We're still looking at the official documentation, and we want you to write a demo to verify that.
This method sets up aTimerTo perform the aselector messageon the current thread ' s run loop. The timer is configured to run in the default mode (Nsdefaultrunloopmode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the Timer waits until the run loop is in the default mode.
It probably means that the system relies on a timer to ensure that the delay is triggered, but only if runloop
default mode
it succeeds at that time, selector
it will wait until run loop
it is switched on default mode
.
According to our previous timer
statement, here actually calls Performselector:afterdelay: the same will cause the system to target
strong references, also retain
live. This way, if you can't do it all the time selector
(for example, if runloop
it's not running default model
), it can also cause a target
memory leak that can't be released.
How to solve this problem?
In fact, it is very simple, we cancel the call at the appropriate time, the system provides an interface:
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget
This function can be dealloc
called in, you can think for yourself?
On the addobserver and removeobserver problems of nsnotification
We should notice that we will often dealloc
call inside again, will not removeObserver
the above problem?
The answer is no, because addObserver
only a weak reference is created to the receiver, so there is no memory leak. But we need to dealloc
call inside removeObserver
, avoid the notification when the object has been destroyed, this time it will happen crash
.
C-Language interface
The C language cannot call retain and release in OC, and the General C interface provides release functions (such as cgcontextrelease (context C)) to manage memory.ARC不会自动调用这些C接口的函数,所以这还是需要我们自己来进行管理的.
The following is a common drawing code, where you need to call the release interface yourself.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
Cgcontextref context =Cgbitmapcontextcreate (NULL, Target_w, Target_h,8,0, RGB, BMI); Cgcolorspacerelease (RGB); UIImage *pdfimage =Nil if (context! = null) { cgcontextdrawpdfpage (context, page); cgimageref imageref = cgbitmapcontextcreateimage (context); cgcontextrelease (context); Pdfimage = [uiimage Imagewith cgimage:imageref scale:screenscale orientation: Uiimageorientationup]; cgimagerelease (imageref); else { cgcontextrelease ( context); } /span> |
In general, arc is very useful and can help you solve most of the memory leak problems. So it is recommended that you use arc directly, and try not to use MRC.
Reference documents
- Transitioning to ARC Release Notes
- iOS app development: What is ARC?
- Blocks, Operations, and Retain Cycles
- iOS7.0 using Arc
- Block usage summary, using block in arc, how to prevent circular referencing
- What to know about Nstimer in iOS
- Use block correctly to avoid cycle retain and crash
Transferred from: http://luoyibu.com/2014/10/18/ARC%E4%B8%8B%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E5%86%85%E5%AD%98% e7%ae%a1%e7%90%86/
The memory management that needs attention under arc