最近發(fā)現(xiàn)應(yīng)用有卡頓現(xiàn)象,后來仔細(xì)查找,發(fā)現(xiàn)有幾個地方是挺耗內(nèi)存的。
1.應(yīng)用中使用了地圖,頁面返回的時候,地圖緩存沒有清理
2.網(wǎng)絡(luò)請求,頁面返回的時候沒有終止網(wǎng)絡(luò)加載任務(wù)
3.加載的h5頁面,沒有進(jìn)行緩存,著實體驗不佳,每次都要加載
4.dealloc方法,為什么沒有執(zhí)行?
5.app中怎樣減少loading,達(dá)到更順暢的體驗
針對以上問題,進(jìn)行了一系列的檢索,實驗,不過慶幸的是,差不多一天的時間,把這些問題都解決了,現(xiàn)做一下整理。
解決問題1.應(yīng)用中使用了地圖,頁面返回的時候,地圖緩存沒有清理
應(yīng)用中使用了地圖,頁面返回的時候,地圖緩存沒有清理,項目中集成了蘋果地圖,發(fā)現(xiàn)每次打開地圖界面,內(nèi)存都會上升幾十M,并且一直上升不降,直到卡死,造成這一結(jié)果的根本原因是地圖的mapView沒有釋放,導(dǎo)致每次打開地圖界面的時候內(nèi)存中都重新加載了一個地圖mapView。于是在網(wǎng)上搜索了一番找到了解決辦法,只需要在地圖的ViewController中dealloc方法中釋放掉mapView,將mapView設(shè)置成nil就行了。詳見博客地址:http://blog.csdn.net/isalvador/article/details/51082860,具體代碼如下:
//并且在界面將要顯示的時候設(shè)置代理,將要消失的時候取消代理
- (void)viewWillAppear:(BOOL)animated {
_mapView.delegate = self;
}
- (void)viewWillDisappear:(BOOL)animated {
_mapView.delegate = nil;
}
- (void)dealloc{
if (_mapView) {
_mapView = nil;
}
}
備注:如果沒有調(diào)用dealloc方法,請查看問題4的解決方法
解決問題2.網(wǎng)絡(luò)請求,頁面返回的時候沒有終止網(wǎng)絡(luò)加載任務(wù)
根據(jù)簡書上的文章iOS取消界面的網(wǎng)絡(luò)請求得到的答案:要取消網(wǎng)絡(luò)請求,就需要一個類NSURLSessionDataTask的對象方法-cancel,有時候一個頁面可能有多個請求,這個時候怎么辦呢?對,可以將每個task放在數(shù)組里,然后在頁面退出調(diào)用dealloc方法時,遍歷一下這個數(shù)組,判斷如果有正在執(zhí)行中的任務(wù)取消掉就可以了。就是這么簡單!
// 將請求任務(wù)添加到數(shù)組中,以post方式為例,get方式相同
NSURLSessionDataTask *urlTask = [self.httpSessionManager POST:URLString parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
DebugLog(@"====請求成功獲取到的數(shù)據(jù)====%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
DebugLog(@"error ==>%@",error);
}];
[self.urlTaskArray addObject:urlTask];
// 然后在這里遍歷數(shù)組,取消掉正在執(zhí)行的任務(wù)
- (void)dealloc{
if (self.urlTaskArray.count) {
for (NSURLSessionDataTask *urlTask in self.urlTaskArray) {
if (urlTask.state == NSURLSessionTaskStateRunning) {
[urlTask cancel];
}
}
}
}
解決問題3.加載的h5頁面,沒有進(jìn)行緩存,著實體驗不佳,每次都要加載
思路是第一次加載之后進(jìn)行緩存,下次直接從緩存中獲取,不用再次加載,詳見我的另一篇文章
iOS 緩存之(WebView)網(wǎng)頁緩存
解決問題4.dealloc方法,為什么沒有執(zhí)行?
根本原因是當(dāng)前的控制器的引用計數(shù)不為1,就是說可能存在沒有被釋放的情況,造成了循環(huán)引用。
可能有這幾種情況:
1>代理屬性是否使用assign進(jìn)行修飾,而不是weak,assign比weak少了一個功能,對象不用時不能自動設(shè)置成nil。
2>block中是否使self,而不是__weak typeof(self) weakSelf = self; 中的weakSelf,造成了相互持有,都不能釋放掉。
3>遵守的協(xié)議有沒有設(shè)置能nil。
- (void)viewWillAppear:(BOOL)animated {
_mapView.delegate = self;
}
- (void)viewWillDisappear:(BOOL)animated {
_mapView.delegate = nil;
}
經(jīng)過鄙人的測試,一般就是這幾個問題造成的,如果還是沒有執(zhí)行dealloc方法,請反復(fù)進(jìn)行核實以上步驟。
解決5.app中怎樣減少loading,達(dá)到更順暢的體驗
情形1>app中有兩個詳情頁面需要先加載圖片,然后在顯示其他內(nèi)容,而且圖片也是要加載原圖,因為圖片質(zhì)量較高,所以添加了loading,是的使用了SDWebImage進(jìn)行緩存,但是每次都顯示loading體驗不太好。解決方法,每次顯示loaidng前,先進(jìn)行判斷如果有緩存,將不顯示loading直接從緩存中取得圖片。獲取SDWebImage緩存的方法
// 因為這個方法在子線程(全局隊列)中執(zhí)行,所以不需要考慮死線程的問題
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager diskImageExistsForURL:pathUrl]; // pathUrl 是你要加載圖片的url
if ([manager diskImageExistsForURL:pathUrl]) {
UIImage *image = [[manager imageCache] imageFromDiskCacheForKey:pathUrl.absoluteString];
[self loadSquarePhotoWithImage:image];
}else{
[SVProgressHUD show];
UIImageView *tappedImageView = [[UIImageView alloc]init];
__weak typeof(self) weakSelf = self;
[tappedImageView sd_setImageWithURL:pathUrl placeholderImage:nil options:SDWebImageProgressiveDownload completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
tappedImageView.image = image;
[weakSelf loadSquarePhotoWithImage:image];
[SVProgressHUD dismiss];
}];
}
情形2>每次加載h5的時候,考慮到網(wǎng)絡(luò)情況不穩(wěn)定,網(wǎng)速慢的情況,添加了loading,但是每次打開都要顯示loading,都要加載一次,體驗不好。
思路是第一次加載顯示loading,加載完成之后進(jìn)行緩存,下次直接從緩存中獲取,不用再次加載,也不用在顯示loading了,詳見我的另一篇文章
iOS 緩存之(WebView)網(wǎng)頁緩存