IOS development-UITableView, the most common control

Source: Internet
Author: User

IOS development-UITableView, the most common control
UITableView

Set dataSource and delegate of UITableView
Display of multiple groups of data and single group of data in UITableView
Common attributes of UITableViewCell
UITableView performance optimization (cell Recycling)
Custom Cell

How to display data

UITableView requires a data source to display data.
UITableView queries the total number of rows of data from the data source and the data displayed in each row.
UITableView with no data source set is just an empty shell
Any OC object that complies with the UITableViewDataSource protocol can be a UITableView data source.

UITableViewUITableViewDataSource
@property (nonatomic, assign) id 
  
    dataSource;
  
// Call the following method of the data source to know the total number of data groups-(NSInteger) numberOfSectionsInTableView :( UITableView *) tableView; // call the following method of the data source to know how many rows of data each group has-(NSInteger) tableView :( UITableView *) tableView numberOfRowsInSection :( NSInteger) section; // call the following method of the data source to learn what is displayed in each row-(UITableViewCell *) tableView :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) indexPath;
MVC design philosophy

MVC is a design concept that runs throughout iOS development. It requires a certain amount of project experience to deeply understand its meaning and benefits.

Three roles in MVC

// M: Model, Model data // V: View, View (Interface) // C: Control, Control center

Several obvious features and manifestations of MVC:
What is displayed on the View depends on the Model.
As long as the Model data is changed, the display status of the View changes accordingly.
Control initializes the Model and passes the Model to the View for parsing and display.

Introduction to UITableViewCell

Each row of UITableView is a UITableViewCell. The tableView: cellForRowAtIndexPath: Method of dataSource is used to initialize each row.

UITableViewCell has a default sub-View: contentView. contentView is the parent view of the content displayed by UITableViewCell. It can display some secondary indicator views.

The secondary indicator view is used to display an icon indicating an action. You can set the accessoryType of UITableViewCell to display it. The default value is UITableViewCellAccessoryNone (no secondary indicator view is displayed). The other values are as follows:

UITableViewCellAccessoryDisclosureIndicatorUITableViewCellAccessoryDetailDisclosureButtonUITableViewCellAccessoryCheckmark

You can also use the cell accessoryView attribute to customize the secondary indicator view (for example, place a switch to the right)

ContentView of UITableViewCell

By default, contentView has three subviews.
Two of them are UILabel (accessed through the textLabel and detailTextLabel attributes of UITableViewCell)
UIImageView (accessed through the imageView attribute of UITableViewCell)
UITableViewCell also has a UITableViewCellStyle attribute to determine which child views are used for contentView and their location in contentView.

UITableViewCell Structure

Cell Reuse Principle

The memory of iOS devices is limited. If you use UITableView to display thousands of data records, you need thousands of UITableViewCell objects, which consumes the memory of iOS devices. To solve this problem, you need to reuse the UITableViewCell object.

Reuse Principle: when the list is rolled, some uitableviewcells will be removed from the window, And UITableView will put UITableViewCell outside the window into an object pool, waiting for reuse. When UITableView requires dataSource to return UITableViewCell, dataSource will first view this object pool. If there is an unused UITableViewCell in the pool, dataSource will configure the UITableViewCell with new data and then return it to UITableView, re-display in the window to avoid creating new objects

There is another very important issue: Sometimes you need to customize UITableViewCell (using a subclass to inherit UITableViewCell), and each row does not necessarily use the same UITableViewCell, therefore, a UITableView may have different types of UITableViewCell, and there are many different types of UITableViewCell in the object pool. Therefore, when UITableView is used to reuse UITableViewCell, The UITableViewCell of the error type may be obtained.

Solution: UITableViewCell has an NSString * reuseIdentifier attribute. You can input a specific string identifier when initializing UITableViewCell to set the reuseIdentifier (generally the class name of UITableViewCell is used ). When UITableView requires dataSource to return UITableViewCell, it first uses a string to identify the corresponding type of UITableViewCell object in the object pool. If yes, It is reused. If no, this string identifier is passed in to initialize a UITableViewCell object.

Cell reuse code
-(UITableViewCell *) tableView :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) indexPath {// 1. define the identifier of a cell static NSString * ID = @ "mjcell"; // 2. retrieve cell UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: ID] From the cache pool; // 3. if no cell in the cache pool if (cell = nil) {cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: ID];} // 4. set cell attributes... return cell ;}
Create an xib file to describe the internal structure of a view (assuming XXXCell. xib) create a custom Class (the custom Class must inherit the view that comes with the system, and the Class that inherits the custom Class depends on the Class of the xib root object) the Class Name of the new class should be the same as the file name of the xib (for example, the class name is XXXTgCell. connecting m files provides a class method to return a created custom view (blocking the process of loading from xib). It provides a setter Method for passing model data to overwrite model attributes, here, we will display the model data to the use cases of Delegate on the corresponding child control.
Object A has some internal events and wants to notify object B that object B wants to listen to what happened in object A. Object A wants to call A method of object B in its own method, in addition, object A cannot be coupled with object B. Dependent object A wants to pass data to object B ...... In the above cases, the results are the same: object B is the proxy of object A (delegate)

First, find out who is the proxy (delegate)

Defines the proxy protocol. protocol naming rules: control class name + Delegate

Define proxy Methods
The proxy method is generally defined as @ optional.
The proxy method names start with the control name
The proxy method has at least one parameter and passes the control itself out.

Set the proxy (delegate) object (for example, myView. delegate = xxxx ;)
The proxy object complies with the protocol.
This implementation method in the proxy object Implementation Protocol

Call the proxy method of the proxy object (delegate) at the right time to notify the proxy of what happened.
(Determine whether the proxy method is implemented before the call)

Customize cell by code (cell height inconsistency)

1. Create a class that inherits from UITableViewCell
2. Override initWithStyle: reuseIdentifier: Method
Add all child controls to be displayed (you do not need to set the data and frame of the Child control. The child control must be added to contentView)
Perform one-time attribute setting for the sub-control (some attributes only need to be set once, such as font \ fixed image)
3. provide two models
Data Model: stores text data and image data.
Frame model: the height of the frame \ cell that stores the data model \ All child Controls
4. cell has a frame model (do not directly have a data model)
5. Override the setter method of the frame model attribute: In this method, set the display data and frame of the Child control.
6. the initialization of frame model data has taken the form of lazy loading (the frame model data corresponding to each cell is loaded only once)

UITableView Example 1: display the city list

Data Source plist file:

#import "ViewController.h"
@interface ViewController ()
  
   @property (weak, nonatomic) IBOutlet UITableView *tableView;@property (weak, nonatomic) IBOutlet UIToolbar *toolBar;@property NSArray *provinces;@property NSArray *cities;@end
  
@ Implementation ViewController-(void) viewDidLoad {[super viewDidLoad]; // load data NSBundle * mainbundle = [NSBundle mainBundle]; // if the type is not set, the extension self must be provided in the resource parameter. provinces = [NSArray arrayWithContentsOfFile: [mainbundle pathForResource: @ "provinces. plist "ofType: nil]; self. cities = [NSArray arrayWithContentsOfFile: [mainbundle pathForResource: @ "cities. plist "ofType: nil]; // bind NSArray * items = self. toolBar. items; for (UIBarButtonItem * item in items) {if (item. title) {NSLog (@ "current item: % @", item. title); [item setAction: @ selector (toolBarItemClick :)] ;}}# Number of pragma mark-UITableViewDataSouce data source methods/*** Section, total number of groups of data */-(NSInteger) numberOfSectionsInTableView :( UITableView *) tableView {return self. provinces. count;}/*** number of rows in the section */-(NSInteger) tableView :( UITableView *) tableView numberOfRowsInSection :( NSInteger) section {return [self. cities [section] count];}/*** content displayed in each row (cell) */-(UITableViewCell *) tableView :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) indexPath {NSLog (@ "TableView to get content: section: % d, row: % d", indexPath. section, indexPath. row); UITableViewCell * cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: nil]; // obtain the city array NSArray * city = self in cities. cities [indexPath. section]; cell. textLabel. text = city [indexPath. row]; [cell setSelectionStyle: UITableViewCellSelectionStyleNone]; // if the current cell is selected, set its selected accessoryType NSArray * selpaths = [tableView indexPathsForSelectedRows]; if ([selpaths containsObject: indexPath]) {cell. accessoryType = UITableViewCellAccessoryCheckmark;} return cell;}/*** add Index */-(NSArray *) sectionIndexTitlesForTableView :( UITableView *) tableView {return self. provinces;}/*** display the header title of the section group */-(NSString *) tableView :( UITableView *) tableView titleForHeaderInSection :( NSInteger) section {return self. provinces [section]; // name of each province} # pragma mark-UITableViewDelegate proxy method/*** call/-(NSIndexPath *) tableView :( UITableView *) when it is to be selected *) tableView willSelectRowAtIndexPath :( NSIndexPath *) indexPath {NSLog (@ "section: % d, row: % d to be selected", indexPath. section, indexPath. row); return indexPath;}/*** called when the current row is selected */-(void) tableView :( UITableView *) tableView didSelectRowAtIndexPath :( NSIndexPath *) indexPath {NSLog (@ "section: % d, row: % d already selected", indexPath. section, indexPath. row); // set its accessoryType to CheckMark UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath]; [cell setAccessoryType: UITableViewCellAccessoryCheckmark];} /*** called when the current row is about to be deselected */-(NSIndexPath *) tableView :( UITableView *) tableView willDeselectRowAtIndexPath :( NSIndexPath *) indexPath {NSLog (@ "section: % d, row: % d Will be deselected soon ", indexPath. section, indexPath. row); return indexPath;}/*** called when the current row is deselected */-(void) tableView :( UITableView *) tableView didDeselectRowAtIndexPath :( NSIndexPath *) indexPath {UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath]; [cell setAccessoryType: UITableViewCellAccessoryNone]; NSLog (@ "section: % d, row: % d has been deselected ", indexPath. section, indexPath. row) ;}# pragma mark-event method/*** click button */-(void) toolBarItemClick :( UIBarButtonItem *) sender {NSLog (@ "button: % @ clicked ", sender. title); if (sender. tag = 3) {NSArray * selIndexLst = [self. tableView indexPathsForSelectedRows]; NSLog (@ "selIndex: % @", selIndexLst); return ;}@ end

:

UITableView instance 2: Single-group data model display

Data Source plist file:

// Model class # import
  
   
@ Interface Hero: NSObject @ property (nonatomic, copy) NSString * name; @ property (nonatomic, copy) NSString * icon; @ property (nonatomic, copy) NSString * intro; + (instancetype) heroWithDict :( NSDictionary *) dict;-(instancetype) initWithDict :( NSDictionary *) dict; @ end
  
#import "Hero.h"@implementation Hero+ (instancetype)heroWithDict:(NSDictionary *)dict{    return [[self alloc]initWithDict:dict];}- (instancetype)initWithDict:(NSDictionary *)dict{    if (self==[super init]) {        [self setValuesForKeysWithDictionary:dict];    }    return self;}@end
#import "ViewController.h"#import "Hero.h"@interface ViewController ()
  
   @property(nonatomic,strong) NSArray* heros;@property (weak, nonatomic) IBOutlet UITableView *tableView;@end
  
@ Implementation ViewController-(void) viewDidLoad {[super viewDidLoad];}/*** hide the title bar */-(BOOL) prefersStatusBarHidden {return YES ;} // initialize-(NSArray *) heros {if (_ heros = nil) {// 1. obtain the full path NSString * path = [[NSBundle mainBundle] pathForResource: @ "heros. plist "ofType: nil]; // 2. load the array NSArray * dictArray = [NSArray arrayWithContentsOfFile: path]; // 3. convert all the dictionaries in dictArray into model objects and put them in the new array. NSMutableArray * heroArray = [NSMutableArray array]; for (NSDictionary * dict in dictArray) {// 3.1 create model object Hero * hero = [Hero heroWithDict: dict]; // 3.2 add model object to array [heroArray addObject: hero];} // 4. value assignment _ heros = heroArray;} return _ heros;} # pragma mark-data source method-(NSInteger) tableView :( UITableView *) tableView numberOfRowsInSection :( NSInteger) section {return self. heros. count;}/*** Knowledge Point 1: cell Performance Optimization * 1. search for reusable cells in the cache pool by using an identifier * 2. if no reusable cell is found in the cache pool, a new cell is created and an identifier is assigned to the cell * 3. set new data for the cell * // *** whenever a cell enters the field of view, tableView (UITableViewCell *) is called */-(UITableViewCell *) :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) indexPath {// static modifier local variable: ensure that local variables are allocated only once (only initialized once) static NSString * ID = @ "hero "; // 1. find the reusable cell by using an identifier in the cache pool. dequeue: output (Search) UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: ID]; // 2. if no cell if (cell = nil) {cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: ID]; NSLog (@ "------ the cache Pool cannot be found, therefore, cell-% ld ", (long) indexPath is created. row);} // 3. model Hero * hero = self. heros [indexPath. row]; // set the cell data cell. textLabel. text = hero. name; cell. detailTextLabel. text = hero. intro; cell. imageView. image = [UIImage imageNamed: hero. icon]; // set the cell type of the indicator on the right of the cell. accessoryType = UITableViewCellAccessoryDisclosureIndicator; // set the image background UIImageView * bgView = [[UIImageView alloc] init]; bgView. image = [UIImage imageNamed: @ "buttondelete"]; cell. backgroundView = bgView; // set the selected background UIView * selectedbgView = [[UIView alloc] init]; selectedbgView. backgroundColor = [UIColor greenColor]; cell. selectedBackgroundView = selectedbgView; return cell;} # pragma mark-proxy method // height between control and Status Bar-(CGFloat) tableView :( UITableView *) tableView heightForRowAtIndexPath :( NSIndexPath *) indexPath {return 60;}-(void) tableView :( UITableView *) tableView didSelectRowAtIndexPath :( NSIndexPath *) indexPath {// 1. the Hero * hero = self. heros [indexPath. row]; // pop-up box UIAlertView * alert = [[UIAlertView alloc] initWithTitle: @ "data display" message: nil delegate: self cancelButtonTitle: @ "cancel" otherButtonTitles: @ "OK", nil]; // set the dialog box type alert. alertViewStyle = UIAlertViewStylePlainTextInput; // obtain the unique text box and display the hero name [alert textFieldAtIndex: 0]. text = hero. name; [alert show]; // bind the row number to alertView. tag = indexPath. row;} //-(void) tableView :( UITableView *) tableView didDeselectRowAtIndexPath :( NSIndexPath *) indexPath // {///Deselect: deselect // NSLog (@ "unselect row % d", indexPath. row); //} # proxy method of pragma mark-alertView-(void) alertView :( UIAlertView *) alertView clickedButtonAtIndex :( NSInteger) buttonIndex {if (buttonIndex = 0) return; // 1. obtain the final text NSString * name = [alertView textFieldAtIndex: 0]. text; // 2. modify the model attribute int row = alertView. tag; Hero * hero = self. heros [row]; hero. name = name;/*** Knowledge Point 2: Data refresh * reloadData: tableView re-requests data from the data source and re-calls the corresponding method of the data source to obtain data * re-calls the tableView of the Data source: numberOfRowsInSection: Get the number of rows * re-call the tableView of the Data source: cellForRowAtIndexPath: Learn what cell is displayed for each row * // 3. let tableView reload model data // refresh all // [self. tableView reloadData]; // partial refresh NSIndexPath * path = [NSIndexPath indexPathForItem: row inSection: 0]; [self. tableView reloadRowsAtIndexPaths: @ [path] withRowAnimation: UITableViewRowAnimationBottom];} @ end

:

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.