iOS开发初探篇——表视图中的MVC运用
概述
本初探篇为本人学习iOS开发中的一个总结系列,为工作和业余学习中遇到的初级问题的一个初步探究。本文初探的内容是MVC设计模式在表视图中的应用。主要以探究MVC为主,至于OC基本语法和表视图的使用上的优化等问题先不考虑。首先感谢博主KC写的精彩博文。
本文主要内容如下:
1.MVC基本介绍
2.MVC在表视图中的应用
MVC基本介绍
MVC模式这个名词太熟悉,不过本人由于缺乏工程实践经验,对其理解目前还停留在理论的表面层次上。在iOS开发中MVC模式第一次在表视图设计中应用到,想借此机会对其有个初步的认识。
MVC在表视图中的对号入座,目前的理解为如下图所示:
MVC在表视图中的应用
对上图再补充说明:在定制TableViewCell中,Cell即为MVC中的View,Model中的数据一般来自网络请求得到的数据,简单的模型可以封装成由各类属性组成字典,然后字典封装到可变数组中。具体用法会在下面的内容中进行介绍。严格意义上的MVC是不允许Model和View之间进行数据访问的。但实际情况有时也不一定严格遵守。下面做一个简单的具体工程实例。
首先UI需求如下图所示,显然我们需要定制TaleView中的Cell。
1.Model的定制
我们需要通过网格请求获取到的数据有:具体的图片、具体的姓名、具体的昵称。在这里先包装成字典的形式,然后把字典传到Model中。Model根据字典的key获取Value组装成一个类供Cell使用。注意,不同的字典就可以生成不同的Model类。在这里做一个学生类的形式进行展现。具体的代码如下所示。
// // Student.h // CustomCellByCode // // Created by hushunfeng on 15-6-20. // Copyright (c) 2015年 CMCC. All rights reserved. // #import <Foundation/Foundation.h> @interface Student : NSObject @property (strong, nonatomic) UIImage *icon; @property (strong, nonatomic) NSString *name; @property (strong, nonatomic) NSString *nickname; -(Student*)initWithDictionary:(NSDictionary *)dic; @end
// // Student.m // CustomCellByCode // // Created by hushunfeng on 15-6-20. // Copyright (c) 2015年 CMCC. All rights reserved. // #import "Student.h" @implementation Student - (Student *) initWithDictionary:(NSDictionary *)dic{ if(self = [super init]){ self.icon = dic[@"image"]; self.name = dic[@"name"]; self.nickname = dic[@"nickname"]; } return self; } @end
2.Cell的定制
Cell的定制根据UI界面的实际情况来就行。此设计中,姓名:,昵称:是写死在Cell中的。需要变动的只是图片、真实姓名和真实昵称。具体代码如下。
// // MyCell.h // CustomCellByCode // // Created by hushunfeng on 14-8-27. // Copyright (c) 2014年 e世雕龙. All rights reserved. // #import <UIKit/UIKit.h> #import "Student.h" @interface MyCell : UITableViewCell @property (strong, nonatomic) UIImageView *myImageView;//头像 @property (strong, nonatomic) UILabel *nameLabel;//姓名 @property (strong, nonatomic) UILabel *nicknameLabel;//昵称 @property (strong,nonatomic) Student *stu; @end
// // MyCell.m // CustomCellByCode // // Created by hushunfeng on 15-6-20. // Copyright (c) 2015年 CMCC. All rights reserved. // #import "MyCell.h" @implementation MyCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // Initialization code //创建自定义单元格中控件 //写死的 UILabel *nameLabel = [[UILabel alloc]initWithFrame:CGRectMake(160, 45, 51, 21)]; nameLabel.text = @"姓名:"; UILabel *nicknameLabel = [[UILabel alloc]initWithFrame:CGRectMake(160, 80, 51, 21)]; nicknameLabel.text = @"昵称:"; //根据model传进来的值要变动的 self.nameLabel = [[UILabel alloc]initWithFrame:CGRectMake(239, 45, 51, 21)]; self.myImageView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 10, 120, 120)]; self.nicknameLabel = [[UILabel alloc]initWithFrame:CGRectMake(239, 80, 51, 21)]; //加入单元格内容视图中 [self.contentView addSubview:self.myImageView]; [self.contentView addSubview:nameLabel]; [self.contentView addSubview:self.nameLabel]; [self.contentView addSubview:nicknameLabel]; [self.contentView addSubview:self.nicknameLabel]; } return self; } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state } #pragma mark 绑定model传进来的数据的方法 - (void)bind:(Student *)stu { self.myImageView.image = stu.icon; self.nameLabel.text = stu.name; self.nicknameLabel.text = stu.nickname; } @end
3.ViewController
// // MainViewController.h // CustomCellByCode // // Created by hushunfeng on 15-6-20. // Copyright (c) 2014年 CMCC. All rights reserved. // #import <UIKit/UIKit.h> @interface MainViewController:UIViewController <UITableViewDataSource,UITableViewDelegate> @end
// // MainViewController.m // CustomCellByCode // // Created by hushufeng on 15-6-20. // Copyright (c) 2014年 CMCC. All rights reserved. // #import "MainViewController.h" #import "Student.h" #import "MyCell.h" @interface MainViewController () @property (strong,nonatomic) UITableView *tableView; @property (strong, nonatomic) NSMutableArray *students;//数据源 @end @implementation MainViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height) style:UITableViewStylePlain]; self.tableView.dataSource = self; self.tableView.delegate = self; [self.view addSubview:self.tableView]; //准备数据源 UIImageView *view1 = [[UIImageView alloc]init]; view1.image = [UIImage imageNamed:@"guan"]; UIImageView *view2 = [[UIImageView alloc]init]; view2.image = [UIImage imageNamed:@"hejin"]; UIImageView *view3 = [[UIImageView alloc]init]; view3.image = [UIImage imageNamed:@"tang"]; NSDictionary *dic1 = @{@"image":view1.image, @"name":@"孙悟空", @"nickname":@"猴子"}; NSDictionary *dic2 = @{@"image":view2.image, @"name":@"八戒", @"nickname":@"呆子"}; NSDictionary *dic3 = @{@"image":view3.image, @"name":@"唐僧", @"nickname":@"三藏"}; Student *model1 = [[Student alloc]initWithDictionary:dic1]; Student *model2 = [[Student alloc]initWithDictionary:dic2]; Student *model3 = [[Student alloc]initWithDictionary:dic3]; // self.students = [[NSMutableArray alloc]init]; [self.students addObject:model1]; [self.students addObject:model2]; [self.students addObject:model3]; // self.students = [NSArray arrayWithObjects:model1,model2,model3, nil]; } #pragma mark - Table view data source //该数据源方法指定表视图有几个分区 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } //该数据源方法指定表视图每个分区有几行数据 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return self.students.count; } //该数据源方法指定表视图如何显示数据 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //创建可重用标识符 static NSString *cellID = @"cellID"; //首先从出列可重用队列中获取单元格 MyCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; //如果没有则创建单元格 if (!cell) { cell = [[MyCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; } // //获取Student对象 Student *stu = [[Student alloc]init]; stu = self.students[indexPath.row]; [cell bind:stu];//绑定数据 return cell; } #pragma mark 该数据源方法指定单元格的高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 141; } /* // Override to support conditional editing of the table view. - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the specified item to be editable. return YES; } */ /* // Override to support editing the table view. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the row from the data source [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } } */ /* // Override to support rearranging the table view. - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { } */ /* // Override to support conditional rearranging of the table view. - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the item to be re-orderable. return YES; } */ /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
效果图: