IOS cyclic reference solution, ios reference solution

Source: Internet
Author: User

IOS cyclic reference solution, ios reference solution

I. BLOCK loop reference

Generally, a class uses the block as its own attribute variable, and then the class uses the class itself in the block method body. Create a circular reference.

// When defining a block, external variables are copied and strongly referenced. self itself is strongly referenced.

The solution is as follows:

1 # import "ViewController. h "2 # import" NetworkTools. h "3 4 @ interface ViewController () 5 @ property (nonatomic, strong) NetworkTools * tools; 6 @ end 7 8 @ implementation ViewController 9 // 1. release the circular references. Interrupt the reference chain! 10-(void) viewDidLoad {11 [super viewDidLoad]; 12 13 // local variables do not produce circular applications, and global attributes generate circular References 14 self. tools = [[NetworkTools alloc] init]; 15 16 // 1. when defining a block, external variables are copied once, the self will be strongly referenced. 17 18 // The method for removing the circular reference 119 // _ weak is the 20 launch of iOS 5.0 // If the asynchronous operation is not completed, release the controller, __weak itself is a weak reference 21 // when asynchronous execution is complete, callback is performed. self has been released, and attributes cannot be accessed or the method 22 // _ weak is equivalent to weak, no strong references will be made, but if the object is released, the execution address will point to nil23 // _ weak for more secure 24 _ weak typeof (self) weakSelf = Self; 25 26 // release the circular reference method 227 // _ unsafe_unretained is a 28 // MRC classic error launched by iOS 4.0, and EXC_BAD_ACCESS has bad memory access, the wild pointer 29 // is equivalent to assign and will not be strongly referenced. However, if the object is released, the memory address remains unchanged. If it is called again at this time, the access to the wild pointer 30 // _ unsafe_unretained typeof (self) weakSelf = self; 31 32 [self. tools loadData: ^ (NSString * html) {33 // strongSelf strong reference, strong reference to weakSelf, intended, after asynchronous completion, continue to execute the callback code 34 // However, it does not help !!!!!!!! 35 _ strong typeof (self) strongSelf = weakSelf; 36 37 NSLog (@ "% @", html, strongSelf. view); 38}]; 39} 40 41-(void) dealloc {42 NSLog (@ "Controller 88"); 43} 44 45 @ end

Ii. Timer NSTimer loop reference

It is mainly because from the timer's point of view that the caller self will enter dealloc when being parsed. In dealloc, the timer of the timer can be stopped and the memory can be released by the way; but from the perspective of self, he believes that timer does not stop timing and does not analyze the structure, so I will never have a chance to enter dealloc. Reference cyclically and wait for each other.

Example:

On the one hand, NSTimer is often used as a member variable of a class, while NSTimer must specify self as the target during initialization, which may easily cause loop reference. On the other hand, if timer remains in the validate state, its reference count will always be greater than 0. Let's take a look at the example of NSTimer (ARC mode ):

 1 import <Foundation/Foundation.h> 2  3 interface Friend : NSObject 4     -(void)cleanTimer; 5 end 6  7 import "Friend.h" 8  9 interface Friend ()10     STimer *_timer;11 end12 13 implementation Friend14 15 -(id)init16 {17     if (self = [super init]) {18         _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleTimer:)19         userInfo:nil repeats:YES];20     }21     return self;22 }23 24 - (void)handleTimer:(id)sender25 {26     NSLog(@"%@ say: Hi!", [self class]);27 }28 29 - (void)cleanTimer30 {31     [_timer invalidate];32     _timer = nil;33 }34 35 - (void)dealloc36 {37     [self cleanTimer];38     NSLog(@"[Friend class] is dealloced");39 }40 41 @end

Initialize a Friend object outside the class, and release the friend after a delay of 5 seconds (external running in a non-arc environment)

1 Friend *f = [[Friend alloc] init];2 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{3     [f release];4 });

The expected result is that, 5 seconds after initialization, the f object is release, the dealloc method of f is called, the timer in dealloc is invalid, and the object is destructed. But the result is as follows:

1 18:00:35. 300 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 2 18:00:36. 299 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 3 18:00:37. 300 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 4 18:00:38. 299 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 5 18:00:39. 299 WZLCodeLibrary [41422: 3390529] Friend say: Hi! // Failed to stop as expected 6 18:00:40. 299 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 7 18:00:41. 300 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 8 18:00:42. 300 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 9 18:00:43. 299 WZLCodeLibrary [41422: 3390529] Friend say: Hi! 10 18:00:44. 300 WZLCodeLibrary [41422: 3390529] Friend say: Hi! <Br> ...... it cannot be stopped .....

Why? It is mainly because from the timer's point of view that the caller (Friend object) will enter dealloc when it is parsed. In dealloc, the timer of the timer can be stopped and the memory is released; but from the perspective of Friend, he thinks that timer does not stop timing and does not analyze the structure, so I will never have a chance to enter dealloc. Reference cyclically and wait for each other. The crux of the problem is that the call time of the-(void) cleanTimer function is incorrect. Obviously, it cannot be put in the caller's dealloc. A better solution is to open this function so that the Friend caller can explicitly call it to clear the site. As follows:

1 Friend *f = [[Friend alloc] init];2 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{3     [f cleanTimer];4     [f release];5 });

3. delegate

The issue of circular references on delegation is already a commonplace, and this article will not be detailed. The killer to avoid this problem is also simple to cry. A word: Use assign (MRC) to declare delegate) or weak (ARC), do not play retain or strong. After all, this basically cannot escape the loop reference!

What we mentioned above is common. In fact, circular reference means that our strong reference forms a closed loop, and there will also be a lot of self-written code. We should pay attention to writing the code at ordinary times.

Sorry, I will try again to explain it further:

Loop Reference refers to the process where multiple objects reference each other to form a ring. As a result, it is impossible for the external entities to truly cancel the ring memory. In fact, it is similar to a deadlock. For example, A-> B-> C-> .... -> X-> B-> indicates strong reference. In this case, the reference count of B is 2. If A is released by the system, theoretically A will automatically reduce the resources referenced by, that is B, then the reference count of B is changed to 1, and all B cannot be released. However, A has been released, the memory of all B instances cannot be released and reused, leading to memory leakage. Scenario 1: delegateDelegate is the most common cyclic reference in ios development. Generally, weak or assign @ property (nonatomic, weak, nullable) must be used to declare delegate) id <UITableViewDelegate> delegate; of course, how can we choose whether to use assign or weak? MRC can only use assign. We recommend that you use weak in the case of ARC, because weak-modified variables automatically point to nil after or not, preventing insecure wild pointers. 2. BlockBlock is also a common issue of loop reference, when self is used in a Block, it is prone to circular references. Therefore, many people declare a _ weak to modify self when they use the block. In fact, this is not the case. Not all blocks used will have the Self loop reference problem. This is the case only when self has the strong reference of the Block. Therefore, when Block is used temporarily in a function, circular applications are not displayed, because Block reference belongs to the stack at this time. When the block on the stack is released, the reference count of self in the block will also be reduced. Of course, it is not necessary for Self to directly reference the Block. If the self variable is B, B has a Block variable, which is prone to this situation. Good news is that circular reference occurs in the block, and xcode7 will prompt a warning (the previous version is not clear ). Case 3: NSTimer This is a magic NSTimer. When you create and use NSTimer, NSTimer will have a strong reference to the current self by default, and all the time when self is used to complete the plan, use the invalidate of NSTimer to stop whether to control the reference to self [_ timer invalidate];

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.