【Bug】UITableViewCell AutoLayout重布局約束沖突

CC

開了簡書10個月呀酸,一直說要記錄一些東西,結(jié)果總有各種借口拖延。今天不打LOL,完成開篇大任=_=


BUG

最近項(xiàng)目中遇到一個問題:對UITableViewCell采用AutoLayout自動布局碰辅,由內(nèi)容撐起高度。而內(nèi)容是需要網(wǎng)絡(luò)返回的蕉鸳,所以在一開始進(jìn)入VC乎赴,會向服務(wù)器發(fā)出請求,同時(shí)進(jìn)行了初始繪制潮尝;在接收到服務(wù)器返回?cái)?shù)據(jù)時(shí),UITableView進(jìn)行reloadData饿序,同時(shí)根據(jù)數(shù)據(jù)重新繪制勉失。而重新繪制導(dǎo)致UITableViewCell高度與之前不同,這時(shí)就報(bào)了約束沖突原探。但是UI呈現(xiàn)完全沒問題乱凿。

約束沖突

起始約束是在-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier初始化方法里的調(diào)用的顽素;而當(dāng)網(wǎng)絡(luò)數(shù)據(jù)返回時(shí),UITableView reloadData徒蟆;-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法會調(diào)用cell中一個塞數(shù)據(jù)的方法胁出,在塞數(shù)據(jù)方法最后會調(diào)用setNeedsUpdateConstraints方法;而在-(void)updateConstraints方法中段审,會根據(jù)塞入的數(shù)據(jù)全蝶,來進(jìn)行約束的update,這里用的Masnory庫寺枉,調(diào)用的方法是- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block抑淫。這個約束沖突就報(bào)在了-(void)updateConstraints方法中。

分析與解決

根據(jù)AutoLayout的報(bào)錯姥闪,發(fā)現(xiàn)其他都沒毛病始苇,就最后一項(xiàng)有問題:height == 190.5?沃德法克筐喳?打開Debug View看一眼:

289.5 催式!= 190.5

就說不可能這么矮=_=,190.5是初始沒有內(nèi)容時(shí)的高度避归,而289.5是網(wǎng)絡(luò)數(shù)據(jù)返回后蓄氧,根據(jù)數(shù)據(jù)重布局的高度。那么沖突應(yīng)該就是報(bào)在這個位置了槐脏。

一個腦殘的猜測

就是是不是因?yàn)榫W(wǎng)絡(luò)數(shù)據(jù)返回太快了喉童,太短時(shí)間內(nèi)多次更改constrains,再updateConstraints會導(dǎo)致沖突顿天?(網(wǎng)絡(luò)數(shù)據(jù)回來100ms以內(nèi)堂氯,好吧,不快=_=)

妥牌废,setNeedsUpdateConstraints延時(shí)1秒執(zhí)行咽白。

果然不報(bào)錯了!BUT鸟缕!文字圖片之間的間距被擠壓晶框,重疊到了一起是鬧哪樣啊懂从?

但是重疊的畫面出現(xiàn)后授段,再次reloadData,就沒問題了番甩。請求一次數(shù)據(jù)要reloadData兩次侵贵?這不是一名合格的程序員應(yīng)該做的事情,你知道reloadData有多耗費(fèi)資源霸笛Α(- 不知道窍育。 - 小伙子卡睦,可以的,你被開了)漱抓!

一個不腦殘的事實(shí)

debug view Hierarchy里面給的清清楚楚表锻,contentView.height約束的prority是1000。所以就是你在高度190.5時(shí)候乞娄,撐高contentView瞬逊,超出了190.5導(dǎo)致約束沖突報(bào)錯了唄。于是:

解決方案一——撲街

把撐高contentView的約束全部設(shè)置priority為999补胚。

修改約束proroty

哈哈哈码耐!果然不報(bào)錯了。

=_=||| ?尷尬溶其,約束是不沖突了骚腥,但是UI呈現(xiàn)有問題了,又把我文字之間的間隔給抹掉了瓶逃,再戰(zhàn)束铭!

解決方案二——撲街

直接拿掉contentView的height約束,沒有這個約束厢绝,看你還怎么沖突契沫,嘿嘿嘿。

在updateConstraints方法開始的伊始昔汉,用一個for循環(huán)懈万,判斷去除contentView的height約束。

結(jié)果靶病,很遺憾会通,不僅約束報(bào)錯,UI呈現(xiàn)也完全不對了娄周。

是不是沒去除干凈涕侈?打個斷點(diǎn),po一下contentView的constrains煤辨,發(fā)現(xiàn)果然還有東西:

NSAutoresizingMaskLayoutConstraint還在

哦裳涛,看來UITableView不是用AutoLayout布局的,這個AutoresizingMask有點(diǎn)可疑众辨,查端三,給朕徹查!

學(xué)習(xí)了一下Autoresizing泻轰,三種自適應(yīng)布局方式之一(另外兩種是layoutsubview中手動布局和autolayout)技肩,我的理解就是frame布局上增加了一定的自適應(yīng)。

然后——UITableView用的Frame布局8∩P樾觥!滾動動畫巴啦巴啦的也是靠著frame和bounds來做的S净印H蝗!屉符!厲害了word哥>缃!4V印K粝恪!來一波傳送——https://www.objc.io/issues/3-views/scroll-view/

建議objc的東西都學(xué)習(xí)一下啦吨艇,爆強(qiáng)躬它!英語沒過六級的同學(xué)(沒錯,就是我)可以搜下Objc中國咯东涡。

解決方案三——撲街

修改contentView.height約束的prority為999冯吓。

修改contentview約束prority

其實(shí)根據(jù)方案二的結(jié)果已經(jīng)猜到了——不僅約束報(bào)錯,UI呈現(xiàn)也完全不對了疮跑。其他cell 的contentview.height.prority都是1000组贺,就你自己是999,坑定有問題啊祖娘。當(dāng)然失尖,可以所有cell的contentview.height.prority都設(shè)為999,但是考慮cell復(fù)用問題渐苏,改動面太大掀潮,所以就放棄了。

正確解決方案

回到一開始的腦殘猜測整以。延時(shí)setNeedsUpdateConstraints執(zhí)行胧辽,再次reloaddata,就沒問題公黑。那么UITableViewCell設(shè)置contentView的height的時(shí)間應(yīng)該是在updateConstrains之后邑商,所以導(dǎo)致高度沒有實(shí)時(shí)變化,從而沖突(- 機(jī)智如我凡蚜! - 其實(shí)一開始報(bào)約束沖突的時(shí)候就該想到的人断,報(bào)沖突在updateConstrains,但是高度沒有實(shí)時(shí)更新朝蜘。- 你走開6衤酢)。

然后就查了一下setNeedsUpdateConstraints機(jī)制,然后就引出了setNeedsLayout的問題暇仲。兩者的區(qū)別是個毛毛步做?

從stackoverflow上找到一份答案,鏈接沒存奈附,大概意思就是——兩者都是表示需要重新布局全度,而且都是標(biāo)記需要,并不會立即執(zhí)行斥滤,會在下一個循環(huán)里執(zhí)行将鸵;setNeedsUpdateConstraints對應(yīng)-(void)updateConstraints,setNeedsLayout對應(yīng)- (void)layoutSubviews佑颇。BUT顶掉,setNeedsUpdateConstraints會調(diào)用-(void)updateConstraints之后再調(diào)用- (void)layoutSubviews,而setNeedsLayout只會調(diào)用- (void)layoutSubviews(本人親測這樣子的)挑胸。

我的理解:setNeedsUpdateConstraints就是更新約束痒筒,setNeedsLayout就是更新frame,約束的底層其實(shí)就是更改frame嗜暴,所以setNeedsUpdateConstraints會同時(shí)調(diào)用兩者(- 不對凸克。- 你留言。)闷沥。

說了這么多萎战,終于到解決方案了。最終方案是還在stackoverflow上找到的舆逃,一個來自于三年前的帖子——http://stackoverflow.com/questions/19132908/auto-layout-constraints-issue-on-ios7-in-uitableviewcell蚂维。

這篇帖子給了兩個解決方案,一個是設(shè)置:self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;

另外一個是:在更新約束之前路狮,設(shè)置self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

第一種方案我這邊不可行虫啥,根據(jù)方案二里的log,contentview的寬奄妨、高已經(jīng)設(shè)置了Autoresizing涂籽,這個有毛用?反正我設(shè)置了砸抛,沒用评雌。

第二種方案。直焙。景东。

(- 啊啊啊啊啊啊奔誓!直接改高度斤吐,我他喵的怎么就沒想到!! - 因?yàn)槟隳槾蟆?- 臉大有福和措!你羨慕不來的庄呈!啊啊啊啊>势拧抒痒!好氣盎仙堋0涔印!傀广! - 颁独。。伪冰。)

昂誓酒,在更新約束之前,直接把contentView的寬度贮聂、高度值設(shè)置為大于等于約束之后的寬高就解決問題了靠柑。UITableViewCell給contentView計(jì)算并設(shè)置寬高是在- (void)layoutSubviews方法中進(jìn)行的,而-(void)updateConstraints- (void)layoutSubviews之前執(zhí)行吓懈,從而更新約束超出之前寬高值歼冰,導(dǎo)致沖突;而在-(void)updateConstraints之前擴(kuò)增一下寬高耻警,就不會沖突隔嫡,而在- (void)layoutSubviews方法中又重新計(jì)算了高度賦值,所以UI呈現(xiàn)也沒問題甘穿。

BUT腮恩,為毛設(shè)置高度超出約束之后應(yīng)得的值就沒問題咧(如本例中,需要更新約束前温兼,設(shè)置contentView.height的值大于等于289.5)秸滴?約束把高度撐起來不行?壓縮反而可以募判?講道理的話荡含,不應(yīng)該設(shè)置的剛剛好才行么?

一位老司機(jī)告訴我兰伤,可能是這個樣子的:

你把高度設(shè)低了内颗,那么你布局的時(shí)候就超出去了,布局都完不成敦腔;而你把高度設(shè)高了均澳,那么你布局最起碼能在這個view里完成。

BUT,我的約束是從上到下找前,從top到bottom串聯(lián)起來的糟袁,你設(shè)置height高了,肯定會有一個部分被拉伸躺盛,而所有的priority都是1000项戴,講道理的話,也應(yīng)該報(bào)沖突啊槽惫。

求老司機(jī)解答 =_=

總結(jié)

stackoverflow果然是一個神奇的網(wǎng)站周叮,三年前的解答竟然解決了我的問題,古人誠不我欺也界斜。

objc要好好學(xué)習(xí)仿耽,英文水平有待提升(現(xiàn)在屏幕分兩半,一半objc各薇,一半百度翻譯)项贺。

最后,竟然寫了這么多峭判,LOL一把去开缎,有問題請留言,擼完之后看=_=林螃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奕删,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子治宣,更是在濱河造成了極大的恐慌急侥,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侮邀,死亡現(xiàn)場離奇詭異坏怪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)绊茧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門铝宵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人华畏,你說我怎么就攤上這事鹏秋。” “怎么了亡笑?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵侣夷,是天一觀的道長。 經(jīng)常有香客問我仑乌,道長百拓,這世上最難降的妖魔是什么琴锭? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮衙传,結(jié)果婚禮上决帖,老公的妹妹穿的比我還像新娘。我一直安慰自己蓖捶,他們只是感情好地回,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俊鱼,像睡著了一般刻像。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亭引,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天绎速,我揣著相機(jī)與錄音,去河邊找鬼焙蚓。 笑死,一個胖子當(dāng)著我的面吹牛洒宝,可吹牛的內(nèi)容都是我干的购公。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼雁歌,長吁一口氣:“原來是場噩夢啊……” “哼宏浩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起靠瞎,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤比庄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乏盐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佳窑,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年父能,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了神凑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡何吝,死狀恐怖溉委,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情爱榕,我是刑警寧澤瓣喊,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站黔酥,受9級特大地震影響藻三,放射性物質(zhì)發(fā)生泄漏八匠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一趴酣、第九天 我趴在偏房一處隱蔽的房頂上張望梨树。 院中可真熱鬧,春花似錦岖寞、人聲如沸抡四。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽指巡。三九已至,卻和暖如春隶垮,著一層夾襖步出監(jiān)牢的瞬間藻雪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工狸吞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勉耀,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓蹋偏,卻偏偏與公主長得像便斥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子威始,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

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