这本书相信大家也多多少少看过好多次了.可我自己仅仅也只是看而已.
直到看到别人用设计模式写出优雅的代码,才发现!
这些设计模式,自己都懂....
可是从来就没有把它实际的用到代码中.项目中写的最顺手的还是MVC慢慢的项目变庞大了,或许公司就倒了....
OK,来扯一个实际场景,首先我一个展示一个视图,然后从服务器中请求数据,再把请求下来的数据,填充到视图中展示出来.就这么一个逻辑.
方案一: 经典MVC
1.Model
2.View
3.controller
方案二: MVVM
1.Model
2.View
3.viewModel
4.controller
方案三 工厂模式|组合模式,路由?
1.view {
Cells
view
}
2.controllers
3.EnterRoom
4.privateTools {
ActionTools
FormatTools
ViewTools
}
5.protocol
这一回重点讲述方案三.
View,cells,跟Controller,我就不多扯了大伙都明白.
EnterRoom 负责 跳转控制器举个例子
控制器A想push到控制器B
那么传统的是
UIViewControler *vc = [UIViewController new];
[self.navigationController pushViewController:vc animated:YES];
按照工厂模式,路由跳转
id vc = [MTCollegeEnterRoom viewController];
[self.navigationController pushViewController:vc animated:YES];
有没有觉得好奇?我为什么要单独写一个类来做生成控制器的事情?
好处有如下.
1.在其他控制器中,我跳转不必要导入其他的控制器头文件.
2.在跳转控制时,我不必在写生成控制器的代码.
3.减少类与类之间的耦合,如何非得关联,则加一个中间层. MTCollegeEnterRoom这个就是中间层,曾经读到一段话:没有什么事情是加一个中间层不能解决的,不过不行就再加一个.
设想一下: 工厂 - 全国代理商 -省级区域代理商 - 县级区域代理商 - 专卖店
这个不就是中间层吗?生活中例子随处可见不浪费时间了.
下面来介绍如何生成视图了对不对?
老套路老规矩
MTHeaderView *view = [MTHeaderView headerView];
self.tableView.tableHeaderView = headerView;
按照工厂模式,路由跳转
UIView *headerView = [MTViewFactory collegeMusicHeaderView];
self.tableView.tableHeaderView = headerView;
你瞧是不是很熟悉?很控制器的套路几乎一样,又是套了一个中间层.
这是时候,你估计会想到,既然没有导入头文件,那么我要用点语法怎么办?
难不成继续强转?导入头文件?
NONONO!
如果你需要给属性赋值,可以在外界提供一个Dict或者模型.
利用KVC
[headerView setValue:model forKey:@"model"];
在headerView内部做赋值刷新.
我想你肯定又要问,如果有代理时间怎么办?或者block
按照工厂模式,路由跳转
UIView *headerView = [MTViewFactory collegeMusicHeaderViewDelegate:self];
self.tableView.tableHeaderView = headerView;
在方法内部
举个例子
+ (UIView *) collegeMusicHeaderViewDelegate:(id)delegate{
MTCollegeMusicHeaderView *headerView = [MTCollegeMusicHeaderView mtNew];
headerView.delegate = delegate;
return headerView;
}
block也是同理,在我项目中可以说全局用的delegate,只需要代理方法按照规范去写,我想接盘侠会很舒服的.
下面protocol
个就没有什么好说的了,在.h全部用@class,不直接导类,把每个模块的代理写在单独的一个类里面,用的时候只需要引入protocol 就好了.
介绍这个类了FormatTools
按照单一职责的思想,我们把功能模块全部细致划分.
我还是举个代码例子
先看.h
//
// MTSpectralDetailsFormatter.h
// LoveGuQin
//
// Created by fox on 2018/5/28.
// Copyright © 2018年 Moemoe. All rights reserved.
//
#import
#import "CollegeProtocol.h"
@class MTSpectralDetailsModel;
@interface MTSpectralDetailsFormatter : NSObject
@property(nonatomic,weak)id delegate;
- (instancetype)initWithTableView:(UITableView *)tablewView;
@property(nonatomic,strong)MTSpectralDetailsModel *detailsModel;
@end
再看.m
//
// MTSpectralDetailsFormatter.m
// LoveGuQin
//
// Created by fox on 2018/5/28.
// Copyright © 2018年 Moemoe. All rights reserved.
//
#import "MTSpectralDetailsFormatter.h"
#import "MTViewFactory+College.h"
#import "MTSpectralDetailsCell.h"
#import "MTCollegeEnterRoom.h"
#import "MTSpectralDetailsLoopCell.h"
#import "MTSpectralDetailsModel.h"
@interface MTSpectralDetailsFormatter ()
@property(nonatomic,strong)UITableView *tableView;
@end
@implementation MTSpectralDetailsFormatter
- (instancetype)initWithTableView:(UITableView *)tableView {
if (self = [super init]) {
self.tableView = tableView;
[tableView registerClass:[MTSpectralDetailsCell class] forCellReuseIdentifier:NSStringFromClass([MTSpectralDetailsCell class])];
[tableView registerClass:[MTSpectralDetailsLoopCell class] forCellReuseIdentifier:NSStringFromClass([MTSpectralDetailsLoopCell class])];
}
return self;
}
- (void)setDetailsModel:(MTSpectralDetailsModel *)detailsModel {
_detailsModel = detailsModel;
[_tableView reloadData];
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
if (indexPath.row == 0) {
MTSpectralDetailsCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MTSpectralDetailsCell class]) forIndexPath:indexPath];
cell.titleString = self.detailsModel.data.content;
return cell;
}else {
MTSpectralDetailsLoopCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MTSpectralDetailsLoopCell class]) forIndexPath:indexPath];
cell.dataArray = self.detailsModel.data.scans;
cell.delegate = self.delegate;
return cell;
}
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
#pragma mark - ********* College Delegate *********
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
CGFloat height = [self.detailsModel.data.content sizeForFont:[UIFont systemFontOfSize:15] size:CGSizeMake(kScreenWidth - 48, 0) mode:0].height;
return height;
}else {
return 200;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 0;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return nil;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return nil;
}
@end
发现没有,这个好处不需要我多说了吧.这一项,我已经把tableView的一系列相关代码移到这里来了.
这个时候再去看对应的控制器代码就简洁了..
//
// MTSpectralController.m
// LoveGuQin
//
// Created by fox on 2018/5/26.
// Copyright © 2018年 Moemoe. All rights reserved.
//
#import "MTSpectralController.h"
#import "MTViewFactory+Music.h"
#import "MTSpectralFormatter.h"
#import "MTSpectralRequest.h"
#import "MTSpectralModel.h"
#import "MTCollegeEnterRoom.h"
@interface MTSpectralController ()
@property(nonatomic,strong)UIView *searchView;
@property(nonatomic,strong)UITableView *tableView;
@property(nonatomic,strong)MTSpectralFormatter *formatter;
@property(nonatomic,strong)NSArray *dataArray;
@end
@implementation MTSpectralController
- (void)moeupNavigation {
[self hideNav:YES withAnimation:NO];
[self mtNavTransparent];
}
- (void)moeupSubview {
self.searchView = [MTViewFactory searchVeiw:self withPlaceholdString:@"搜索琴曲" WithStyle:MTNavSearchReturn];
[self.view addSubview:self.searchView];
[self.view addSubview:self.tableView];
}
- (void)moeupData {
MTSpectralRequest *request = [[MTSpectralRequest alloc]init];
request.delegate = self;
[request start];
}
#pragma MARK -- YTKRequestDelegate
- (void)requestFinished:(__kindof YTKBaseRequest *)request {
MTSpectralModel *model = [MTSpectralModel yy_modelWithDictionary:request.responseObject];
if ([model.code integerValue] == 1) {
self.dataArray = model.data;
self.formatter.dataArray = self.dataArray;
}else {
[MBProgressHUD MT_ShowError:model.message];
}
}
- (void)requestFailed:(__kindof YTKBaseRequest *)request {
NSString *error = request.error.localizedDescription;
[MBProgressHUD MT_ShowError:error];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.searchView.frame = CGRectMake(24 *kScale, MT_ASPECT_STATUS_BAR_H + 15, kScreenWidth - 48 *kScale, 44);
self.tableView.frame = CGRectMake(0, self.searchView.bottom + 20 , MT_SCREEN_WIDTH, MT_SCREEN_HEIGHT - self.searchView.bottom - 20);
}
#pragma MARK -- MTMainMusicNavSearchViewDelegate
- (void)musicNavSearchViewTextFieldDidBeginEditing:(UITextField *)textField searchView:(MTMainMusicNavSearchView *)searchView {
[textField resignFirstResponder];
[self.navigationController pushViewController:[MTCollegeEnterRoom searchMainController] animated:YES];
}
- (void)musicNavSearchViewSearchClickReturn {
[self mtPopback];
}
- (UITableView *)tableView{
if (!_tableView) {
_tableView = [[UITableView alloc]initWithFrame:CGRectZero style:UITableViewStyleGrouped];
_tableView.delegate = self.formatter;
_tableView.dataSource = self.formatter;
_tableView.showsVerticalScrollIndicator = NO;
_tableView.showsHorizontalScrollIndicator = NO;
_tableView.backgroundColor = [UIColor whiteColor];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
return _tableView;
}
- (MTSpectralFormatter *)formatter{
if (!_formatter) {
_formatter = [[MTSpectralFormatter alloc]initWithTableView:_tableView];
_formatter.dataArray = self.dataArray;
}
return _formatter;
}
@end
最后一个ActionTools
这个相信就不需要我多讲了吧?
这个自行斟酌,有些可以你写个代理放到控制器.
如果是纯点击跳转,可以独立写个类ActionTools
最后一个提示,cell其实也是可以复用的.比如说cell是容器,但是可以把它里面的东西写成一个XIB或者代码自定义View,这样,你拿View去到处复用,不是很happy?
一个工程都按照如上套路写,工程再大又何妨?
iOS很简单,也很难.入门简单,当知道的越多的时候,越感到无知......
OK.写了一个半个早上.如果对你有用,点个