[iOS]将DataSource分离并构建更轻量的UIViewController

在objccn.io中看到一篇文章,构建更轻量的View Controllers,在此自己实践一下加深理解。

新疆项目,learn--tableview,类前缀为LT,开始我们的实验。

首先需要在StoryBoard中拖拽一个UITableView,在头文件中申明tableView变量并建立连接:

新建ArrayDataSource类,作为TableView的DataSource。目的是将DataSource从原本的ViewController中分离出来:

//
//  ArrayDataSource.h
//  objc.io example project (issue #1)
//

#import <Foundation/Foundation.h>

typedef void (^TableViewCellConfigureBlock)(id cell, id item);

@interface ArrayDataSource : NSObject <UITableViewDataSource>

- (id)initWithItems:(NSArray *)anItems
     cellIdentifier:(NSString *)aCellIdentifier
 configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock;

- (id)itemAtIndexPath:(NSIndexPath *)indexPath;

@end

//
//  ArrayDataSource.h
//  objc.io example project (issue #1)
//

#import "ArrayDataSource.h"

@interface ArrayDataSource ()

@property (nonatomic, strong) NSArray *items;
@property (nonatomic, copy) NSString *cellIdentifier;
@property (nonatomic, copy) TableViewCellConfigureBlock configureCellBlock;

@end

@implementation ArrayDataSource

- (id)init
{
    return nil;
}

- (id)initWithItems:(NSArray *)anItems
     cellIdentifier:(NSString *)aCellIdentifier
 configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock
{
    self = [super init];
    if (self) {
        self.items = anItems;
        self.cellIdentifier = aCellIdentifier;
        self.configureCellBlock = [aConfigureCellBlock copy];
    }
    return self;
}

- (id)itemAtIndexPath:(NSIndexPath *)indexPath
{
    return self.items[(NSUInteger) indexPath.row];
}

#pragma mark UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.items.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier
                                                            forIndexPath:indexPath];
    id item = [self itemAtIndexPath:indexPath];
    self.configureCellBlock(cell, item);
    return cell;
}

@end

可以看得出来,这个DataSource的管理类接受三个变量进行初始化,分别是:

1.anItems,存储表格数据的对象,是一个NSArray,里面存储封装好的对象,我们并不知道它是什么类型的,所以在使用的时候用id取出其中的元素。

2.cellIdentifier,单元格的标示符,用来指定TableView使用的单元格,是单元格的唯一标识,在创建和设计Cell的时候可以指定。

3.configureCellBlock,一个用来设置每个单元格的block,因为具体的item格式我们并不知道,所以我们也就不知道该如何初始化一个cell里面的数据,需要用block进行设置,因为这个block的目的是为了将item的数据应用到cell上,所以block接受两个参数,cell和item。

接下来在添加一个LTMyCell类,作为自定义的单元格类。在xib中添加两个label用来显示数据:

将xib中的两个label与.h头文件建立连接,连接后的头文件如下:

+ (UINib *)nib;

@property (weak, nonatomic) IBOutlet UILabel *photoTitleLabel;
@property (weak, nonatomic) IBOutlet UILabel *photoDateLabel;

修改.m文件,实现相关方法如下:

+ (UINib *)nib
{
    return [UINib nibWithNibName:@"PhotoCell" bundle:nil];
}

- (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;
    }
}

接着,新建LTPhoto的封装类,我们需要把用来展示的数据进行分装:

//
//  LTPhoto.h
//  learn-tableview
//
//  Created by why on 8/11/14.
//  Copyright (c) 2014 why. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface LTPhoto : NSObject <NSCoding>

@property (nonatomic, copy) NSString* name;
@property (nonatomic, strong) NSDate* creationDate;

@end

//
//  LTPhoto.m
//  learn-tableview
//
//  Created by why on 8/11/14.
//  Copyright (c) 2014 why. All rights reserved.
//

#import "LTPhoto.h"

static NSString * const IdentifierKey = @"identifier";
static NSString * const NameKey = @"name";
static NSString * const CreationDateKey = @"creationDate";
static NSString * const RatingKey = @"rating";

@implementation LTPhoto

- (void)encodeWithCoder:(NSCoder*)coder
{
    [coder encodeObject:self.name forKey:NameKey];
    [coder encodeObject:self.creationDate forKey:CreationDateKey];
}

- (BOOL)requiresSecureCoding
{
    return YES;
}

- (id)initWithCoder:(NSCoder*)coder
{
    self = [super init];
    if (self) {
        self.name = [coder decodeObjectOfClass:[NSString class] forKey:NameKey];
        self.creationDate = [coder decodeObjectOfClass:[NSDate class] forKey:CreationDateKey];
    }
    return self;
}

@end

在写完了LTPhoto这个封装对象之后,我们可以对原来的MyCell进行Category扩展。新建一个Category:

具体代码如下:

#import "LTMyCell.h"

@class LTPhoto;

@interface LTMyCell (ConfigureForPhoto)
- (void)configureForPhoto:(LTPhoto *)photo;

@end

//
//  LTMyCell+ConfigureForPhoto.m
//  learn-tableview
//
//  Created by why on 8/11/14.
//  Copyright (c) 2014 why. All rights reserved.
//

#import "LTMyCell+ConfigureForPhoto.h"
#import "LTPhoto.h"

@implementation LTMyCell (ConfigureForPhoto)

- (void)configureForPhoto:(LTPhoto *)photo
{
    self.photoTitleLabel.text = photo.name;
    self.photoDateLabel.text = [self.dateFormatter stringFromDate:photo.creationDate];
}

- (NSDateFormatter *)dateFormatter
{
    static NSDateFormatter *dateFormatter;
    if (!dateFormatter) {
        dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.timeStyle = NSDateFormatterMediumStyle;
        dateFormatter.dateStyle = NSDateFormatterMediumStyle;
    }
    return dateFormatter;
}

@end

接下来就是在ViewController中指定TableView的DataSource。修改m文件代码如下:

//
//  LTViewController.m
//  learn-tableview
//
//  Created by why on 8/11/14.
//  Copyright (c) 2014 why. All rights reserved.
//

#import "LTViewController.h"
#import "ArrayDataSource.h"
#import "LTMyCell.h"
#import "LTMyCell+ConfigureForPhoto.h"
#import "LTPhoto.h"

static NSString * const PhotoCellIdentifier = @"LTMyCell";

@interface LTViewController ()<UITableViewDelegate>

@property (nonatomic, strong) ArrayDataSource *photosArrayDataSource;

@end

@implementation LTViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    [self setupTableView];

}

- (void)setupTableView
{

    TableViewCellConfigureBlock configureCell = ^(LTMyCell *cell, LTPhoto *photo) {
        [cell configureForPhoto:photo];
    };

    NSMutableArray *photos = [[NSMutableArray alloc] init];
    for (int i = 0; i < 10; i++) {
        LTPhoto *photo = [[LTPhoto alloc] init];
        photo.name = @"Hello";
        photo.creationDate = [NSDate date];
        [photos addObject:photo];
    }

    self.photosArrayDataSource = [[ArrayDataSource alloc] initWithItems:photos
                                                         cellIdentifier:PhotoCellIdentifier
                                                     configureCellBlock:configureCell];

    _tableVIew.dataSource = self.photosArrayDataSource;

    [_tableVIew registerNib:[LTMyCell nib] forCellReuseIdentifier:PhotoCellIdentifier];

}

#pragma mark UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"Click!");
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

这样就实现了基本的DataSource分离。

项目源码地址:learn-tableview

[iOS]将DataSource分离并构建更轻量的UIViewController

时间: 2024-10-06 06:01:49

[iOS]将DataSource分离并构建更轻量的UIViewController的相关文章

更轻量的 View Controllers

View controllers 通常是 iOS 项目中最大的文件,因为它们包含了许多不必要的代码.所以 View controllers 中的代码几乎总是复用率最低的.我们将会看到给 view controllers 瘦身的技术,让代码变得可以复用,以及把代码移动到更合适的地方. http://tang3w.com/translate/objective-c/objc.io/2013/10/22/%E6%9B%B4%E8%BD%BB%E9%87%8F%E7%9A%84-view-control

不用webservice wcf提供服务,用Rest更轻量

从2005年开始就开始有基于服务的开发方式,到08年时候 微软和sun等公司都已经提供了很多基于服务的开发框架 . 微软 .net 平台的基于服务的框架主要有:.NET Remoting.webservice.重量级的WCF 等框架. 随着互联网技术的发展Asp.net webForm 逐渐被Asp.net MVC 替换. 相信在互联网服务开发方向想Asp.net MVC WEB API 这种轻量级的基于Rest风格的服务框架应该也会逐渐替代WCF.不是WCF框架不好,而且太好了,内置的东西很多

比Wireshark更轻量、更方便的抓包软件:Charles

转:http://blog.csdn.net/lixing333/article/details/42776187 之前写过一篇通过Wireshark进行抓包,分析网络连接的文章<通过WireShark抓取iOS联网数据实例分析>:http://blog.csdn.net/lixing333/article/details/7782539 最近一些工作需要抓包,在我的Mac上安装了Wireshark之后,发现运行不了.探究之,发现Wireshark的界面用的是X Window,所以需要在X11

一张表格的协作工具:你还能找到更轻量的吗?

关于协作工具.团队项目管理软件.企业协作平台等标签"协作"的东西,有个共同的障碍.就是须要或复杂或简单的"设置". 比如,创建全部团队成员账号.建立组织.创建组织结构.分配权限. 中国传统管理软件有个如今看来值得怀疑的的特点,就是须要复杂的组织结构和权限分配.包含公司.树状部门结构.岗位.角色.员工. 然后对每一个部分.岗位.角色.员工授权各个模块功能. 看似非常有逻辑.非常严谨.可是,这就是国内信息化系统难以实施的原因之中的一个:太麻烦啦.按现代的评价风格就是.用

更轻更快的Vue.js 2.0与其他框架对比(转)

更轻更快的Vue.js 2.0 崭露头角的JavaScript框架Vue.js 2.0版本已经发布,在狂热的JavaScript世界里带来了让人耳目一新的变化. Vue创建者尤雨溪称,Vue 2.0 在性能上有显著的提升,同时保持轻量的文件下载: 渲染层基于一个轻量级的Virtual DOM实现进行了重写,该Virtual DOM实现fork自snabbdom.新的渲染层相比v1带来了巨大的性能提升,也让Vue 2.0成为了最快速的框架之一. 根据1.0到2.0迁移指南,“大约90%的API是相

分离是为了更好的结合

分离是为了更好的结合 写出高质量软件是困难和复杂的:不仅仅是为了满足需求,还应该是健壮的,可维护的,可测试的,并且足够灵活以适应成长和变化.这就是洋葱架构出现的原因,它代表一组优秀的开发实践,用来开发任何的软件应用都是一个不错的方式. 洋葱架构,也成为整洁架构(The Clean Architecture),用来构建具有如下特点的系统: 1.    独立的Frameworks 2.    可测试 3.    独立的UI 4.    独立的数据库 5.    独立的任意外部服务(代理) 看到这张图

Actor_更轻量化的并发处理模型

JAVA在JDK5之前写并发程序是非常麻烦的,你要么继承Thread类,要么实现Runnable接口,同步机制的力粒度也很粗.JDK5之后,引入了Concurrent包,增加了很多并发特性的支持,如Callable<T>接口,可以使用Future<T>来获取每个任务返回的结果,而原来的Runnable是没有这个能力的.还有就是更细粒度的锁,如Lock接口. Actor Model最早是在上世纪70-80年代就被提出来了,是用来编写并行计算或分布式系统的高层次抽象,让程序员不必为多线

构建更好的客户端 JavaScript 应用

你可能注意到了,最近的一段时间越来越多的Web应用有变复杂的趋势,重心从服务端慢慢向着客户端转移. 这是个正常的趋势么?我不知道.支持和反对者的讨论就像是在讨论复活者和圣诞节哪一个更好一样; 很难说哪一方观点就是完全正确的.因此,本文不会探讨究竟哪一方是对的,不过我还是试图解释一下使用大家所熟知的面向对象编程也许可以成功的解决客户端编程中存在的一些问题. 不太规范的代码的示例 为了顾及一个应用的响应以及用户体验, 导致我们创建了持续增长的复杂的代码, 这些代码变得难于理解和维护. 你可以轻松的想

比容器更轻更快的虚拟机

尽管容器技术在今天越来越被人接受,但是安全性依然是一个绕不开的问题,由于容器采用的是共享内核外加 cgroups 和 namespaces 等黑魔法的方式进行隔离注定了会有很多路径的 bug 导致隔离性问题,安全隐患依然存在.而不使用虚拟机的原因不外乎虚拟机启动太慢,额外开销太高,性能由于多了一层会下降.面对容器和虚拟机这两个极端,容器一方想把容器做的隔离性更好,虚拟化方面想把虚拟机做的更轻.结果, neclab 的一群人居然做到把虚拟机的启动速度做的比 Docker 还快,内存开销比 Dock