iOS AFNetworking 多文件上傳

之所以總結(jié)一下, 是因?yàn)榫W(wǎng)上搜到的寫(xiě)的并不太好, 特此整理一下, 包含單文件上傳, 多文件并行上傳, 多文件串行上傳

傳遞格式

dictionary包含了name, filename, data 分別對(duì)應(yīng)對(duì)象句柄變量名, 傳遞文件名, 傳遞文件二進(jìn)制/本地url
全部使用multipart/form-data表單模擬上傳

默認(rèn)params都通過(guò)字典傳遞, 并且都使用post方式發(fā)送變量參數(shù)

單文件上傳

我對(duì)其進(jìn)行了少許修改, 如果發(fā)的data類型是nsdata或者是nsurl, 進(jìn)入不同的api, 這里并沒(méi)有特別的

+(NSURLSessionUploadTask*)uploadTaskUrl:(NSURL*)uploadPage params:(NSDictionary*)params file:(NSDictionary<NSString*,id>*)unitData completion:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionBlock {
    // 構(gòu)造 NSURLRequest
    NSLog(@"url %@\nparam %@",uploadPage,params);
    NSError* error = NULL;
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[uploadPage absoluteString] parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        if (unitData && [unitData objectForKey:@"key"] && [unitData objectForKey:@"filename"] && [unitData objectForKey:@"data"]) {
            if ([[unitData objectForKey:@"data"] isKindOfClass:[NSData class]]) {
                [formData appendPartWithFileData:(NSData*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data"];
            }else if([[unitData objectForKey:@"data"] isKindOfClass:[NSURL class]]){
                [formData appendPartWithFileURL:(NSURL*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data" error:nil];
            }
        }
    } error:&error];
    NSLog(@"error %@",error);
    // 可在此處配置驗(yàn)證信息
    // 將 NSURLRequest 與 completionBlock 包裝為 NSURLSessionUploadTask
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {
    } completionHandler:completionBlock];
    return uploadTask;
}

多文件串行上傳 (不推薦)

對(duì)接口進(jìn)行多次調(diào)用, 每次只傳一個(gè)文件, 通過(guò)線程控制序列, 缺點(diǎn)是返回多個(gè)結(jié)果, 因?yàn)槭嵌啻畏?wù)器交互訪問(wèn), 這也是從網(wǎng)上找下來(lái)的, 網(wǎng)上可以搜到一大片, 關(guān)于多文件上傳, 大概有2~3種這樣做的方法, 個(gè)人認(rèn)為既然官方支持append api, 那么就說(shuō)明插入的數(shù)據(jù)是可以多重的, 也就有了并行上傳的方法, 不需要再管進(jìn)程的事更方便

+(void)uploadTasks:(NSURL*)uploadPage files:(NSArray<NSDictionary<NSString*,id>*>*)arrFiles progress:(void(^)(float progress))onProgress complete:(void(^)(NSArray<NSDictionary*>* result))onComplete error:(void(^)(NSError* error))onError{
    // 需要上傳的數(shù)據(jù)
    // 準(zhǔn)備保存結(jié)果的數(shù)組,元素個(gè)數(shù)與上傳的圖片個(gè)數(shù)相同胞四,先用 NSNull 占位
    NSMutableArray* result = [NSMutableArray array];
    for (NSInteger i=arrFiles.count;i>0;i--) {
        [result addObject:[NSNull null]];
    }
    dispatch_group_t group = dispatch_group_create();
    for (NSInteger i = 0; i < arrFiles.count; i++) {
        dispatch_group_enter(group);
        NSURLSessionUploadTask* uploadTask = [self uploadTaskUrl:uploadPage params:@{} file:arrFiles[i] completion:^(NSURLResponse *response, NSDictionary* responseObject, NSError *error) {
            onProgress((float)i/arrFiles.count);
            if (error) {
                NSLog(@"第 %d 張圖片上傳失敗: %@", (int)i + 1, error);
                onError(error);
                dispatch_group_leave(group);
            } else {
                NSLog(@"第 %d 張圖片上傳成功: %@", (int)i + 1, responseObject);
                @synchronized (result) { // NSMutableArray 是線程不安全的娇钱,所以加個(gè)同步鎖
                    result[i] = responseObject;
                }
                dispatch_group_leave(group);
            }
        }];
        [uploadTask resume];
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"上傳完成!");
        for (id response in result) {
            NSLog(@"%@", response);
        }
        onComplete(result);
    });
}

多文件并行上傳 (推薦)

所謂并行上傳, 也就是對(duì)同一個(gè)接口同時(shí)傳遞多個(gè)二進(jìn)制文件/url, 因?yàn)橛械臅r(shí)候是需要實(shí)現(xiàn)這一功能的, 同時(shí)上傳多個(gè)文件但只需一次服務(wù)器訪問(wèn)

+(NSURLSessionUploadTask*)uploadTaskUrl:(NSURL*)uploadPage params:(NSDictionary*)params files:(NSArray<NSDictionary<NSString*,id>*>*)fileDatas completion:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionBlock {
    NSLog(@"url %@\nparam %@",uploadPage,params);
    NSError* error = NULL;
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[uploadPage absoluteString] parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        for (int i=0; i<fileDatas.count; i++) {
            NSDictionary* unitData = fileDatas[i];
            if (unitData && [unitData objectForKey:@"key"] && [unitData objectForKey:@"filename"] && [unitData objectForKey:@"data"]) {
                if ([[unitData objectForKey:@"data"] isKindOfClass:[NSData class]]) {
                    [formData appendPartWithFileData:(NSData*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data"];
                }else if([[unitData objectForKey:@"data"] isKindOfClass:[NSURL class]]){
                    [formData appendPartWithFileURL:(NSURL*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data" error:nil];
                }
            }
        }
    } error:&error];
    NSLog(@"error %@",error);
    // 將 NSURLRequest 與 completionBlock 包裝為 NSURLSessionUploadTask
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {
    } completionHandler:completionBlock];
    return uploadTask;
}

喜歡就收藏個(gè)吧, 順便投個(gè)幣

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隘谣,一起剝皮案震驚了整個(gè)濱河市碧注,隨后出現(xiàn)的幾起案子坎缭,更是在濱河造成了極大的恐慌拙吉,老刑警劉巖庸蔼,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡勺良,警方通過(guò)查閱死者的電腦和手機(jī)绰播,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)郑气,“玉大人幅垮,你說(shuō)我怎么就攤上這事∥沧椋” “怎么了忙芒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)讳侨。 經(jīng)常有香客問(wèn)我呵萨,道長(zhǎng),這世上最難降的妖魔是什么跨跨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任潮峦,我火速辦了婚禮,結(jié)果婚禮上勇婴,老公的妹妹穿的比我還像新娘忱嘹。我一直安慰自己,他們只是感情好耕渴,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布拘悦。 她就那樣靜靜地躺著,像睡著了一般橱脸。 火紅的嫁衣襯著肌膚如雪础米。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天添诉,我揣著相機(jī)與錄音屁桑,去河邊找鬼。 笑死栏赴,一個(gè)胖子當(dāng)著我的面吹牛蘑斧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播须眷,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼乌叶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了柒爸?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤事扭,失蹤者是張志新(化名)和其女友劉穎捎稚,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡今野,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年葡公,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片条霜。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡催什,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宰睡,到底是詐尸還是另有隱情蒲凶,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布拆内,位于F島的核電站旋圆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏麸恍。R本人自食惡果不足惜灵巧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抹沪。 院中可真熱鬧刻肄,春花似錦、人聲如沸融欧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蹬癌。三九已至权她,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逝薪,已是汗流浹背隅要。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留董济,地道東北人步清。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像虏肾,于是被迫代替她去往敵國(guó)和親廓啊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 項(xiàng)目中經(jīng)常遇到多圖片的上傳需求封豪,這個(gè)多文件上傳的方法可以使用AFN中的一個(gè)方法谴轮,AFNetWorking的作者在G...
    gaxly閱讀 2,938評(píng)論 0 1
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)吹埠,斷路器第步,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,125評(píng)論 29 470
  • 從三月份找實(shí)習(xí)到現(xiàn)在疮装,面了一些公司,掛了不少粘都,但最終還是拿到小米廓推、百度、阿里翩隧、京東樊展、新浪、CVTE堆生、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,184評(píng)論 11 349
  • 家庭教育對(duì)一個(gè)人影響有多大呢专缠?我小時(shí)候大多數(shù)時(shí)間是我奶奶帶的,可能我都不知道自己的一言一行顽频,為人處事都受到她的深刻...
    看世間濤走云飛閱讀 390評(píng)論 0 0