iOS translation Series: clean table view code

This article from the  Bole Online  -  Christian  translated from  Florian Kugler . Welcome to the technical translation team . See reprint requirements at the end of the article.

A table view is very versatile iOS application building blocks. Thus, there are many directly or indirectly related to the code table view, including providing data, updates the table view, select and control its behavior to make the reaction, which just a few examples. In this article, we will introduce some of the neat and well-structured code.

 

UITableViewController VS UIViewControler

Apple provides UITableViewController specific view controller as a table view. Table view controllers to achieve some very useful features to help you avoid writing duplicate code. On the other hand, Table view controllers management table is limited to a full screen view. However, in most cases, which can meet your needs. If not, we will explain in the following ways to solve it.

 

Table View Controllers feature

Table View Controllers will help you load the data table view when it was first displayed. More specifically, it can help edit mode switching table view, to respond to notices of the keyboard, such as rolling refresh and clear the kind of small options. Importantly, you can customize the subclasses to override these views can be called universal time methods to achieve these characteristics.

Table View Controllers have a unique selling point beyond the unique selling point of the standard view controller, which supports Apple's z "drop-down update" feature is, this is the only way to control refresh the record of a table by using the controller. There are other ways to make it take effect, but the next update in iOS is not so easy

All these principles provide a large number of table view controller interface like Apple has defined as APP if you meet these criteria, stick with the table view controller is a good way to avoid rewriting the template code.

 

Limit Table View Controller

View View Controller attribute table is always set on a table view. If you later decide you want to display things (such as maps) in addition to the view of the table on the screen, if you do not want to rely on clumsy patch that you have a disaster.

If you are already defined in the code defines the interface or use .xib file, then convert to a standard view controller will be quite easy. If you use a script, then this conversion process involves a few more steps. Script, you need to re-create a table view controller to put into a standard table view controller. This means that you must copy all the contents to the new controller and then try to re-establish. Finally, you need to add it again during the transition lost Menu view controller. Most of them are viewWillAppear or viewDidAppear in simple one-line statement. Edit mode is switched requires a click editing table view property method is performed. Most of the work is to re-create keyboard support.

Before you continue to go this route, there is a separation of concerns simple alternative to additional benefits.

 

Sub-view controller

Not to completely get rid of Table View Manager, you can also view it as a sub-controller is added to another view controller (see article on view control manager). Table View Manager then only need to continue to manage the table view and the parent View Manager can handle any additional interface elements you need.

1
2
3
4
5
6
7
8
9
10
11
12
- ( void )addPhotoDetailsTableView
{
     DetailsViewController *details = [[DetailsViewController alloc] init];
     details.photo = self.photo;
     details.delegate = self;
     [self addChildViewController:details];
     CGRect frame = self.view.bounds;
     frame.origin.y = 110;
     details.view.frame = frame;
     [self.view addSubview:details.view];   
     [details didMoveToParentViewController:self];
}

If you choose this solution, you need to establish a communication channel between a child and parent views view. For example, in order to view another push in, the parent view of the need to know the cell table view is selected. For this use scenario, the cleanest way is defined as a table view controller proxy protocol, this protocol may be implemented in the parent view.

If you want to use this solution, you have to create a communication channel from the sub-class to the parent class. For example, if the user selects a cell in the table view, the parent view controller needs to receive the message further to promote the view controller. According to an example, it is generally the most simple method of this table is defined as a view controller trust agreement, then you achieve the parent view manager.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@protocol DetailsViewControllerDelegate
- ( void )didSelectPhotoAttributeWithKey:(NSString *)key;
@end
 
@interface PhotoViewController () <DetailsViewControllerDelegate>
@end
 
@implementation PhotoViewController
// ...
- ( void )didSelectPhotoAttributeWithKey:(NSString *)key
{
     DetailViewController *controller = [[DetailViewController alloc] init];
     controller.key = key;
     [self.navigationController pushViewController:controller animated:YES];
}
@end

As you can see, this structure will be accompanied by some other overhead in communication between the view controller in exchange for a clean separation of concerns and better reusability. Depending on the use case, things eventually will need more than simpler or more complex, you need to consider and decide.

 

Separation of concerns

There are a variety of tasks on the model, controller and views across the border issues when dealing with table view. In order to prevent the view controller becomes a place to store these tasks, we will speak view these tasks alone on a more appropriate place. This helps readability, maintainability and testability of the code.

In view of the controller of contempt article describes in detail the concept and expansion techniques. How our data sources and model logic introduced. In view of the environment table, we will specifically look at how to separate the issues of concerns and views view controller.

 

Bridging the gap between model objects and elements

In a way, we have to hand over the data you want to display in the view layer. Because we want to maintain a clear separation point between a model and the view, often put this task into the source of data in the table view.

1
2
3
4
5
6
7
8
9
- (UITableViewCell *)tableView:(UITableView *)tableView
          cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:@ "PhotoCell" ];
     Photo *photo = [self itemAtIndexPath:indexPath];
     cell.photoTitleLabel.text = photo.name;
     NSString* date = [self.dateFormatter stringFromDate:photo.creationDate];
     cell.photoDateLabel.text = date;
}

This code and data source design logic cell bound together. We will be the best class in the cell category reconstruct it.

1
2
3
4
5
6
7
8
9
10
@implementation PhotoCell (ConfigureForPhoto)
 
- ( void )configureForPhoto:(Photo *)photo
{
     self.photoTitleLabel.text = photo.name;
     NSString* date = [self.dateFormatter stringFromDate:photo.creationDate];
     self.photoDateLabel.text = date;
}
 
@end

In this case, our data source code becomes very simple.

1
2
3
4
5
6
7
- (UITableViewCell *)tableView:(UITableView *)tableView
          cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:PhotoCellIdentifier];
     [cell configureForPhoto:[self itemAtIndexPath:indexPath]];
     return cell;
}

In the sample code, the time when the initialization cell block manner, the data source table have been isolated view of a single control object, in this case, the block as follows

1
2
3
TableViewCellConfigureBlock block = ^(PhotoCell *cell, Photo *photo) {
     [cell configureForPhoto:photo];
};

 

The cell can be reused

In this case there are multiple data models use the same cell type demonstrated under, we can enter even one step we can achieve cell reuse effect. First, we define a protocol object requires the use of all the cell types present data are to be achieved. We then modify the configuration of some cell category, so that it can accept any object follow the above protocol. These two simple steps, and the cell and the cell separation data model can accept different types of data.

Processing state in the cell in the cell

If we wanted to do something different from the default table view and highlight selected, we need to implement ways to achieve the two agents cell modified to state that we want. E.g:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- ( void )tableView:(UITableView *)tableView
         didHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
     PhotoCell *cell = [tableView cellForRowAtIndexPath:indexPath];
     cell.photoTitleLabel.shadowColor = [UIColor darkGrayColor];
     cell.photoTitleLabel.shadowOffset = CGSizeMake(3, 3);
}
 
- ( void )tableView:(UITableView *)tableView
         didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
     PhotoCell *cell = [tableView cellForRowAtIndexPath:indexPath];
     cell.photoTitleLabel.shadowColor = nil;
}

然而,这两个方法需要依赖于知道cell是如何布局的,如果我们想要换一个cel或者重新设计cell,我们同样需要修改这段代理代码。view的设计细节就和代理交织在一起了,我们应该将这段逻辑放到cell中。

1
2
3
4
5
6
7
8
9
10
11
12
13
@implementation PhotoCell
// ...
- ( void )setHighlighted:( BOOL )highlighted animated:( BOOL )animated
{
     [super setHighlighted:highlighted animated:animated];
     if (highlighted) {
         self.photoTitleLabel.shadowColor = [UIColor darkGrayColor];
         self.photoTitleLabel.shadowOffset = CGSizeMake(3, 3);
     } else {
         self.photoTitleLabel.shadowColor = nil;
     }
}
@end

一般来说,我们强烈建议将view层的实现细节和控制器层的实现细节分离开来。代理可以知道view的状态变化,但是不应该知道如何修改view的树状结构以及它的子视图应该设成什么状态,所有这些状态都应该封装在view中,然后提供给外部一个访问的接口。

 

处理多种cell类型

如果在一个table view中有多种cell类型,数据源就要变得失控了。在我们的示例app中,我们的照片详情表格有两种不同类型的cell:一个显示评分,另一个就是一般的显示键-值的cell。为了将显示不同cell类型的代码分离,数据源方法里就是简单调用不同类型cell的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- (UITableViewCell *)tableView:(UITableView *)tableView 
          cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     NSString *key = self.keys[(NSUInteger) indexPath.row];
     id value = [self.photo valueForKey:key];
     UITableViewCell *cell;
     if ([key isEqual:PhotoRatingKey]) {
         cell = [self cellForRating:value indexPath:indexPath];
     } else {
         cell = [self detailCellForKey:key value:value];
     }
     return cell;
}
 
- (RatingCell *)cellForRating:(NSNumber *)rating
                     indexPath:(NSIndexPath *)indexPath
{
     // ...
}
 
- (UITableViewCell *)detailCellForKey:(NSString *)key
                                 value:(id)value
{
     // ...
}

table view 的编辑

table view提供了简单易用的编辑功能,可以重新排序和删除cell。在发生这些事件的情况下,表数据源会通过代理方法的形式获得通知。因此,我们经常看到逻辑的代理方法来执行实际修改数据。

处理数据完全就是模型层的工作。模型层应该提供我们可以从数据源代理方法中调用的用来删除和重新排列数据的接口。用这种方法,控制器就只扮演了视图和模型层之间的协调者,不必知道模型层的实现细节。另外一个好处是,逻辑模型变得更容易的进行测试,因为它不再和控制器层的东西进行交互任务。

 

结论

Table view controllers (和其他控制器对象)大部分情况下都应该起着模型和视图对象之间的协调中介作用,他们不应该关心模型或者视图的具体实现细节。如果你记住这点,那么代表和数据源方法就变得更简单和更容易维护的样板代码了。

这样不仅会降低了Table view controllers 的代码规模和复杂性,而且使模型逻辑代码和视图代码放在了更合适的地方。控制器上下之间的实现细节都被隐藏在简单的API中,最终使得代码更容易理解和协同工作。

 


Original link:  Florian Kugler    translation:  Bole Online  Christian
translation link:  http://blog.jobbole.com/53123/
reproduced must be marked in the text and retain the original link, translators and translation links and other information. ]

Reproduced in: https: //www.cnblogs.com/zhengJason/p/3679394.html

Guess you like

Origin blog.csdn.net/weixin_34336526/article/details/93462273