What about memory leaks, which you don’t know?


I haven’t written anything for a long time, because I have been lazy recently, and I can’t find any good subject matter, so I’m ready to do a sort of memory leak problem. Memory leak problem has been a major problem in the development of the project, this paper aims to help iOS developers engaged in a period of time to quickly find the App memory leak problem. Part of the comparison of the basic content, God can not ignore the spray.

First, starting from AFNet

For iOS developers, AFNetWorking network requests are familiar, for the use of AFNetWorking for general parameters, we usually address environment switching, network monitoring, request error information for package. It is important to note that the request queue manager AFHTTPSessionManager is declared as a singleton creation in the encapsulation of network requests. For this problem, the author of AFNetWorking in gitHub also pointed out that the proposal ensure that users of AFHTTPSessionManager is only one in the same configuration, global management, so we can be solved by a single case form. Show some of the core code below:

+ (AFHTTPSessionManager*) defaultNetManager static AFHTTPSessionManager static dispatch_once_t {*manager; onceToken; dispatch_once (& onceToken, manager ^{= [[AFHTTPSessionManager alloc]init]; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; return manager;}});
(void) + GET: (NSString*) URL parameters: (NSDictionary*) parameter (returnData: (void ^) (NSData * resultData, NSError * error) returnBlock{) / / request queue managers form singleton creation prevent memory leaks AFHTTPSessionManager * Manager = [HttpRequest defaultNetManager] [manager GET:url parameters:parameter; progress:^ (NSProgress * _Nonnull downloadProgress) {success:^} (NSURLSessionDataTask * _Nonnull task ID, _Nullable responseObject) {returnBlock (responseObject, Nil);} failure:^ (NSURLSessionDataTask * _Nullable task NSError * _Nonnull error) {returnBlock (nil, error);}];}
Two, Block cycle reference

Block cycle of the problem has been cited frequently talked about, so far there are many articles to explain in detail the principle and cause of the cycle of the reasons cited, etc., do not pan or cited examples, here is not to repeat. To sum up a word to prevent Block circular reference is to prevent the closed loop between the reference object. For example, the development of a lot of people in the use of MJRefresh talk about

Self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{self.page = 1; [self.dataArr removeAllObjects]; [self loadData];}];

If the current self or its attributes are called in the MJRefresh execution Block, be sure to pay attention to the circular reference problem. We simply analyze why the MJRefresh will cause a circular reference problem:
click into the corresponding headerWithRefreshingBlock method can be

#pragma - mark + headerWithRefreshingBlock: construction method (instancetype) (MJRefreshComponentRefreshingBlock) refreshingBlock *cmp alloc] init] {MJRefreshHeader = [[self; cmp.refreshingBlock = refreshingBlock; return CMP;}

There are only three lines of code, it is created and then return to the View pull-down refresh, here the more important is cmp.refreshingBlock = refreshingBlock; this one, where refreshingBlock is belong to MJRefreshHeader strong reference attributes, finally header will become strong our own tableView reference attribute mj_header, self.tableView is a strong reference header, header strong reference refreshingBlock, if refreshingBlock strong reference self, became a circular reference, so we must use weakSelf to break this cycle. Draw as:

Schematic diagram of What about memory leaks, which you don't know?
cyclic reference

closed loop:
self—> self.tableView—> self.tableView.mj_header—> self.tableView.mj_header.refreshingBlock—> self

Solutions we should not unfamiliar

__weak typeof (self) weakself = self; self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{__strong typeof (self) strongself = weakself; strongself.page = 1; [strongself.dataArr removeAllObjects]; [strongself loadData];}];

[up strongself in order to prevent memory early release, interested in children’s shoes can understand, do not make too much explanation. Of course, can also be used to solve the libextobjc library, writing for @weakify and @strongify will be more convenient.
corresponding to the custom View in some of the Block value issues also need to pay attention to, similar to the above.

Three, delegate cycle reference problem

Delegate cycle reference problem based on comparison, just note that the proxy attribute can be modified to weak

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

The image below illustrates the use of the weak modifier in order to prevent ViewController and UITableView from strong references to memory problems that cannot be released:

What about memory leaks, which you don't know?
delegate loop reference
Four, NSTimer cycle reference

For the timer NSTimer, incorrect use can also cause memory leaks. Here, for example, we declare a class TestNSTimer, which creates a timer execution in its init method.

#import "TestNSTimer.h" @interface (TestNSTimer) @property (nonatomic, strong) NSTimer *timer; @end @implementation TestNSTimer (instancetype init) {if (self = [super init]) {_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector (timeRefresh:) userInfo:nil repeats:YES] return self;};} - (void) timeRefresh: (NSTimer*) {NSLog (@ timer "TimeRefresh...");} - (void) cleanTimer {[_timer invalidate]; _timer = nil;} - {[super (void) dealloc dealloc]; NSLog (@ "destroy"); [self cleanTimer] @end;}

When an external call is created, it will be destroyed in 5 seconds.

TestNSTimer *timer = [[TestNSTimer alloc]init]; dispatch_after (dispatch_time (DISPATCH_TIME_NOW (int64_t) (5 * NSEC_PER_SEC)), dispatch_get_main_queue ([timer), ^{release];});

The final result is

What about memory leaks, which you don't know?
NSTimer print results

TestNSTimer objects can not be normal release, the timer is still unlimited execution.

We all know the timer after use need to stop and hover, but in the end when calling the cleanTimer method? In the dealloc method of the current class? If not, will call the cleanTimer method will produce the following problems in the dealloc method, the current class dealloc is a prerequisite for the implementation of the destruction of the timer need to stop and hover, and hover in the timing of the timer stops and the dealloc method is called, thus waiting for each scene, which has been unable to release the memory. Therefore, we need to pay attention to the timing of the cleanTimer call to avoid memory can not be released, as the solution to the cleanTimer method, the external call can be.

TestNSTimer *timer = [[TestNSTimer alloc]init]; dispatch_after (dispatch_time (DISPATCH_TIME_NOW (int64_t) (5 * NSEC_PER_SEC)), dispatch_get_main_queue ([timer), ^{cleanTimer]; [timer release];});
What about memory leaks, which you don't know?
print results
Five, non OC object memory processing

For iOS development, ARC model has been developed for many years, many people may have forgotten that year retain, release era, but the emergence of ARC is not to say that we can completely ignore the problem of memory leaks. For some non OC objects, the memory will still need to be manually released after use.
for example, such as the commonly used filter operation to adjust the brightness of the picture

CIImage *beginImage = [[CIImage alloc]initWithImage:[UIImage imageNamed:@ "yourname.jpg" CIFilter "; *filter filterWithName:@ [CIFilter =" CIColorControls "]; [filter setValue:beginImage forKey:kCIInputImageKey]; [filter setValue:[NSNumber numberWithFloat:.5] forKey:@" inputBrightness "]; / / -1~1 CIImage *outputImage = [filter outputImage] brightness; //GPU eaglContext = [[EAGLContext alloc] * EAGLContext optimization initWithAPI:kEAGLRenderingAPIOpenGLES3]; eaglContext.multiThreaded = YES; CIContext = *context [CIContext contextWithEAGLContext:eaglContext]; [EAGLContext setCurrentContext:eaglContext]; CGImageRef ref = [context createCGImage:outputImage fromRect:outputImage.extent]; UIImage *endImg [UIImage = imageWithCGImage:ref]; _imageView.image = endImg CGImageRelease; (Ref); / / non OC objects need to manually release the memory

The CGImageRef type variable in the above code is not a OC object, which needs to be manually performed to release CGImageRelease (Ref), otherwise it will cause a lot of memory leaks that cause the program to crash. Other CoreFoundation framework for certain objects or variables need to be manually released, C language code malloc, etc. need to pay attention to free, etc..

Five, map class

Use the map related if the project, must detect memory, because the map is more expensive App memory, so in the realization of a map document according to the relevant functions at the same time, we need to pay attention to the right to release memory, generally need to pay attention to the need to use at the end of the map, such as air agent nil, attention map mark (PIN) reuse, and clear in the use of finished label array.

- (void) clearMapView{self.mapView = nil; self.mapView.delegate =nil; self.mapView.showsUserLocation = NO; [self.mapView removeAnnotations:self.annotations]; [self.mapView removeOverlays:self.overlays]; [self.mapView setCompassImage:nil];}
Six, a large number of cycles of memory inflation problem

Remember there is a more classic interview questions, see what the following code:

For (int i = 0; I 100000; < i++) {NSString = *string @ string = "Abc"; [string lowercaseString]; string [string stringByAppendingString:@ = "XYZ"]; NSLog (@ "% @", string);}

Have a lot of temporary objects inside the loop, until the cycle before the end of the release, may lead to memory leaks, the solution for creating your own autoReleasePool in the cycle, the timely release of memory for temporary variables, reduce peak memory.

For (int i = 0; I 100000; < i++) {@autoreleasepool {NSString = *string @ string = "Abc"; [string lowercaseString]; string [string stringByAppendingString:@ = "XYZ"]; NSLog (@ "% @", string);}}

If you are unfamiliar with autoReleasePool, access to relevant information, after all, can not be described in one or two.

Attached, how to detect App memory leak problem

1, by using Xcode’s Instruments tool (up selection testing)

What about memory leaks, which you don't know?

2, a simple rewrite of the dealloc method of violence, add breakpoints or print to determine whether a normal release.

What about memory leaks, which you don't know?

3, Facebook produced by the FBMemoryProfiler tool class for testing, interested children’s shoes can be understood.

For now, to be continued