iOS 內存泄漏

  我一直覺得如今都是自動內存管理了,還哪有什麼內存泄漏啊。一檢測才知道,不是我太相信Xcode了,就是我太單純了。iOS開發中遇到的內存泄漏主要有幾下幾種:
(1)對象不能釋放。使用Core Foundation對象的時候要特別注意,由於他仍是MRC,須要本身釋放對象。
(2)野指針。這兒比較危險,調用一個不屬於你的對象,發生什麼誰都不知道。
(3)空指針。OC這一點很好,若是你往一個空對象發送消息不會報錯和崩潰。
  檢測內存泄漏我通常用兩種工具Analyze、Leaks。本文主要介紹我在開發中遇到的內存泄漏問題的緣由和解決方案,至於怎麼使用這兩個檢測工具能夠看這篇文章,之後會不斷更新。objective-c

Analyze 檢測的問題

1、Memory error

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];
}

2、Merrory(Core Foundation/Objective-C)

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也就沒有意義了,由於不可能一直有錯誤。
處理:暫時還不知道,有沒有哪位大神能夠告訴啊指針

Leaks 檢測的問題

一.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
相關文章
相關標籤/搜索