我一直覺得如今都是自動內存管理了,還哪有什麼內存泄漏啊。一檢測才知道,不是我太相信Xcode了,就是我太單純了。iOS開發中遇到的內存泄漏主要有幾下幾種:
(1)對象不能釋放。使用Core Foundation對象的時候要特別注意,由於他仍是MRC,須要本身釋放對象。
(2)野指針。這兒比較危險,調用一個不屬於你的對象,發生什麼誰都不知道。
(3)空指針。OC這一點很好,若是你往一個空對象發送消息不會報錯和崩潰。
檢測內存泄漏我通常用兩種工具Analyze、Leaks。本文主要介紹我在開發中遇到的內存泄漏問題的緣由和解決方案,至於怎麼使用這兩個檢測工具能夠看這篇文章,之後會不斷更新。objective-c
1.Null passed to a callee that requires a non-null 1st parameter
調用的方法須要一個非空的參數。
e.g:框架
UIImage *image = [UIImage imageWithData:data];
緣由:把二進制數據流轉換成圖片,若是data爲nil,就不該該調用這個方法。不過不會崩潰,親測。
修改:函數
if(data) { UIImage *image = [UIImage imageWithData:data]; }
1.Potential leak of an object stored into ‘cs’
調用了讓某個對象引用計數加1的函數,但沒有調用相應讓其引用計數減1的函數。
e.g:工具
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
緣由:Core Foundation是一組C語言框架,不是ARC的,須要手動釋放內存,這個比較坑。
修改:post
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone); CGColorSpaceRelease(cs);
(三)Dead store
1.Value stored to ‘payResoult’ during its initialization is never read.
存儲在'payResoult'裏的值從未被讀取過。
e.g:ui
NSString *str = @"Dead store "; str = @"Dead store never used";
緣由:你往內存裏申請了空間,存了值,可是你存的值歷來沒有用過,因此白白消耗了內存。
處理:既然沒用就刪去吧。atom
(四)Coding Conventions(Apple)
Method accepting NSError** should have a non-void value to indicatie whether or not an error occurred;
e.g:spa
- (void)doDecodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints results:(NSMutableArray *)results xOffset:(int)xOffset yOffset:(int)yOffset currentDepth:(int)currentDepth error:(NSError **)error;
緣由: (NSError**)error -> error 的地址(&error)。當error爲nil的時候,&error也就沒有意義了,由於不可能一直有錯誤。
處理:暫時還不知道,有沒有哪位大神能夠告訴啊指針
一.AFNetworking
e.gcode
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer];//請求 manager.responseSerializer = [AFHTTPResponseSerializer serializer];//響應 manager.requestSerializer.timeoutInterval = 5.0f; [manager POST:strURL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) { } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { responseObject = [FHTool ResultDic:responseObject]; if (responseObject) { if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeSuccess,responseObject); } }else { if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeFailed,nil); } } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"strURL = %@\n error = %@",strURL,error.localizedDescription); if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeFailed,@{@"error":error.localizedDescription}); } }];
緣由: 每次請求數據,都會建立一個AFHTTPSessionManager對象,而在ARC模式下,他們不可以被釋放。
解決:把數據請求類封裝成一個單例,只建立一個AFHTTPSessionManager對象。
NetworkManager.h
#import <Foundation/Foundation.h> #import <AFNetworking.h> typedef void (^NetworkInfoBLock)(NetworkReturnCode networkReturnCode ,NSDictionary *responseObject); @interface NetworkManager : NSObject @property (nonatomic, strong) AFHTTPSessionManager *manager; + (instancetype) shareNetworkManager; // post - (void)postNetworkByURL: (NSString *)strURL AndParameter: (id)parameters AndNetworkSuccessBLock: (NetworkInfoBLock)networkInfoBLock; @end
NetworkManager.m
#import "NetworkManager.h" @implementation NetworkManager + (instancetype) shareNetworkManager { static NetworkManager * networkManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ networkManager = [[NetworkManager alloc] init]; AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer];//請求 manager.responseSerializer = [AFHTTPResponseSerializer serializer];//響應 manager.requestSerializer.timeoutInterval = 5.0f; networkManager.manager = manager; }); return networkManager; } - (void)postNetworkByURL: (NSString *)strURL AndParameter: (id)parameters AndNetworkSuccessBLock: (NetworkInfoBLock)networkInfoBLock { [self.manager POST:strURL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) { } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { responseObject = [FHTool ResultDic:responseObject]; if (responseObject) { if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeSuccess,responseObject); } }else { if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeFailed,nil); } } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"strURL = %@\n error = %@",strURL,error.localizedDescription); if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeFailed,@{@"error":error.localizedDescription}); } }]; } @end