iOS开发之MVC

来源:互联网 发布:pp助手 mac 铃声制作 编辑:程序博客网 时间:2024/06/12 07:27

好久没有写文章了,上一篇对于初学者可能比较有用的文章吧……

我的入行语言是Java、JSP,比较强调MVC模式,所以对MVC还是比较了解的。因此后来转入iOS开发,在模式上就没有那么纠结,但是对于很多初入编程领域的人来说可能会比较困惑,下面用一个简单的列表例子来说一下iOS开发当中的MVC模式。

首先,新建一个工程,在工程中新建两个UIViewController的子类,如图:



我将用这两个类来示例非MVC(MainViewController)和MVC(SecondViewController)模式,为了可读性和解释性更强,例子当中没有用IB,所有界面用代码写出(这也是我个人开发中的习惯)。

其中MainViewController.m代码如下

#import "MainViewController.h"#import "ASIFormDataRequest.h"#define kScreenWidth  [UIScreen mainScreen].bounds.size.width#define kScreenHeight [UIScreen mainScreen].bounds.size.height@interface MainViewController ()@property (nonatomic, retain) NSMutableArray *dataArray;@end@implementation MainViewController {    UITableView *_tableView;}- (void)viewDidLoad {    [super viewDidLoad];        [self setupDefaultValue];    [self setupDefaultView];    [self request];}- (void)setupDefaultValue {    self.dataArray = [NSMutableArray array];}- (void)setupDefaultView {    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight) style:UITableViewStylePlain];    _tableView.delegate = self;    _tableView.dataSource = self;    [self.view addSubview:_tableView];}- (void)request {    NSString *urlString = @"http://beautifulword.sinaapp.com/results.php";    NSURL *url = [NSURL URLWithString:urlString];        ASIFormDataRequest *_request = [ASIFormDataRequest requestWithURL:url];    __weak ASIFormDataRequest *request = _request;        [request setCompletionBlock:^{        NSData *data = request.responseData;        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];        NSArray *array = [dict objectForKey:@"Profile"];        for (NSDictionary *itemDict in array) {            [self.dataArray  addObject:itemDict];        }        [_tableView reloadData];    }];    [request setFailedBlock:^{        NSLog(@"failed");    }];        [request startAsynchronous];}#pragma mark- UITableView Delegate- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    return self.dataArray.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *cellID = @"cell";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];    if (cell == nil) {        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID];    }    NSDictionary *dict = self.dataArray[indexPath.row];    cell.textLabel.text = dict[@"name"];    cell.detailTextLabel.text = dict[@"age"];    return cell;}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];}@end

该类很简单,就三部分:初始化属性-初始化界面-网络请求刷新列表。

对于MVC模式,最核心的东西是控制器(Controller),在iOS工程当中,我们可以很容易找到它,从名字就能看出来,比如MainViewController,至于它的作用,可以从苹果官方的开发文档中找到:

View controllers are the foundation of your app’s internal structure. Every app has at least one view controller, and most apps have several. Each view controller manages a portion of your app’s user interface as well as the interactions between that interface and the underlying data. View controllers also facilitate transitions between different parts of your user interface.

简单来说就是管理界面、数据,以及管理界面和界面的变换、管理界面和数据的交互。我们可以看到从界面、数据初始化到网络请求都是在Controller中进行的,如果界面和数据特别复杂的话,这个类可能就会达到上千行,维护起来会特别麻烦,最夸张的可能 tableView:cellForRowAtIndexPath: 方法都有几百行。这时候MVC模式就体现出其优势了,我们将逻辑、数据和界面分离开来,这样在维护的时候就会变得非常容易。

我们来看MainViewController,这个类非常简单,逻辑也非常清楚,其中Model就是网络请求数据,View就是UITableView和UITableViewCell。第一步,先把Model拆分出来,我们新建一个Model类:


UserModel.h文件如下:

#import <Foundation/Foundation.h>@interface UserModel : NSObject@property (nonatomic, copy) NSString *name;@property (nonatomic, copy) NSString *age;@property (nonatomic, copy) NSString *gender;@property (nonatomic, copy) NSString *phone;@property (nonatomic, retain) NSMutableDictionary *dict;@end

UserMode.m文件如下:

#import "UserModel.h"@implementation UserModel- (id)init {    if (self == [super init]) {        self.dict = [[NSMutableDictionary alloc] init];    }    return self;}- (id)valueForUndefinedKey:(NSString *)key {    return @"";}- (void)setValue:(id)value forUndefinedKey:(NSString *)key {    [self.dict setObject:value forKey:key];}@end

这个类很简单,只包含了几个属性。然后我们修改MainViewController当中的请求方法如下:

- (void)request {    NSString *urlString = @"http://beautifulword.sinaapp.com/results.php";    NSURL *url = [NSURL URLWithString:urlString];        ASIFormDataRequest *_request = [ASIFormDataRequest requestWithURL:url];    __weak ASIFormDataRequest *request = _request;        [request setCompletionBlock:^{        NSData *data = request.responseData;        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];        self.dataArray = [dict objectForKey:@"Profile"];        [_tableView reloadData];    }];    [request setFailedBlock:^{        NSLog(@"failed");    }];        [request startAsynchronous];}- (void)setDataArray:(NSMutableArray *)dataArray {    for (NSDictionary *itemDict in dataArray) {        UserModel *model = [[UserModel alloc] init];        for (NSString *key in itemDict) {            [model setValue:itemDict[key] forKey:key];        }        [_dataArray  addObject:model];    }}

可以看到,dataArray中保存的不再是Dictionary,而是UserModel。当然,这个例子比较简单,UserModel内部没有涉及到更复杂的数据处理,所以并不能体现出它的优势,但在以后的开发当中,这么做肯定会事半功倍的。接下来呢,就是View的拆分了,在MainViewController当中初始化Cell的代码如下(这里为了方便,只写出了name和age两个属性):


一般情况下呢,我习惯自定义Cell,便于以后维护,接下来,新建一个TableViewCell的子类UserCell,.h文件如下:

#import <UIKit/UIKit.h>#import "UserModel.h"@interface UserCell : UITableViewCell@property (nonatomic, retain) UserModel *model;@end

UserCell.m文件如下

#import "UserCell.h"#define kScreenWidth  [UIScreen mainScreen].bounds.size.width#define kScreenHeight [UIScreen mainScreen].bounds.size.height@implementation UserCell {    UILabel *_nameLabel;    UILabel *_ageLabel;    UILabel *_genderLabel;    UILabel *_phoneLabel;}- (void)awakeFromNib {}- (UserCell *)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];    if (self) {        _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth/4, 40)];        _nameLabel.textColor = [UIColor blackColor];        _nameLabel.textAlignment = NSTextAlignmentCenter;        [self.contentView addSubview:_nameLabel];                _ageLabel = [[UILabel alloc] initWithFrame:CGRectMake(kScreenWidth/4, 0, kScreenWidth/4, 40)];        _ageLabel.textColor = [UIColor blackColor];        _ageLabel.textAlignment = NSTextAlignmentCenter;        [self.contentView addSubview:_ageLabel];                _genderLabel = [[UILabel alloc] initWithFrame:CGRectMake(kScreenWidth/4*2, 0, kScreenWidth/4/2, 40)];        _genderLabel.textColor = [UIColor blackColor];        _genderLabel.textAlignment = NSTextAlignmentCenter;        [self.contentView addSubview:_genderLabel];                _phoneLabel = [[UILabel alloc] initWithFrame:CGRectMake(kScreenWidth/4*3-kScreenWidth/4/2, 0, kScreenWidth/4+kScreenWidth/4/2, 40)];        _phoneLabel.textColor = [UIColor blackColor];        _phoneLabel.textAlignment = NSTextAlignmentCenter;        [self.contentView addSubview:_phoneLabel];    }    return self;}- (void)setSelected:(BOOL)selected animated:(BOOL)animated {    [super setSelected:selected animated:animated];}- (void)setModel:(UserModel *)model {    _model = model;    _nameLabel.text = model.name;    _ageLabel.text = model.age;    _genderLabel.text = model.gender;    _phoneLabel.text = model.phone;}@end

Cell的初始化呢,就都封装到UserCell类当中了,MainViewController中的tableView:cellForRowAtIndex:方法就改成如下了:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *cellID = @"cell";    UserCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];    if (cell == nil) {        cell = [[UserCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];    }    cell.model = self.dataArray[indexPath.row];    return cell;}

这样,当我们需要调整Cell布局的时候呢,就不需要再修改MainViewController类了,只需要找到UserCell调整就可以了。

MVC分离完成之后,将代码整理到另一个类SecondViewController中,如下:

#import "SecondViewController.h"#import "ASIFormDataRequest.h"#import "UserModel.h"#import "UserCell.h"#define kScreenWidth  [UIScreen mainScreen].bounds.size.width#define kScreenHeight [UIScreen mainScreen].bounds.size.height@interface SecondViewController ()@property (nonatomic, retain) NSMutableArray *dataArray;@end@implementation SecondViewController {    UITableView *_tableView;}- (void)viewDidLoad {    [super viewDidLoad];        [self setupDefaultValue];    [self setupDefaultView];    [self request];}- (void)setupDefaultValue {    _dataArray = [NSMutableArray array];}- (void)setupDefaultView {    _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight) style:UITableViewStylePlain];    _tableView.delegate = self;    _tableView.dataSource = self;    [self.view addSubview:_tableView];}- (void)request {    NSString *urlString = @"http://beautifulword.sinaapp.com/results.php";    NSURL *url = [NSURL URLWithString:urlString];        ASIFormDataRequest *_request = [ASIFormDataRequest requestWithURL:url];    __weak ASIFormDataRequest *request = _request;        [request setCompletionBlock:^{        NSData *data = request.responseData;        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];        self.dataArray = [dict objectForKey:@"Profile"];        [_tableView reloadData];    }];    [request setFailedBlock:^{        NSLog(@"failed");    }];        [request startAsynchronous];}#pragma mark- UITableView Delegate- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    return self.dataArray.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *cellID = @"cell";    UserCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];    if (cell == nil) {        cell = [[UserCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];    }    cell.model = self.dataArray[indexPath.row];    return cell;}- (void)setDataArray:(NSMutableArray *)dataArray {    for (NSDictionary *itemDict in dataArray) {        UserModel *model = [[UserModel alloc] init];        for (NSString *key in itemDict) {            [model setValue:itemDict[key] forKey:key];        }        [_dataArray  addObject:model];    }}@end

OK,整个介绍到此为止,关于MVC的理论知识,还请自行百度 。

示例的源码地址:MVCTest on github


0 0
原创粉丝点击