背景:
最近項目要做上傳圖片功能坟奥,圖片必須是高清的述吸,所以不讓壓縮优俘,上傳圖片是大量的曹傀,比如幾百張,這個如果是用afn植阴,將圖片直接for循環(huán)加入到formData里會出現(xiàn)一個問題,臨時變量太多,導(dǎo)致內(nèi)存緊張察净,最后程序奔潰。之前寫過用自動釋放池解決它盼樟,但是還是效果不大氢卡。如果上傳的多的話,內(nèi)存還是受不了晨缴。
解決辦法一適用于圖片少量的如40張圖片
我之前寫的在這译秦,可以看看自動釋放池的方法,如果你上傳圖片的數(shù)量不多的話击碗,可以用這種方法筑悴。也很簡單的。鏈接在這里http://www.reibang.com/p/9e84fe63d5c0
解決辦法二適用于圖片大量的如1000張圖片
思考稍途,為甚內(nèi)存會占用那么多呢阁吝?就是因為圖片一口氣讀到內(nèi)存中了。如果咱們上傳三五張圖片械拍,肯定不會出問題突勇。如何把1000張圖片分開傳呢?所以必須要用到多線程的知識坷虑。創(chuàng)建個隊列甲馋。然后挨個傳。注意不要把文件存到隊列里迄损,只要先存一個文件名定躏,執(zhí)行的時候再去讀取文件的內(nèi)容。如果要是將image傳給隊列芹敌,內(nèi)存還是會爆的痊远。所以存?zhèn)€圖片名字。一個字符串肯定沒有image占用的內(nèi)存大吧党窜。上代碼吧拗引。我的圖片來源于相冊,所以我用的圖片id幌衣。
/**
創(chuàng)建隊列然后開始上傳圖片
@param LocalIdArray 獲取相冊的圖片id數(shù)組矾削,如果你是本地的就傳遞圖片名字?jǐn)?shù)組壤玫,或者是沙盒的文件名字?jǐn)?shù)組
*/
- (void)uploadOperation:(NSArray *)LocalIdArray
{
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
self.queue = queue;
//這個就是控制同時上傳幾張圖片的,如果是1的話就是串行隊列了哼凯。我是4欲间,是并行隊列。
queue.maxConcurrentOperationCount = 4;
for (int i = 0; i<LocalIdArray.count; i++)
{
//加上自動釋放池断部,及時的釋放臨時變量猎贴,防止內(nèi)存奔潰
@autoreleasepool {
NSString *imageName = [NSString stringWithFormat:@"up_%d.jpg",i];
WS(weakSelf)
//創(chuàng)建一個任務(wù)
NSBlockOperation *uploadOperation = [NSBlockOperation blockOperationWithBlock:^{
[weakSelf uploadTaskWithLocalId:LocalIdArray[i] imageount:LocalIdArray.count imageName:imageName];
}];
//將任務(wù)加入到隊列中
[queue addOperation:uploadOperation];
}
}
}
/**
開始上傳單張圖片
@param LocalId 圖片的id
@param count 一共上傳多少張圖片
@param imageName 圖片的名稱
*/
- (void)uploadTaskWithLocalId:(NSString *)LocalId imageount:(NSInteger)count imageName:(NSString *)imageName
{
//通過圖片的id轉(zhuǎn)化為image,如果是圖片名字或者是沙盒圖片文件名字那更簡單了。
CustomAlbumTool *customAlbumTool = [CustomAlbumTool sharedCustomAlbumTool];
PHFetchResult<PHAsset *> *upAssetArr = [PHAsset fetchAssetsWithLocalIdentifiers:@[LocalId] options:nil];
PHAsset *asset = [upAssetArr firstObject];
UIImage *image = [customAlbumTool getImageWithAsset:asset targetSize:PHImageManagerMaximumSize];
//afn上傳的參數(shù)
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
dic[@"xxx"] = [UserDataCenter xxx];
dic[@"xxx"] = self.xxx;
//因為afn上傳是異步執(zhí)行的所以創(chuàng)建一個信號量蝴光。就是為了讓一個任務(wù)完全的執(zhí)行完畢后才執(zhí)行下一個任務(wù)她渴。加信號量就是為了把afn異步轉(zhuǎn)化為同步。如果不轉(zhuǎn)化的話蔑祟。queue.maxConcurrentOperationCount = 1趁耗,也沒辦法做到隊列內(nèi)同步。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
WS(weakSelf)
[SWAYNetWorking uploadWithUrl:uploadModelUrl parameters:dic constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSData *data = UIImageJPEGRepresentation(image, 1.0);
[formData appendPartWithFileData:data name:@"file" fileName:imageName mimeType:@"image/jpeg"];
} withProgress:^(NSProgress *uploadProgress) {
} success:^(id responseObject) {
//圖片成功了讓信號量加1
dispatch_semaphore_signal(semaphore);
} failure:^(NSError *error) {
//圖片傳失敗了讓信號量加1
dispatch_semaphore_signal(semaphore);
}];
//信號量等待疆虚。DISPATCH_TIME_FOREVER 永遠(yuǎn)等到吧苛败。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
監(jiān)聽全部成功刷新ui,可以定義個int型變量径簿,上傳成功一張圖片加1罢屈。如果等于總的圖片數(shù)量就相當(dāng)于上傳完成了,那么就刷新UI吧篇亭。也可以創(chuàng)建個上傳成功刷新UI的任務(wù)缠捌。添加依賴。在任務(wù)里執(zhí)行刷新UI暗赶。
/**
創(chuàng)建隊列然后開始上傳圖片
@param LocalIdArray 獲取相冊的圖片id數(shù)組鄙币,如果你是本地的就傳遞圖片名字?jǐn)?shù)組,或者是沙盒的文件名字?jǐn)?shù)組
*/
- (void)uploadOperation:(NSArray *)LocalIdArray
{
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
self.queue = queue;
//這個就是控制同時上傳幾張圖片的蹂随,如果是1的話就是串行隊列了十嘿。我是4,是并行隊列岳锁。
queue.maxConcurrentOperationCount = 4;
NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 回到主線程執(zhí)行绩衷,方便更新 UI 等
}];
}];
for (int i = 0; i<LocalIdArray.count; i++)
{
//加上自動釋放池,及時的釋放臨時變量激率,防止內(nèi)存奔潰
@autoreleasepool {
NSString *imageName = [NSString stringWithFormat:@"up_%d.jpg",i];
WS(weakSelf)
//創(chuàng)建一個任務(wù)
NSBlockOperation *uploadOperation = [NSBlockOperation blockOperationWithBlock:^{
[weakSelf uploadTaskWithLocalId:LocalIdArray[i] imageount:LocalIdArray.count imageName:imageName];
}];
//添加依賴咳燕。
[completionOperation addDependency:uploadOperation];
//將任務(wù)加入到隊列中
[queue addOperation:uploadOperation];
}
}
//將刷新UI的任務(wù)加入隊列,當(dāng)所有的上傳任務(wù)結(jié)束才會調(diào)用completionOperation乒躺。
[queue addOperation:completionOperation];
}
如果要是你的業(yè)務(wù)是不能讓一張圖片傳遞失敗招盲,那么當(dāng)有一張圖沒有傳成功的話就直接取消所有任務(wù)就行了。
[weakSelf.queue cancelAllOperations];