TableViewCell的幾種重用方式的區(qū)別

重用機(jī)制

關(guān)于TableView的重用機(jī)制相信網(wǎng)上教程一堆,這里不作過(guò)多說(shuō)明,但是有幾個(gè)重點(diǎn)會(huì)說(shuō)明下:

reuseIdentifier

個(gè)人覺(jué)得最重要的一點(diǎn),就是Cell的reuseIdentifier屬性,其實(shí)不管你是注冊(cè)nib還是class,最終的重用靠的主要是這個(gè)標(biāo)識(shí)符,只有這個(gè)屬性有值的Cell,在滑動(dòng)出TableView后才會(huì)進(jìn)入重用隊(duì)列,隊(duì)列有Cell,你在dequeueReusable的時(shí)候才能拿到Cell,如果你沒(méi)注冊(cè),但是只要Cell有這個(gè)屬性值,那么它再滑出去后也必然能被重用

registerNib(class):forCellReuseIdentifier

上面說(shuō)的注冊(cè)單元格的兩種方式,簡(jiǎn)稱(chēng)r,他們將Cell以nib或者class的形式注冊(cè),但是重點(diǎn)還是后面的forCellReuseIdentifier,也即是說(shuō)這個(gè)Cell,會(huì)因?yàn)檫@個(gè)參數(shù)而賦值給reuseIdentifier屬性,所以這個(gè)Cell才能被重用.

總結(jié):重點(diǎn)還是reuseIdentifier,不管你注冊(cè)沒(méi)注冊(cè),只要你產(chǎn)生的Cell的屬性reuseIdentifier是有值的,那么它滑動(dòng)出TableView后就可以被再次重用.那registerNib(class):是干嘛用的呢,后面會(huì)再提到.

重用生成單元格方法

關(guān)于重用生成TableViewCell的機(jī)制這里不作多的說(shuō)明,這里只是對(duì)比下幾種重用方式的區(qū)別,目前重用單元格使用下面兩種方法:

  • dequeueReusableCellWithIdentifier:
  • dequeueReusableCellWithIdentifier: forIndexPath:

這里暫且簡(jiǎn)稱(chēng)上面前者為方法d1,后者為d2.
這兩個(gè)方法的返回值都是UITableviewCell,網(wǎng)上大部分的講解或者抄襲的講解可能說(shuō)的區(qū)別僅僅是d1可能返回nil,而d2則在沒(méi)有使用r方法的情況下會(huì)崩潰,這些都沒(méi)問(wèn)題,不然也不會(huì)有那么多抄襲的博客了.這里先說(shuō)下他們的共同點(diǎn)和不同點(diǎn):

共同點(diǎn)

他們都會(huì)先根據(jù)identifier來(lái)復(fù)用在重用隊(duì)列的單元格,且復(fù)用不到的時(shí)候會(huì)去根據(jù)r方法注冊(cè)的Cell來(lái)獲取新的,r方法注冊(cè)的時(shí)候已經(jīng)給cell了identifier,因此這兩個(gè)方法新生成的cell,都會(huì)有重用標(biāo)示,都可以進(jìn)入重用隊(duì)列(前提是使用r方法注冊(cè)過(guò)),不會(huì)為nil.

不同點(diǎn)

如果你沒(méi)有使用r方法注冊(cè),在找r方法產(chǎn)生的cell的時(shí)候,區(qū)別就來(lái)了,因?yàn)闆](méi)有用r注冊(cè),d1會(huì)返回nil,而d2則直接崩潰.

說(shuō)的再細(xì)點(diǎn):

在使用了r方法注冊(cè)的情況下

只要使用r方法注冊(cè)了單元格設(shè)置了標(biāo)識(shí)符(前提是注冊(cè)的沒(méi)問(wèn)題),那么在重用的時(shí)候,不管你是用d1還是d2,只要重用不到,就返回r方法注冊(cè)的帶標(biāo)識(shí)符的新單元格(新生成,非重用),即使你用d1來(lái)獲取cell,也不會(huì)返回給你nil,這兩種情況目測(cè)沒(méi)發(fā)現(xiàn)任何區(qū)別,那么問(wèn)題來(lái)了,d2方法的IndexPath參數(shù),系統(tǒng)是干嘛了?好吧,其實(shí)我也不知道,官方文檔是這么說(shuō)的:

This method uses the index path to perform additional configuration based on the cell’s position in the table view

所以,文檔也說(shuō)的不清不楚,只是說(shuō)會(huì)根據(jù)位置來(lái)增加一些額外的配置信息,具體是啥信息,不知道,我查了下Stack Overflow,這個(gè)參數(shù),老外們也是諸多疑問(wèn),如果有哪位知道具體的區(qū)別,請(qǐng)告知,謝謝.在使用r方法注冊(cè)的前提下,兩者目測(cè)并沒(méi)有什么區(qū)別.既然目測(cè)沒(méi)有什么區(qū)別,那自然使用d2比較合適,因?yàn)楫吘顾潜容^新的方法.

另外這里說(shuō)下一種寫(xiě)法,雖然也沒(méi)什么問(wèn)題,但是我個(gè)人覺(jué)得不提倡:先使用d1來(lái)獲取單元格,然后判斷是否為空,為空的話(huà)再去注冊(cè)并調(diào)用d1.說(shuō)直白點(diǎn)就是,先不注冊(cè),先去用d1重用,為空的話(huà)就使用r注冊(cè),然后再用d1,就有了Cell了.但是其實(shí)只要只要使用了r方法且注冊(cè)的是正確的,不管你是用d1和d2都不會(huì)是空,既然這樣,那為何不直接在TableView對(duì)象生成完了就先使用r注冊(cè)下,cellforRow直接使用d1就完了,它肯定不會(huì)是nil的,用上面這種寫(xiě)法其實(shí)if(!cell)里只走一次后就不會(huì)再走了.
好吧,其實(shí)說(shuō)了這么多,無(wú)非想說(shuō)明一點(diǎn):
只要使用了r方法且注冊(cè)的nib或者class沒(méi)問(wèn)題,那么不管你是用d1還是d2,它始終不會(huì)是空,都會(huì)正常生成單元格.

結(jié)論:在使用r方法注冊(cè)過(guò)的前提下,使用d2方法來(lái)重用單元格,不要使用d1(雖然d1也沒(méi)問(wèn)題,但是畢竟d2比較新)

不使用r方法注冊(cè)的情況下

d1和d2的返回值都是UITableviewCell,前面已經(jīng)說(shuō)了,在這種情況下,d1返回可能是nil,而d2會(huì)崩潰.所以不使用r方法的情況下,我們直接排除掉d2,不使用d2來(lái)重用單元格,使用d1.
d1在返回的是nil的情況下該如何做呢,再重新注冊(cè)?No,No,No,上面已經(jīng)說(shuō)過(guò)了,既然你要注冊(cè),就沒(méi)必要做判斷,提前注冊(cè)好這里直接就不會(huì)是nil,而且我這里已經(jīng)寫(xiě)到不使用r方法注冊(cè)的情況下了,不要讓我再繞回去了.說(shuō)白了,你只要想用r方法,那么就乖乖用d2就完了.

r方法其實(shí)它的重點(diǎn)在于你用d方法拿不到單元格的時(shí)候,d1或者d2方法會(huì)根據(jù)r方法注冊(cè)的nib或者class,生成新的單元格,并賦值identifier,那么這里其實(shí)也是一樣的,在Cell為nil的時(shí)候,你只需要生成對(duì)應(yīng)的單元格,且給identifier賦值即可.常規(guī)單元格使用方法:initWithStyle: reuseIdentifier:,它可以指定identifier,即生成的單元格是可以正常重用的.
大部分的時(shí)候我們需要使用xib來(lái)創(chuàng)建cell,那么可能的用法有下面幾種:

if (!cell) {
    UINib *nib = [UINib nibWithNibName:cellId bundle:nil];
    cell = [nib instantiateWithOwner:nil options:nil].firstObject;
//        NSArray *files = [[NSBundle mainBundle] loadNibNamed:@"xx" owner:nil options:nil];
//        cell = files.firstObject;
    CLog(@"生成了新的單元格");
}

或者:

if (!cell) {
//        UINib *nib = [UINib nibWithNibName:cellId bundle:nil];
//        cell = [nib instantiateWithOwner:nil options:nil].firstObject;
    NSArray *files = [[NSBundle mainBundle] loadNibNamed:@"xx" owner:nil options:nil];
    cell = files.firstObject;
    CLog(@"生成了新的單元格");
}

上面兩種方式姑且叫x1和x2.剛說(shuō)了,新生成的Cell要能重用,重點(diǎn)是identifier有值,然后這兩種方式都沒(méi)有給identifier賦值的參數(shù),有好多人可能直接就這么用了,這樣其實(shí)根本就沒(méi)重用,每次進(jìn)cellforRow,使用d1方法都會(huì)得到nil,每次都會(huì)生成新的,浪費(fèi)內(nèi)存.那上面這兩種方法拿到的cell要怎么設(shè)置它的identifier呢,很簡(jiǎn)單,需要直接在xib的cell里設(shè)置,打開(kāi)cell的第四個(gè)選項(xiàng)卡你就可以看到Identifier了,或者還有個(gè)辦法,在x1或者x2最后,直接[cell setValue:@"xx" forKey:@"reuseIdentifier"];

這樣它在移出TableView外后就可以進(jìn)入到重用隊(duì)列了.

注意:這一步非常重要,不設(shè)置標(biāo)識(shí)符的話(huà),重用沒(méi)有任何意義,每次進(jìn)來(lái)都會(huì)是nil,都會(huì)重新生成!

最終使用方式

大部分情況下,我們都是使用xib來(lái)創(chuàng)建cell,根據(jù)上面的內(nèi)容綜合,大概可以總結(jié)出下面兩種方式來(lái)重用單元格

  • r+d2

使用r方法先注冊(cè),然后再使用d2重用單元格,不用判斷cell是否為nil

  • d1+x1 or d1+x2(xib里或者代碼設(shè)置identifier)

不使用r方法注冊(cè),使用d1方法重用單元格,但需要判斷是否為空,為空則使用x1或者x2方法生產(chǎn)新的cell并設(shè)置Identifier.

很明顯,第一種方式更簡(jiǎn)潔,首先在TableView初始化完后,注冊(cè),然后直接重用即可.常規(guī)來(lái)說(shuō)只需要xib上做好UI即可,如果你每個(gè)界面每個(gè)TableView都是單獨(dú)寫(xiě)的,且cell都是一個(gè)一個(gè)單獨(dú)寫(xiě)的,那么這么寫(xiě)會(huì)好點(diǎn).
但是我更傾向于第二種,以下是原因:

為什么不用r注冊(cè)的方式:

假設(shè)的app是在賣(mài)某種產(chǎn)品,有兩種類(lèi)型,數(shù)據(jù)都是一個(gè)接口給的.這兩種產(chǎn)品一種可以隨意投資,算是常規(guī)產(chǎn)品,一種則有上限,它比常規(guī)產(chǎn)品多一個(gè)百分比的字段.UI上則只是這個(gè)特殊產(chǎn)品有個(gè)百分比的進(jìn)度條,常規(guī)產(chǎn)品則沒(méi)有進(jìn)度條.
這里姑且不討論數(shù)據(jù)結(jié)構(gòu)問(wèn)題,很多剛培訓(xùn)出來(lái)的同學(xué)可能會(huì)這么做:直接新建兩套Cell類(lèi)文件(兩套h和m)并關(guān)聯(lián)xib,連線(xiàn),然后r方法注冊(cè),d2方法重用,再low一點(diǎn)的,d1方法重用,判斷為空的話(huà)再r方法注冊(cè)再d1方法重用.

既然都是同樣的產(chǎn)品,只是類(lèi)型不同,為何就不是一個(gè)類(lèi),哪怕繼承與同一個(gè)父類(lèi)也行,為什么要單獨(dú)分開(kāi)?有人可能會(huì)說(shuō),xib得要倆啊?是,新建一個(gè)類(lèi)只能有一個(gè)xib,但是誰(shuí)規(guī)定了一個(gè)xib不能有多個(gè)cell或者視圖.如果不能的話(huà),為什么可以拖多個(gè)cell甚至別的UIView到同一個(gè)xib里?蘋(píng)果是吃飽了撐著做這個(gè)功能的?

個(gè)人建議:相同類(lèi)型的UI,只建一套h.m文件,UI則放在一個(gè)xib里即可,個(gè)人覺(jué)得大部分情況下,一個(gè)TableView的cell都可以在一套h.m文件內(nèi),當(dāng)然,情況比較復(fù)雜的話(huà)另當(dāng)別論,具體的結(jié)構(gòu)需要根據(jù)實(shí)際情況而定,像上面這種情況,只需要建一套Cell類(lèi)文件(文件默認(rèn)包含一個(gè)類(lèi))即可,作為常規(guī)產(chǎn)品,特殊產(chǎn)品你可以繼承與它,但不要單獨(dú)寫(xiě)h.m文件,直接就在原來(lái)的文件中寫(xiě)即可,一套h.m文件一個(gè)類(lèi),一個(gè)xib一個(gè)視圖,那是剛培訓(xùn)出來(lái)的做法,你見(jiàn)過(guò)蘋(píng)果官方的api每個(gè)類(lèi)都是單獨(dú)放在一個(gè)文件里?如果你的產(chǎn)品有n個(gè),那文件不是得多的要死?

那如何使用呢?首先,這種情況,r方法肯定是不能用了,為什么?因?yàn)樗鼤?huì)報(bào)錯(cuò),r方法(使用nib)的時(shí)候,會(huì)根據(jù)xib的元素注冊(cè)成單元格,但是前提是它能找到,如果一個(gè)xib建立了多個(gè)cell,r方法就會(huì)報(bào)錯(cuò),它不知道你要用哪個(gè),那你如果單純是為了用r+d2方法而用,行,就建n個(gè)xib文件慢慢玩吧

所以,這種情況,使用d1+x方法即可,x方法最后cell的獲取是從數(shù)組中得到的,而這個(gè)數(shù)組其實(shí)就是xib的所有文件,之前寫(xiě)的是數(shù)組的firstObject,現(xiàn)在按照下標(biāo)讀取即可.

所以如果是常規(guī)就一種產(chǎn)品的cell就那么一個(gè)UI,那么ok,可以直接r+d2,如果一種產(chǎn)品類(lèi)型很多,則使用d1+x.

那為什么我還是選擇后者,這里涉及到UITableview的封裝.具體這里不多說(shuō),大概就是為了保證UITableview的效率,具體可以搜下為什么要封裝UITableview.封裝后,cellForRow會(huì)集中在一個(gè)地方,外部則需要告訴它諸如行高,重用標(biāo)識(shí),下標(biāo)等,因?yàn)榉庋b,所以要適合所有的可能性,所以這里必然不能使用r+d2的方法了,只能使用d1+x方法了.

尾文:

目前正在重寫(xiě)app架構(gòu),UITableView也在封裝,關(guān)于重用這塊剛好有感而發(fā),所以寫(xiě)了這么點(diǎn)東西,文中提到的d2方法中的indexpath參數(shù),若真有知道具體用處的,歡迎留言,謝謝.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末些举,一起剝皮案震驚了整個(gè)濱河市窑滞,隨后出現(xiàn)的幾起案子漓帚,更是在濱河造成了極大的恐慌晰韵,老刑警劉巖捆探,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件双谆,死亡現(xiàn)場(chǎng)離奇詭異佃扼,居然都是意外死亡衷蜓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)判呕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)倦踢,“玉大人,你說(shuō)我怎么就攤上這事侠草∪杌樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵边涕,是天一觀(guān)的道長(zhǎng)晤碘。 經(jīng)常有香客問(wèn)我,道長(zhǎng)功蜓,這世上最難降的妖魔是什么园爷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮式撼,結(jié)果婚禮上童社,老公的妹妹穿的比我還像新娘。我一直安慰自己著隆,他們只是感情好扰楼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著美浦,像睡著了一般季希。 火紅的嫁衣襯著肌膚如雪瞬场。 梳的紋絲不亂的頭發(fā)上派近,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天建瘫,我揣著相機(jī)與錄音,去河邊找鬼。 笑死案腺,一個(gè)胖子當(dāng)著我的面吹牛庆冕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播劈榨,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼访递,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了同辣?” 一聲冷哼從身側(cè)響起拷姿,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旱函,沒(méi)想到半個(gè)月后响巢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棒妨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年踪古,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片券腔。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伏穆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纷纫,到底是詐尸還是另有隱情枕扫,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布辱魁,位于F島的核電站烟瞧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏商叹。R本人自食惡果不足惜燕刻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剖笙。 院中可真熱鬧,春花似錦请唱、人聲如沸弥咪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)聚至。三九已至,卻和暖如春本橙,著一層夾襖步出監(jiān)牢的瞬間扳躬,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贷币,地道東北人击胜。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像役纹,于是被迫代替她去往敵國(guó)和親偶摔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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

  • UITableViewCell重用機(jī)制 1.cell使用重用的原因和重用機(jī)制的原理: 原因: 一個(gè)UITableV...
    交警隊(duì)不是沒(méi)有人兒閱讀 1,262評(píng)論 2 5
  • UITableViewCell如果在tableView:cellForRowAtIndexPath:方法中促脉,像其他...
    ForeverYoung21閱讀 5,991評(píng)論 3 16
  • 代碼創(chuàng)建UIWindow對(duì)象 Xcode7之后使用代碼創(chuàng)建UIWindow對(duì)象: //創(chuàng)建UIWindow對(duì)象 s...
    云之君兮鵬閱讀 1,317評(píng)論 0 2
  • 其實(shí)很難辰斋,想要抱怨的時(shí)候,不知道找誰(shuí)瘸味,也是宫仗,誰(shuí)想聽(tīng)你倒苦水呢,生而為人旁仿,都不容易锰什,只有自己能力提高,變強(qiáng)大了丁逝,才能...
    Ailsa_12c5閱讀 185評(píng)論 0 0
  • 2014.6.20 詩(shī)之必要也還在于我們內(nèi)在給予的意義承載汁胆,即是我們之主體化關(guān)懷的構(gòu)建,抑或再現(xiàn)霜幼,都是我們的存在性...
    宙六十三閱讀 175評(píng)論 0 0