ViewController代码拆分实践

日常里的异常,人生至乐!

如果你才刚刚接触iOS开发,可以先看看我写的另一篇文章《从零开始学iOS开发的15条建议》http://www.jianshu.com/p/8472ba0f2bb6

首先,创建一个Single View Application。


Single View Application

接着,找来一个数据API,这里以V2EX的公开API为例:
https://www.v2ex.com/p/7v9TEc53

我们只拿其中一个API:首页右侧的 10 大每天的内容。
https://www.v2ex.com/api/topics/hot.json

AppDelegate.m

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];

    ViewController *viewController = [[ViewController alloc] init];
    UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:viewController];
    self.window.rootViewController = navigationController;

    [self.window makeKeyAndVisible];

    return YES;
}

ViewController.m

@interface ViewController ()<NSURLConnectionDataDelegate,UITableViewDataSource,UITableViewDelegate>

@property (nonatomic, strong) NSMutableData *receiveData;
@property (nonatomic, strong) NSArray *hotList;

@property (nonatomic, strong) UITableView *tableView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.hotList = [NSKeyedUnarchiver unarchiveObjectWithFile:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@".hotListArchiver"]];
    [self.tableView reloadData];

    self.receiveData = [[NSMutableData alloc]init];
    NSURL *url = [[NSURL alloc]initWithString:@"https://www.v2ex.com/api/topics/hot.json"];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    
    CGRect frame = [[UIScreen mainScreen]bounds];
    self.tableView = [[UITableView alloc]initWithFrame:frame];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    [self.view addSubview:self.tableView];
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"cellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
    }
    
    cell.textLabel.text = self.hotList[indexPath.row][@"title"];
    cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http:%@",self.hotList[indexPath.row][@"member"][@"avatar_mini"]]]]];
    return cell;
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.receiveData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSError *error = nil;
    self.hotList = [NSJSONSerialization JSONObjectWithData:self.receiveData options:NSJSONReadingAllowFragments error:&error];
    [self.tableView reloadData];

    NSLog(@"hotList\n%@",self.hotList);
    [NSKeyedArchiver archiveRootObject:self.hotList toFile:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@".hotListArchiver"]];
}

DetailViewController.h

@interface DetailViewController : UIViewController

@property (nonatomic, strong) NSDictionary *detailData;
@end

DetailViewController.m

@implementation DetailViewController

-(void)viewDidLoad
{
    self.title = self.detailData[@"title"];
}

@end

代码运行效果:


ViewController
DetailViewController

下面,我们开始拆。

首先,创建接口 Interface。

创建接口 Interface

然后,创建相应的类。

创建相应的类

把代码移到相应的类里:
ViewController.h

@interface ViewController : UIViewController

@property (nonatomic, weak) id<ViewInterface> viewModel;
@property (nonatomic, weak) id<APIInterface> apiHandle;
@property (nonatomic, weak) id<StoreInterface> storeHandle;
@property (nonatomic, weak) id<RouteInterface> routeHandle;
@end

ViewController.m

@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>

@property (nonatomic, strong) NSMutableData *receiveData;
@property (nonatomic, strong) NSArray *hotList;

@property (nonatomic, strong) UITableView *tableView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initUI];
    self.hotList = [self.storeHandle unarchive];
    [self tableViewReloadData];
    [self.apiHandle loadData];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

-(void)initUI
{
    self.title = @"最热10条";
    CGRect frame = [[UIScreen mainScreen]bounds];
    self.tableView = [[UITableView alloc]initWithFrame:frame];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    [self.view addSubview:self.tableView];
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"cellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
    }
    NSDictionary * data =self.hotList[indexPath.row];
    
    return [self.viewModel configureWithCell:cell data:data];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *detailData = self.hotList[indexPath.row];
    [self.routeHandle pushDetailInterfaceFromViewController:self detailData:detailData];
}

- (void)tableViewReloadData
{
    [self.tableView reloadData];
}

- (void)hotListWtihData:(NSArray *)data
{
    self.hotList = data;
    
    [self tableViewReloadData];
    [self.storeHandle archiveWithObject:self.hotList];
}
@end

ViewModel.m

@implementation ViewModel

- (UITableViewCell *)configureWithCell:(UITableViewCell *)cell data:(NSDictionary *)data
{
    cell.textLabel.text = data[@"title"];
    cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http:%@",data[@"member"][@"avatar_mini"]]]]];
    return cell;
}
@end

APIHandle.h

@interface APIHandle : NSObject<APIInterface>
@property (nonatomic, weak) id<ViewInterface> viewModel;
@end

APIHandle.m

@interface APIHandle()<NSURLConnectionDataDelegate>

@property (nonatomic, strong) NSMutableData *receiveData;
@end

@implementation APIHandle

- (void)loadData
{
    self.receiveData = [[NSMutableData alloc]init];
    NSURL *url = [[NSURL alloc]initWithString:@"https://www.v2ex.com/api/topics/hot.json"];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.receiveData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSError *error = nil;
    id data = [NSJSONSerialization JSONObjectWithData:self.receiveData options:NSJSONReadingAllowFragments error:&error];
    NSLog(@"data\n%@",data);
    
    [self.viewModel hotListWtihData:data];
}
@end

StoreHandle.m

@implementation StoreHandle

- (id)unarchive
{
    return [NSKeyedUnarchiver unarchiveObjectWithFile:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@".hotListArchiver"]];
}

- (void)archiveWithObject:(id)object
{
    [NSKeyedArchiver archiveRootObject:object toFile:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@".hotListArchiver"]];
}
@end

RouteHandle.m

#import "DetailViewController.h"

@implementation RouteHandle

- (void)pushDetailInterfaceFromViewController:(UIViewController *)viewController detailData:(NSDictionary *)detailData
{
    DetailViewController *detailViewController = [[DetailViewController alloc]init];
    detailViewController.detailData = detailData;
    [viewController.navigationController pushViewController:detailViewController animated:YES];
}
@end

AppDelegate.m

#import "ViewModel.h"
#import "APIHandle.h"
#import "StoreHandle.h"
#import "RouteHandle.h"

@interface AppDelegate ()
@property (nonatomic, strong) ViewModel *viewModel;
@property (nonatomic, strong) APIHandle *apiHandle;
@property (nonatomic, strong) StoreHandle *storeHandle;
@property (nonatomic, strong) RouteHandle *routeHandle;
@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];
    
    ViewController *viewController = [[ViewController alloc] init];
    viewController.viewModel = self.viewModel;
    self.apiHandle.viewModel = viewController;
    viewController.apiHandle = self.apiHandle;
    viewController.storeHandle = self.storeHandle;
    viewController.routeHandle = self.routeHandle;
    
    UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:viewController];
    self.window.rootViewController = navigationController;
    
    [self.window makeKeyAndVisible];

    return YES;
}

- (ViewModel *)viewModel
{
    if(!_viewModel)
    {
        _viewModel= [[ViewModel alloc] init];
    }
    return _viewModel;
}

- (APIHandle *)apiHandle
{
    if(!_apiHandle)
    {
        _apiHandle= [[APIHandle alloc] init];
    }
    return _apiHandle;
}

- (StoreHandle *)storeHandle
{
    if(!_storeHandle)
    {
        _storeHandle= [[StoreHandle alloc] init];
    }
    return _storeHandle;
}

- (RouteHandle *)routeHandle
{
    if(!_routeHandle)
    {
        _routeHandle= [[RouteHandle alloc] init];
    }
    return _routeHandle;
}

后记(下面以聊家常为主,没时间没兴趣的朋友请直接忽略):

在日常中积累越多的人,生活越感无聊,虽然在外人看来顺风顺水。
在异常中辛苦存活的人,生活快感无比,虽然在外人看来非常凶险。
人活一辈子,究竟为了什么呢?:)终究难逃一死啊。或快又或慢。
这是一个非常有意思的问题。有意思的根本在于这一个问题的残酷。
因为,追问之下,多数人都只能回答:我一直不知道!!!!!!!
不要那么笃定啊!不要逃避不确定性啊!人生摇摆中存活才会有趣!

我一直以为,我需要异常来让自己觉得自己是生物而不是死物。
但,真正的异常在哪里呢?最大的异常在哪里呢?
最大的异常,在日常里。
让日常变得异常。
日常非常美丽。整整齐齐,稳稳当当。
如果,日常可以异化,异化成另一种整整齐齐、稳稳当当,那就太好玩了。
如果,可以让这个世界异化成另一种日常。让人们习惯异化,就太好玩了。

寻找日常里的可异化的点,用尽一生去把它异化成日常,那就会太好玩了。

这次找到了一个点:)
递减:)

长久以来,我们被教导要去追求多样性,要丰富。
这是最大的陷阱。
因为,我们会被个体的多样性削弱群体的多样性。
相反,如果我们能回归个人的单一性却可以创造出最广泛的群体多样性。

所以,我们要放弃扩张,而是尽自己一切的努力去收缩。
把触角收缩到以自我为中心的极致小的那个点。
那个,除了自己,任何人都不可能有的点。
当,我们都能找到自己的点,这个世界就有70个点。
相反,看看我们身边的这个世界,不停地扩张、积累,最好大家都在吃一样的食物,穿一样的衣服,看一样的娱乐,过一样的人生。
看似极大丰富,实则是极尽无聊。

不外寻,只自问。
通过永不停止的递减,以退为进,找到自己那唯一的点。
不要再被这个世界繁杂所拖累了。

回归本心,重新出发。

深挖日常!向日常深处进军!

日常深处有无尽的独一异常!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容