iOS programming UITableView and UITableViewController
iOS programming UITableView and UITableViewController
A UITableView displays a single column of data with a variable number of rows.
UITableView 展示单列数据和不定数量的行。
Create a new iOS Empty Application project and configure it
1.1 UITableViewController
Model-View-Controller design pattern
(1)Model: Holds data and knows nothing about the user interface.
拥有数据却不知道用户界面。
(2)View: Is visible to the user and knows nothing about the model objects.
可以被用户看到,却不知道model对象
(3)Controller: Keeps the user interface and the model objects in sync. Controls the flow of the application; for example, the controller might be responsible for showing a "Really delete this item?" message before actually deleting some data.
保持用户界面和模型对象同步。例如控制器可能在确定要删除一些数据之前,负责显示 "确定要删除这项吗" 。
a UITableView, a view object, does not handle application logic or data.
因此,UITableView,一个view object ,不知道如何处理逻辑和数据。
When using a UITableView, you must consider what else is necessary to get the table working in your application:
当你想使用一个UITableIView时,你必须考虑在你的应用程序中还有什么需要的才能让table 工作。
(1)A UITableView typically needs a view controller to handle its appearance on the screen.
一个UITableView 一般需要一个view controller 处理它的显示部分。
(2)A UITableView needs a data source. A UITableView asks its data source for the number of rows
to display, the data to be shown in those rows, and other tidbits that make a UITableView a useful user interface. Without a data source, a table view is just an empty container. The dataSource for a UITableView can be any type of Objective-C object as long as it conforms to the UITableViewDataSource protocol.
UITableView需要一个data source.一个UITableView 要求data source 有几行要显示,要显示的数据,和其他好东西让UITableView 成为一个有用的user interface .datasource 可以是任何顺从了UITableViewDataSource protocol 的对象。
(3)A UITableView typically needs a delegate that can inform other objects of events involving the UITableView. The delegate can be any object as long as it conforms to the UITableViewDelegate protocol.
UITableVIew 一般需要一个delegate 来通知其他涉及UITableView的对象。delegate可以是任何遵守了UITableViewDelegate protocol 的对象。
An instance of the class UITableViewController can fill all three roles: view controller, data source, and delegate.
一个UITableViewController的实例能填充三个角色:view controller ,data source ,and delegate.
UITableViewController is a subclass of UIViewController, so a UITableViewController has a view. A UITableViewController's view is always an instance of UITableView, and the UITableViewController handles the preparation and presentation of the UITableView.
UITableViewController 是UIViewController的子类。所以UITableViewController有一个view,它的view是UITableView,UITableViewCOntroller负责UITableView的准备和展现
When a UITableViewController creates its view, the dataSource and delegate instance variables of the UITableView are automatically set to point at the UITableViewController
当UITableViewController创建一个view时,UITableView 的dataSource和delegate将自动的指向UITableViewController。
1.2 Subclassing UITableViewController
#import <UIKit/UIKit.h>
@interface BNRItemsViewController : UITableViewController
The designated initializer of UITableViewController is initWithStyle:, which takes a constant that determines the style of the table view.
UITableViewController指定的初始化方法是initWithStyle,将有一个常量决定table view的样式。
There are two options: 有两个选择:
UITableViewStylePlain and
UITableViewStyleGrouped.
You are changing the designated initializer to init. As such, you need to follow the two rules of initializers:
你将初始化部分放在了init 方法里。这样你要做两件事情。
(1)Call the superclass's designated initializer from yours
调用superclass 的指定initializer初始化你的。
(2)Override the superclass's designated initializer to call yours
重现superclass的指定的initializer来调用你自己。
- (instancetype)init
{
// Call the superclass's designated initializer
self = [super initWithStyle:UITableViewStylePlain];
return self;
}
- (instancetype)initWithStyle:(UITableViewStyle)style
{
return [self init];
}
in BNRAppDelegate ,
#import "BNRItemsViewController.h"
// Create a BNRItemsViewController BNRItemsViewController *itemsViewController =
[[BNRItemsViewController alloc] init];
// Place BNRItemsViewController's table view in the window hierarchy self.window.rootViewController = itemsViewController;
1.3 UITableView's Data Source
1.4 Creating BNRItemStore
BNRItemStore will be a singleton.
BNRItemStore将会是单例的。
This means there will only be one instance of this type in the application; if you try to create another instance, the class will quietly return the existing instance
也就是说将在应用中将只有一个实例。如果你想创建另外一个实例,这个类将返回一个已经存在的实例。
#import <Foundation/Foundation.h>
@interface BNRItemStore : NSObject
// Notice that this is a class method and prefixed with a + instead of a -
+ (instancetype)sharedStore;
@end
When this message is sent to the BNRItemStore class, the class will check to see if the single instance of BNRItemStore has already been created. If it has, the class will return the instance. If not, it will create the instance and return it.
当这个消息发送给BNRItemStore,这个类将会检查是否已经创建了一个实例,如果创建了,就返回这个实例,如果没有,就创建并返回一个实例。
@implementation BNRItemStore
+ (instancetype)sharedStore
{
static BNRItemStore *sharedStore = nil;
// Do I need to create a sharedStore?
if (!sharedStore) {
sharedStore = [[self alloc] initPrivate]; }
return sharedStore; }
// If a programmer calls [[BNRItemStore alloc] init], let him know the error of his ways
- (instancetype)init
{
@throw [NSException exceptionWithName:@"Singleton" reason:@"Use +[BNRItemStore sharedStore]"
return nil; {
userInfo:nil];
// Here is the real (secret) initializer
- (instancetype)initPrivate
{
self = [super init];
return self; }
Notice that the variable sharedStore is declared as static. A static variable is not destroyed when the method is done executing. Like a global variable, it is not kept on the stack.
注意到sharedStore声明为一个static 。当一个方法执行完成后,一个static 变量不被销毁。像全局变量,它并不保存在stack中。
@class BNRItem;
@property (nonatomic, readonly) NSArray *allItems;
- (BNRItem *)createItem;
See the @class directive? That tells the compiler that there is a BNRItem class and that the compiler does not need to know this class's details in the current file – only that it exists.
它告诉编译器有一个这样的BNRItem类,而编译器现在不需要知道它的细节,只需要知道它存在就行了。
Using the @class directive can speed up compile times considerably because fewer files have to be recompiled when one file changes.
如果考虑到有些时候当文件变化时,文件需要重新编译 ,用@class命令可能加速编译。、
但是当我们需要知道这个类中得细节的时候,我们还是需要导入的。
@interface BNRItemStore ()
@property (nonatomic) NSMutableArray *privateItems;
@end
- (BNRItem *)createItem
{
BNRItem *item = [BNRItem randomItem];
[self.privateItems addObject:item];
return item; }
1.5 Implementing data source methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [[[BNRItemStore sharedStore] allItems] count];
}
When Apple started supporting both 32-bit and 64-bit systems, they needed an integer type that was a 32-bit int in 32-bit applications and a 64-bit int in 64-bit applications.
当apple 开始支持32-bit 和64-bit系统,他们需要32和64的实数在32和64位的机器里面。
Thus, NSInteger (which is signed) and NSUInteger (which is unsigned) were born. These types are used extensively throughout Apple's frameworks.
因此NSInteger(有符号)和NSUInteger(无符号)就出现了。
1.6 UITableViewCells
Each row of a table view is a view.
table view 的每一行都是一个view。
These views are instances of UITableViewCell.
这些view是UITableViewCell的一个实例。
A cell itself has one subview – its contentView
每一个cell 又有一个contentView。
The contentView is the superview for the content of the cell.
每个contentView是这个cell 内容的superview。
The real meat of a UITableViewCell is the three subviews of the contentView. Two of those subviews are UILabel instances that are properties of UITableViewCell named textLabel and detailTextLabel. The third subview is a UIImageView called imageView
实际中,UITableViewCell 是contentView的三个子类。两个是UILabel 为textLabel 和detailTextLabel。第三个是UIImageVIew 叫做imageView。
Each cell also has a UITableViewCellStyle that determines which subviews are used and their position within the contentView.
每个cell 都有一个UITableViewCellStyle决定那个subview 需要用到和在contentView 的位置。
How do you decide which cell a BNRItem corresponds to? One of the parameters sent to tableView:cellForRowAtIndexPath: is an NSIndexPath, which has two properties: section and row. When this message is sent to a data source, the table view is asking, "Can I have a cell to display in section X, row Y?" Because there is only one section in this exercise, your implementation will only be concerned with the row.
When this message is sent to a data source, the table view is asking, "Can I have a cell to display in section X, row Y?" 当这个消息被发送给data source,table view 正在询问:"我能不能有一个展现在x section,y row的cell "。
1.7 Resuing UITableViewCells
When the user scrolls the table, some cells move offscreen. Offscreen cells are put into a pool of cells available for reuse.
当用户scroll table,一些cell 移动到offscreen。Offscreen cells 放在一个能重新利用的cell pool中。
Then, instead of creating a brand new cell for every request, the data source first checks the pool.
不是先为每次请求创建一个新的cell,data source 首先检查这个pool
If there is an unused cell, the data source configures it with new data and returns it to the table view.
如果里面有一个未被利用的cell,那么data source 配置给他新的数据并返回给table view。
There is one problem: sometimes a UITableView has different types of cells.
有时候 UITableView有不同类型的cell。
Occasionally, you have to subclass UITableViewCell to create a special look or behavior.
有时候你还需要继承UITableView创建不同外观的table view。
However, different subclasses floating around the pool of reusable cells create the possibility of getting back a cell of the wrong type.
由于不同的子类产生了
You must be sure of the type of the cell returned to you so that you can be sure of what properties and methods it has.
你必须确定返回给你的cell的类型,这样你才能确定它有什么属性和方法。
you do not care about getting any specific cell out of the pool because you are going to change the cell content anyway.
你并不关心从pool中获得特殊的cell 因为不管怎样,你都会改变cell content。
What you need is a cell of a specific type.
你所需要的是cell 的特殊类型。
The good news is that every cell has a reuseIdentifier property of type NSString.
好消息是每个cell 都有一个类型为NSString的reuseIdentifier属性。
When a data source asks the table view for a reusable cell, it passes a string and says, "I need a cell with this reuse identifier."
当一个数据源请求table view 一个reusable cell时,它传递了一个string并说:"我需要一个cell 有这样的reuse identifier"
// Get a new or recycled cell UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath];
you are giving that control to Apple to get the benefits of the reuse identifier.
你把控制权给Apple 来获得reuse identifier的好处 。
For this to work, you need to tell the table view which kind of cell it should instantiate if there are no cells in the reuse pool.
为了让这个工作,你需要告诉table view 假若在reuse pool 里没有可用的cell时我们选择那样类型的cell 来初始化。
In BNRItemsViewController.m, override viewDidLoad to register UITableViewCell class with the table view.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"];
}
Reusing cells means that you only have to create a handful of cells, which puts fewer demands on memory.
重新利用cells意味着 你只需要创建一把cell,这将会要求很少的内存。