AFNetworking_網(wǎng)絡(luò)文件下載上傳詳解(注意事項(xiàng))

本文摘自:http://www.ithao123.cn/content-8680777.html

[摘要:當(dāng)前市道上的APP讯泣,凡是有觸及到視頻阵漏、期刊预侯、或別的大型文件傳輸、掃瞄等用處的甲雅,增加下載或緩存至當(dāng)?shù)氐墓πб悦饩W(wǎng)速的限定及依附解孙,毫無(wú)疑問(wèn)皆將給用戶(hù)帶去更好的體驗(yàn)。而道到下]

當(dāng)前市面上的APP务荆,凡有涉及到視頻、期刊穷遂、或其它大型文件傳輸函匕、瀏覽等用途的,添加下載或緩存至本地的功能以避免網(wǎng)速的限制及依賴(lài)蚪黑,毫無(wú)疑問(wèn)都將給用戶(hù)帶來(lái)更好的體驗(yàn)盅惜。而談到下載技術(shù),就又不得不牽扯到了斷點(diǎn)續(xù)傳忌穿,隊(duì)列任務(wù)等老生常談的問(wèn)題抒寂。這不,本人當(dāng)前的項(xiàng)目掠剑,就恰好遇到了這樣的需求屈芜。然而在經(jīng)過(guò)大量調(diào)研之后,本人竟無(wú)法找到一篇總結(jié)得很好的文檔,對(duì)此進(jìn)行全面的介紹井佑;能夠?qū)さ降囊恍┗钴S度并不高的開(kāi)源項(xiàng)目属铁,卻又不能恰如其分并抱之以信賴(lài)滿(mǎn)足項(xiàng)目的需求。所以仔細(xì)斟酌后躬翁,不得不選擇自己動(dòng)手焦蘑,豐衣足食。鉆研的過(guò)程中遇到了不少坑盒发、不少困難例嘱,有些個(gè)別的地方真是不用不知道,一用才知道是如此得蹩腳宁舰,難怪很少有人對(duì)此進(jìn)行系統(tǒng)完整的介紹∑绰眩現(xiàn)將本人在實(shí)現(xiàn)下載模塊時(shí)所用到的技術(shù)總結(jié)如下,相信本文中所蘊(yùn)涵的干貨一定不會(huì)令費(fèi)心閱讀的你感到失望明吩!話(huà)休絮煩间学。首先,說(shuō)下載就離不開(kāi)網(wǎng)絡(luò)請(qǐng)求印荔。而當(dāng)今iOS開(kāi)發(fā)技術(shù)當(dāng)中低葫,最廣泛使用的網(wǎng)絡(luò)請(qǐng)求框架無(wú)疑要屬AFNetworking。經(jīng)過(guò)對(duì)其進(jìn)行簡(jiǎn)單研究后仍律,你就會(huì)尋到最適合用來(lái)完成下載這件“小事”的組件嘿悬,叫做AFHTTPRequestOperation

現(xiàn)假定我們的需求是最常見(jiàn),也是最能體現(xiàn)技術(shù)問(wèn)題的一個(gè)水泉,叫做:下載隊(duì)列在某一時(shí)刻善涨,最多僅能有一個(gè)下載任務(wù)處于正在下載的狀態(tài)中!-- 敘述的節(jié)奏似乎稍稍快了些

那就先來(lái)看下實(shí)現(xiàn)隊(duì)列下載草则、斷點(diǎn)續(xù)傳等需求的關(guān)鍵示例代碼吧!

NSError * error = nil;

// 創(chuàng)建下載隊(duì)列

NSOperationQueue * downloadOperationQueue = [[NSOperationQueue alloc]init];

// 規(guī)定operationQueue中钢拧,最大可以同時(shí)執(zhí)行的operation數(shù)量為1

downloadOperationQueue.maxConcurrentOperationCount = 1;

// 創(chuàng)建單個(gè)下載任務(wù)(訪問(wèn)已下載部分的文件,實(shí)現(xiàn)斷點(diǎn)續(xù)傳)

NSMutableURLRequest * downloadRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:DOWNLOAD_URL_STRING]];

[[NSURLCache sharedURLCache] removeCachedResponseForRequest:downloadRequest];

AFHTTPRequestOperation * downloadOperation = [[AFHTTPRequestOperation alloc]initWithRequest:downloadRequest];

unsigned long long downloadedPartFileSize = 0;

if ([[NSFileManager defaultManager] fileExistsAtPath:DOWNLOADED_PART_FILE_PATH]) {

NSDictionary * fileAttributes = [[NSFileManager defaultManager]attributesOfItemAtPath:DOWNLOADED_PART_FILE_PATH error:&error];

downloadedPartFileSize = [fileAttributes fileSize];

NSString * headerRangeFieldValue = [NSString stringWithFormat:@"bytes=%llu-", downloadedPartFileSize];

[downloadRequest setValue:headerRangeFieldValue forHTTPHeaderField:@"Range"];

}

downloadOperation.outputStream = [NSOutputStream outputStreamToFileAtPath:DOWNLOADED_PART_FILE_PATH append:YES];

[downloadOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {

NSLog(@"%lld/%lld", totalBytesRead + downloadedPartFileSize, totalBytesExpectedToRead + downloadedPartFileSize);

}];

[downloadOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

NSLog(@"downloadOperation completion block invoked");

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

NSLog(@"downloadOperation failure block invoked");

}];

// 將單個(gè)下載任務(wù)加入到下載隊(duì)列當(dāng)中

[downloadOperationQueue addOperation:downloadOperation];

// 暫停某下載任務(wù)

[downloadOperation pause];

// 繼續(xù)某下載任務(wù)

[downloadOperation resume];

// 取消某下載任務(wù)(同時(shí)應(yīng)將其已下載部分的文件刪除)

[downloadOperation cancel];

[[NSFileManager defaultManager] removeItemAtPath:DOWNLOADED_PART_FILE_PATH error:&error];

// 取消全部下載任務(wù)

[downloadOperationQueue cancelAllOperations];

// 此外還有若干方法用以判斷相應(yīng)一見(jiàn)其名便知其義的狀態(tài)...

downloadOperation.isReady

downloadOperation.isExecuting

downloadOperation.isPaused

downloadOperation.isCancelled

downloadOperation.isFinished

// 判斷downloadOperation是否存在在downloadOperationQueue當(dāng)中

[downloadOperationQueue.operations containsObject:downloadOperation]

以上代碼創(chuàng)建了一個(gè)AFHTTPRequestOperation對(duì)象作為單個(gè)下載任務(wù)炕横,并將其加入到NSOperationQueue中源内。仿照上例,我們可以創(chuàng)建多個(gè)AFHTTPRequestOperation對(duì)象并加入到NSOperationQueue中份殿,即形成了下載隊(duì)列
做到這里膜钓,你是不是認(rèn)為已經(jīng)沒(méi)有神馬技術(shù)問(wèn)題啦?只要把operation一個(gè)個(gè)地添加到queue里卿嘲,下載任務(wù)就可以一個(gè)接一個(gè)地自動(dòng)執(zhí)行了颂斜!而如果我們將上一個(gè)operation暫停、取消拾枣,或是它自然地下載完成了沃疮,又或是它下載中途失敗了盒让,下一operation就會(huì)聰明地自動(dòng)啟動(dòng),繼續(xù)其下載任務(wù)了7薨酢E幢颉?錯(cuò)4兴A冒恰!吨些!

接下來(lái)筆者將要告訴你的搓谆,就是本文最最核心的干貨,絕對(duì)顛覆你的想象:朗泉手!只要你親手動(dòng)手試一試,就會(huì)發(fā)現(xiàn)如下大跌眼球的驚恐現(xiàn)象E计鳌斩萌!

驚人事實(shí) 1:對(duì)queue中前一個(gè)下載operation執(zhí)行pause方法,下一個(gè)operation并不能自動(dòng)啟動(dòng)進(jìn)入正在執(zhí)行的狀態(tài)F梁洹颊郎!

驚人事實(shí) 2:如果queue中前一個(gè)下載operation執(zhí)行失敗了(可用下載中途斷網(wǎng)進(jìn)行模擬),它將從queue中自動(dòng)地被移除掉v纭姆吭!

驚人事實(shí) 3:注意到代碼里那個(gè)failure回調(diào)的block了沒(méi)?它不僅僅將在operation執(zhí)行失敗的時(shí)候被調(diào)用唁盏,還會(huì)在operation被cancel的時(shí)候被調(diào)用D诶辍!所以對(duì)于神馬叫做“operation的失敗”厘擂,你要重新建立起你的世界觀了@サ!

驚人事實(shí) 4:如果對(duì)一個(gè)正處于pause狀態(tài)的operation執(zhí)行cancel會(huì)怎么樣刽严?答案是這個(gè)operation還保留在queue中0毫椤!并且仍然保持著pause狀態(tài)8圩倔既!僅有的一點(diǎn)變化恕曲,是它的isCancelled屬性鹏氧,變成了YES!佩谣!

......未完待續(xù)把还,本文要令你感到驚詫的,還有很多

有木有感到AFHTTPRequestOperation和NSOperationQueue是個(gè)多么坑爹的東東?為何就不能像我們想象中一樣用得舒爽吊履?

原因就在于AFHTTPRequestOperation的父類(lèi)NSOperation安皱,在設(shè)計(jì)之處就不是為了下載的操作而生的!人家開(kāi)始就僅僅是用來(lái)處理多線程的巴а住W靡痢!所以造成了AFNetworking在擴(kuò)展這個(gè)類(lèi)的時(shí)候缀踪,可用的資源居砖、接口等等就非常少。對(duì)于什么下載任務(wù)暫停/繼續(xù)驴娃,下載中途失敗等等情況奏候,很多問(wèn)題幾乎就是沒(méi)有辦法理想地解決的,只好用NSOperation中僅有的幾種狀態(tài)予以并不貼切的表示唇敞。于是乎就出現(xiàn)了上表中種種詭異的情況

補(bǔ)充幾點(diǎn)干貨蔗草。然后告訴你一個(gè)本文之前偷偷誤導(dǎo)了你的大坑!疆柔!

驚人事實(shí) 5:如果一個(gè)queue中有一個(gè)下載operation正在執(zhí)行咒精,此時(shí)對(duì)另一處在isReady狀態(tài)的operation執(zhí)行start方法會(huì)怎么樣?你很可能會(huì)說(shuō):“沒(méi)用的婆硬,因?yàn)橹霸O(shè)了queue.maxConcurrentOperationCount = 1嘛狠轻!” 可事實(shí)恰好相反,這個(gè)operation也會(huì)立刻被啟動(dòng)執(zhí)行1蚍浮向楼!于是乎你不忍心看到的事情就出現(xiàn)了,這時(shí)queue將會(huì)有兩個(gè)任務(wù)被同時(shí)執(zhí)行P城湖蜕!maxConcurrentOperationCount完全失效了!宋列!

驚人事實(shí) 6:承接上一點(diǎn)昭抒,如果此時(shí)另一條的狀態(tài)不是isReady,而是isPaused暫停狀態(tài)炼杖,你對(duì)其執(zhí)行resume方法灭返,此時(shí)會(huì)怎么樣呢?哈哈坤邪,沒(méi)錯(cuò)熙含,你吸取了上一條的經(jīng)驗(yàn),終于猜對(duì)了艇纺!這個(gè)operation也會(huì)立刻啟動(dòng)被執(zhí)行怎静,不管當(dāng)前的queue有沒(méi)有另一個(gè)operation正在被執(zhí)行S实!從中我們就可以意識(shí)到蚓聘,maxConcurrentOperationCount這個(gè)屬性腌乡,只能管得自動(dòng)啟動(dòng)每一operation時(shí),先檢查下是否正在執(zhí)行的operation的數(shù)量已經(jīng)超過(guò)那個(gè)數(shù)字了夜牡;可是如果你要手動(dòng)start某一operation与纽,對(duì)不起,這條限制半點(diǎn)都沒(méi)有用處了......

驚人事實(shí) 7:從上表中我們可以看到塘装,無(wú)論是一個(gè)operation自然地執(zhí)行完畢渣锦,還是中途失敗,還是被執(zhí)行了cancel方法氢哮,都會(huì)被標(biāo)記為isFinished袋毙,從operation中被移除掉,operation所認(rèn)為的“完成”可完全不像我們想象中的那么狹義冗尤!問(wèn)題來(lái)了听盖,此時(shí)如果再對(duì)這個(gè)operation執(zhí)行start方法會(huì)怎么樣?對(duì)不起裂七!沒(méi)有任何用處皆看!:sob:所以你如果想要讓一個(gè)已失敗的operation從斷點(diǎn)處繼續(xù)再開(kāi)始執(zhí)行下載該怎么辦?不好意思背零,只好新建operation重新再來(lái)了......頭痛腰吟、抓狂得很啊a闫俊毛雇!本人剛開(kāi)始實(shí)現(xiàn)下載模塊相關(guān)需求的時(shí)候,就被這些問(wèn)題坑了個(gè)體無(wú)完膚侦镇。最后得出了本文最大的關(guān)鍵結(jié)論灵疮,也就是前面所說(shuō)的“大坑”:

不能夠使用NSOperationQueue來(lái)進(jìn)行多下載任務(wù)的管理!?欠薄震捣!

理由如下:

你無(wú)法妥善地實(shí)現(xiàn)“隊(duì)列中最多僅能有一個(gè)下載任務(wù)正在進(jìn)行”這條產(chǎn)品經(jīng)理臆測(cè)會(huì)讓開(kāi)發(fā)變簡(jiǎn)單的需求!闹炉!比方說(shuō)蒿赢,你讓NSOperationQueue中一個(gè)operation暫停后,下一個(gè)任務(wù)并不會(huì)自動(dòng)啟動(dòng)霸ァ羡棵!有人說(shuō)可以手動(dòng)去start下一個(gè)operation,如果這個(gè)姑且算做可以接受昵观,可是問(wèn)題又來(lái)了:我們沒(méi)有辦法手動(dòng)將一個(gè)operation置為isReady狀態(tài)傲狼弧!啊犬!處于isReady狀態(tài)的operation灼擂,要么是還未加入queue,要么是加入了還未輪到執(zhí)行觉至,但是它只要一執(zhí)行剔应,就再也回不到isReady的狀態(tài)了!那我們要讓暫停的operation恢復(fù)到等待下載狀態(tài)該怎么搞语御?此時(shí)可能還有另一operation正在執(zhí)行熬!应闯!反之筆者搞了半天纤控,是無(wú)能為力了

下載是需要一定時(shí)間的過(guò)程,需要不停地向服務(wù)器進(jìn)行請(qǐng)求碉纺,那么就永遠(yuǎn)避免不了因?yàn)榫W(wǎng)絡(luò)等原因中途會(huì)失敗的問(wèn)題船万。可要命的是骨田,一旦下載失敗耿导,operation就會(huì)毫不妥協(xié)地從queue中被移除掉啊L汀舱呻!你能在這時(shí)候讓你的下載任務(wù)從UI界面上消失掉嗎?顯然大BOSS是不會(huì)允許你這么干的悠汽。有人說(shuō)可以重建operation再加入到queue中箱吕,可那樣你只能將operation插到隊(duì)尾,列表順序就被打亂了笆脸濉V呈稀!你去瞧瞧看姻采,operationQueue.operations雅采,那可只是一個(gè)只讀屬性啊?住婚瓜!

......自己去體會(huì)吧,反正坑多的已經(jīng)無(wú)力吐槽刑棵,再堅(jiān)持下去也是枉費(fèi)心思了巴刻。

不幸的事情來(lái)了。筆者最后只得放棄NSOperationQueue蛉签,使用古老原始的工具--NSMutableArray來(lái)進(jìn)行多下載任務(wù)的管理胡陪。這樣

的話(huà)所有operation的啟動(dòng)沥寥、移除等操作都必須依靠手動(dòng)來(lái)執(zhí)行。這個(gè)辦法雖然辦法土了些柠座,可是起碼對(duì)于每個(gè)operation的控制權(quán)又重新回到了

我們手里邑雅。有得必有失嘛!當(dāng)能恰當(dāng)?shù)貙?shí)現(xiàn)了項(xiàng)目需求的時(shí)候妈经,這點(diǎn)犧牲也就算不上神馬了

在使用AFHTTPRequestOperation時(shí)我們還需要注意以下幾點(diǎn):

對(duì)isReady狀態(tài)的operation執(zhí)行resume淮野、pause、cancel等方法是沒(méi)有任何用處的吹泡,所以為了確保執(zhí)行正確骤星,在對(duì)operation執(zhí)行resume、pause爆哑、cancel前洞难,都要首先執(zhí)行[operation start]。(對(duì)已經(jīng)start過(guò)的operation執(zhí)行start不會(huì)造成任何影響)

對(duì)處于isPaused的operation執(zhí)行cancel方法是無(wú)法得到正確結(jié)果的揭朝,所以每次執(zhí)行cancel方法前廊营,都要先執(zhí)行一下[operation resume]。 (同樣對(duì)于正處于isExecuting狀態(tài)的operation來(lái)說(shuō)萝勤,執(zhí)行resume方法也是不會(huì)造成任何影響的)

對(duì)于下載模塊這個(gè)糾結(jié)之處來(lái)說(shuō)露筒,本地持久化下載記錄的相關(guān)數(shù)據(jù)也是必不可少的,理由如下:

AFHTTPRequestOperation敌卓、NSMutableArray這些都是運(yùn)行時(shí)的東西慎式,一關(guān)掉app,這些東西自然也都消失得無(wú)影無(wú)蹤了趟径。我們能讓下載記錄就此消失得無(wú)影無(wú)蹤么瘪吏?NO!顯然是不能接受的

我們下載得到的那個(gè)文件蜗巧,可能是已下載完成的掌眠,可能是只下載了部分的;而只下載了部分這種的幕屹,又可能是下載中途暫停了的蓝丙,失敗的,被取消的等等情況望拖。請(qǐng)問(wèn)單憑這個(gè)文件如何判斷它是屬于哪種情況渺尘?而且這還不夠,有些下載任務(wù)根本可能就還未生成相應(yīng)的下載文件说敏,app就已經(jīng)被關(guān)了芭父!你能就把這種的下載任務(wù)扔掉嗎?顯然是絕不可以的

不使用operationQueue我們同樣無(wú)法手動(dòng)將operation標(biāo)記為隊(duì)列等待的isReady狀態(tài)医咨,怎么辦枫匾?只有將operation設(shè)定為paused,然后相應(yīng)的數(shù)據(jù)記錄標(biāo)記為isReady狀態(tài)好了(本人使用的是CoreData進(jìn)行本地持久化存儲(chǔ))

......用operation外的數(shù)據(jù)模型記錄下載任務(wù)的狀態(tài)好處還有很多拟淮,但同時(shí)帶來(lái)的同步更新問(wèn)題也有很多干茉,具體就留給大家自己去體會(huì)了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惩歉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子俏蛮,更是在濱河造成了極大的恐慌撑蚌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搏屑,死亡現(xiàn)場(chǎng)離奇詭異争涌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)辣恋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)亮垫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人伟骨,你說(shuō)我怎么就攤上這事饮潦。” “怎么了携狭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵继蜡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我逛腿,道長(zhǎng)稀并,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任单默,我火速辦了婚禮碘举,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搁廓。我一直安慰自己引颈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布境蜕。 她就那樣靜靜地躺著线欲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汽摹。 梳的紋絲不亂的頭發(fā)上李丰,一...
    開(kāi)封第一講書(shū)人閱讀 52,807評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音逼泣,去河邊找鬼趴泌。 笑死舟舒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嗜憔。 我是一名探鬼主播秃励,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吉捶!你這毒婦竟也來(lái)了夺鲜?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤呐舔,失蹤者是張志新(化名)和其女友劉穎币励,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年催束,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仅胞。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖剑辫,靈堂內(nèi)的尸體忽然破棺而出干旧,到底是詐尸還是另有隱情,我是刑警寧澤妹蔽,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布莱革,位于F島的核電站,受9級(jí)特大地震影響讹开,放射性物質(zhì)發(fā)生泄漏盅视。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一旦万、第九天 我趴在偏房一處隱蔽的房頂上張望闹击。 院中可真熱鬧,春花似錦成艘、人聲如沸赏半。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)断箫。三九已至,卻和暖如春秋冰,著一層夾襖步出監(jiān)牢的瞬間仲义,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留埃撵,地道東北人赵颅。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像暂刘,于是被迫代替她去往敵國(guó)和親饺谬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

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