繼續(xù)上一篇班巩,本周的重構重點是UI部分代碼的優(yōu)化析藕。
1. AutoLayout及Masonry
AutoLayout是蘋果在IOS6中推出的一種新的UI構建方式准谚,旨在解決不同屏幕分辨率之間的適配問題萧恕。相信大多數(shù)人可能跟我一樣鸠蚪,對這種方式是又愛又恨,因為AutoLayout中的確存在很多坑饥臂。不過隨著iOS設備尺寸越來越多逊躁,還是值得去學習掌握AudoLayout的。
本次重構中在UITableViewCell中使用AutoLayout上遇到了一個坑隅熙,正常情況下在cell中使用AutoLayout需設置約束上下左右都為-8才能鋪滿整個Cell稽煤。但發(fā)現(xiàn)在iOS6中沒有問題,但在iOS7以上囚戚,左右約束需設置為-15才能鋪滿酵熙。我的解決方案是在cell.contentView上再添加一層父View,針對不同的系統(tǒng)做了一個適配驰坊。但問題的根本原因目前還沒有找到匾二,有待后續(xù)觀察。
另外拳芙,對于手寫約束來說察藐,使用蘋果原生的API可能會很痛苦,因為約束代碼將又臭又長舟扎,例如:
[self.view addConstraint: [NSLayoutConstraint constraintWithItem:AView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:BView
attribute:NSLayoutAttributeLeft
multiplier:1
constant:0]];
僅表示AView的左側距離BView的左側一個單位分飞,所以有必要引入一些第三方工具。
Masonry是一個輕量級的布局框架 擁有自己的描述語法 采用更優(yōu)雅的鏈式語法封裝自動布局 簡潔明了 并具有高可讀性 而且同時支持 iOS 和 Max OS X睹限。
上面那句使用Mansory可以精簡為:
[AView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(BView.left).with.offset(1);
}];
一個View的多個約束可以在同一個Block中實現(xiàn)譬猫,并且代碼書寫方式讓人更容易理解讯檐。
更多使用技巧請戳:Masonry
2. Cell中對Layer的處理
其實cell中應避免一切對Layer的處理,包括圓角染服,陰影裂垦,甚至不應該包含任何透明View,因為這種渲染對系統(tǒng)的開銷非常大肌索,眾多的Cell將使頁面變的非辰堵#卡,在使用Layer時诚亚,也應該使用如下的方法減少以系統(tǒng)的開銷晕换。
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
CGPathRef path = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
[self.layer setShadowPath:path];
3. UITableViewCell中嵌套UITableView
看到網上有人說應該避免在UITableViewCell中使用UITableView,我覺得可以視需求的不同做不同的處理站宗。對于一個模型結構非常復雜的TabeView闸准,嵌套TableView可以降低代碼的耦合,將不同的業(yè)務模型分散處理梢灭。只是需要注意的是夷家,子TableView和父TableView的實現(xiàn)不應該在同一個文件中處理,也就是說delegate和dateSource不應該指向同一個對象敏释,可以將子TableView封裝成一個Cell库快,delegate和dataSource都交由這個Cell處理,這樣才能有效降低代碼的耦合钥顽,并且精簡原文件的邏輯和大小义屏。
4. UITableView中間層模型的封裝
相信很多人會Cell的展示邏輯直接放到TableView的delegate中處理,例如:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (A) {
if(B){
return BHeight;
}
return AHeight;
}else if (C) {
if(B){
return BHeight;
}
return CHeight;
}
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(A){
if(B) {
return 2;
}
return 1;
}else if(C) {
if(B){
return 2;
}
return 1;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(A) {
if(B) {
return BCell;
}
return ACell;
}else if(C) {
if(B){
return BCell;
}
return CCell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(A) {
if(B) {
doB();
}
doA();
}else if(C) {
if(B){
doB();
}
doC();
}
}
所有代理中的邏輯都必須相同蜂大,而且同樣的方法要寫多次闽铐,例如上面的B。使用這樣的方式奶浦,當遇到邏輯非常復雜的TableView時將使我們苦不堪言兄墅。TableView的代理應該只負責去構建Cell,而不應該來處理邏輯判斷澳叉。所以隙咸,我們應該構建一個中間的模型層,在TableView reloadData的時候加載這個模型層耳高,例如:
- (void)setupTableModel
{
if(A) {
if(B) {
[arrayModel addObject:BModel];
}
[arrayModel addObject:AModel];
}else if(C) {
if(B){
[arrayModel addObject:BModel];
}
[arrayModel addObject:CModel];
}
}
- (void)reloadTable
{
[self setupTableModel];
[tableView reloadData];
}
此時:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[array objectAtIndex:row] isEqual:AModel]) {
return AHeight;
}else if ([[array objectAtIndex:row] isEqual:BModel]) {
return BHeight;
}else if ([[array objectAtIndex:row] isEqual:CModel]) {
return CHeight;
}
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrayModel.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[array objectAtIndex:row] isEqual:AModel]) {
return ACell;
}else if ([[array objectAtIndex:row] isEqual:BModel]) {
return BCell;
}else if ([[array objectAtIndex:row] isEqual:CModel]) {
return CCell;
}
return nil;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[array objectAtIndex:row] isEqual:AModel]) {
doA();
}else if ([[array objectAtIndex:row] isEqual:BModel]) {
doA();
}else if ([[array objectAtIndex:row] isEqual:CModel]) {
doA();
}
}
此時的delegate中只關注tableView的Cell構建和Cell行為扎瓶,并不關心任何構建順序等邏輯判斷所踊。