篇头
很久以前看到一个故事,大概就是一位程序员编程
第一年写程序是 print(“hello,world”);
第二年 try{print(“hello,world”); } catch{}
第五年 封装了成了一个XXprint的类,写了多以的方法
第十年 回到了print(“hello,world”);
简单点的说,我们从学会代码的实现,到学会断言抓异常,到学会优化,最后看到了本质。有点像山里的和尚,小和尚,和尚,老和尚,僧生。
一、项目文件中的规范及内容
1、以Controller文件为例(直接贴代码)
#import "DetailViewController.h"
#import "TestModel.h"
#import "PopView.h"
#import "TestCell.h"
//----->扩展的类
@interface UDDHeadView : UIView
@property (nonatomic,strong) UIImageView *iconImageView;
@property (nonatomic,strong) UILabel *titleLabel;
@property (nonatomic,strong) UIControl *control;
@end
@implementation UDDHeadView
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
_iconImageView = [[UIImageView alloc]init];
_iconImageView.contentMode = UIViewContentModeScaleToFill;
_iconImageView.clipsToBounds = YES;
[self addSubview:_iconImageView];
_titleLabel = [[UILabel alloc]init];
_titleLabel.font = [UIFont systemFontOfSize:14];
_titleLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:_titleLabel];
_control = [[UIControl alloc]init];
[self addSubview:_control];
}
return self;
}
@end
@interface DetailViewController ()<UITableViewDelegate,UITableViewDataSource,PopViewDelegate>
@property (nonatomic,strong) UILabel *titleLabel;
@property (nonatomic,strong) UILabel *contentLabel;
@property (nonatomic,strong) UITableView *tableView;
@property (nonatomic,strong) NSMutableArray *dataSource;
@property (nonatomic,strong) PopView *popView;
@end
@implementation DetailViewController
//----->这个地方放懒加载
- (UILabel *)titleLabel{
if (!_titleLabel) {
_titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 100,[UIScreen mainScreen].bounds.size.width,40)];
}
return _titleLabel;
}
- (PopView *)popView{
if (_popView) {
_popView = [[PopView alloc]initWithFrame:self.view.bounds];
_popView.delegate = self;
}
return _popView;
}
//------>这个是数据初始化
- (id)init{
self = [super init];
if (self) {
_dataSource = [[NSMutableArray alloc]init];
}
return self;
}
//------>固定视图的初始化
- (void)loadView{
[super loadView];
[self initView];
}
- (void)initView{
self.title = @"详情页面";
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.titleLabel];
_contentLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 160,[UIScreen mainScreen].bounds.size.width,40)];
[self.view addSubview:_contentLabel];
self.edgesForExtendedLayout = UIRectEdgeNone;
self.view.backgroundColor = [UIColor whiteColor];
_tableView = [[UITableView alloc]initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
[_tableView registerClass:[TestCell class] forCellReuseIdentifier:@"testCellId"];
_tableView.dataSource = self;
_tableView.delegate = self;
[self.view addSubview:_tableView];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"地图" style:UIBarButtonItemStylePlain target:self action:@selector(mapView)];
}
//------>就近原则,放试图或者navbar的点击方法
-(void)mapView{
NSLog(@"-----地图------");
}
//------> 放系统的的协议代理方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
TestCell *cell = [tableView dequeueReusableCellWithIdentifier:@"testCellId" forIndexPath:indexPath];
if (indexPath.row < [_dataSource count]) {
cell.model = [_dataSource objectAtIndex:indexPath.row];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return [TestCell heighforTestCell];
}
//------> 放自定义的代理方法
//手机号的监听
- (void)popView:(PopView *)view changeValue:(NSString *)phoneTextFiled{
}
//验证码的监听
- (void)popView:(PopView *)view valiteCodechange:(NSString *)valiteCode{
}
//点击按钮
- (void)popView:(PopView *)view didClickButton:(kClickType)clickType{
}
//------> 动态试图的加载以及网络请求等(耗时操作)
- (void)viewDidLoad {
[super viewDidLoad];
_titleLabel.text = _model.title;
_contentLabel.text = _model.valueString;
[self.popView show];
}
//------> 剩下用到的生命周期
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
这里面会包含一些比较基础的地方。
比如在初始化的时候用new 还是用alloc init,这里简单讲下,new 一般就是创建一个内存片段,然后把这个指针指向这个内存片段,但是alloc init 呢,需要先根据就近原则创建一块内存,然后将这个对象初始化了一下,然后指向那个对象。这里主要有两点,一是内存就近,二是拆分,alloc init 是先创建内存,再初始化。
什么情况下使用lazy load ,这里也做简单的解释。
首先我们做懒加载一个是内存相邻,但是这个优化极其细微。
其二,这个对象有可能不需要创建,就像某个点击某个button 出现一个view ,但是这个view 有可能不出现,不被创建。
其三,重复点击的效果,某个自定义的alert 弹框,我们点击之后出现,然后消失了,再点击又出现了。省去不必要的重复创建某个对象。
再解释下为什么在loadView中创建视图
这个就比较基础,特别了解生命周期的同学都知道loadview是在试图开始加载的时候允许的,那loaddidview呢,这个其实是在nib开始加载的时候运行的,是在loadview之后的。所以我们会在loadView里面创建去初始化一些固定试图,在viewdidload 里面去做逻辑操作。
其他就不一一叙述,每个生命周期里面都有对应的方法。
二、自定义的view 类
typedef enum {
kClickCancleType = 0,//取消
kClickConfirmTyoe = 1,//确定
kClickValiteCodeType = 2,// 获取验证码
}kClickType;
#import <UIKit/UIKit.h>
@protocol PopViewDelegate;
@interface PopView : UIView
@property (nonatomic,strong) UITextField *phoneFiled;
@property (nonatomic,strong) UITextField *valitedCode;
//验证码view
@property (nonatomic,strong) UIView *valiteView;
@property (nonatomic,strong) NSString *title;
@property (nonatomic)id <PopViewDelegate>delegate;
- (void)show;
- (void)dismiss;
@end
@protocol PopViewDelegate<NSObject>
//手机号的监听
- (void)popView:(PopView *)view changeValue:(NSString *)phoneTextFiled;
//验证码的监听
- (void)popView:(PopView *)view valiteCodechange:(NSString *)valiteCode;
//点击按钮
- (void)popView:(PopView *)view didClickButton:(kClickType)clickType;
@end
这里的是一个自定义的弹框。有时候,如何在block和代理里面选择,这也是一个值得思考的问题。代理更偏向于对群体点击事件的一个代理,可以在Controller文件中操作。
block 一个用于点击某button吗,然后将view 中的数据回调回去,而代理更偏向于点击view 里面某个button ,然后告诉代理点击的是那个button 。这里,我把控件全部暴露在.h文件中。可以,实现点击和回调的结合,其实还有是一个字,懒,这个其实是不好的习惯,我们应该在.h文件中展示更少的东西。
还有一个问题就是在预加载文件中写入 你的枚举类型,规范方法。当然如果你要写成轮子的话,就需要写在.h文件中了。
#import "PopView.h"
#import "AppDelegate.h"
#define kAppDelegate (AppDelegate*)[UIApplication sharedApplication].delegate
#define WEAKSELF typeof(self) __weak weakSelf = self;
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
@interface PopView ()
@property (nonatomic,strong)UIView *bgView;
@property (nonatomic,strong)UIView *pushView;
@property (nonatomic,strong,readonly) UILabel *titleLabel;
@property (nonatomic,strong) UIButton *cancleButton;
@property (nonatomic,strong) UIButton *confirmButton;
@property (nonatomic,strong) UIButton *receiveCheckNumButton;
@end
@implementation PopView
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
_bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
UIControl *control = [[UIControl alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
[_bgView addSubview:control];
[control addTarget:self action:@selector(clickScreen) forControlEvents:UIControlEventTouchUpInside];
_bgView.alpha = 0.0;
_bgView.backgroundColor = [UIColor blackColor];
[self addSubview:_bgView];
_pushView = [[UIView alloc]initWithFrame:CGRectMake(50,SCREEN_HEIGHT,SCREEN_WIDTH-100,130)];
_pushView.backgroundColor = [UIColor whiteColor];
_pushView.layer.cornerRadius = 8;
_pushView.layer.masksToBounds = YES;
[self addSubview:_pushView];
_titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, SCREEN_WIDTH-100, 20)];
_titleLabel.font = [UIFont systemFontOfSize:15.f];
[_pushView addSubview:_titleLabel];
_titleLabel.textAlignment = NSTextAlignmentCenter;
_cancleButton = [[UIButton alloc]init];
[_cancleButton setTitle:@"取消" forState:UIControlStateNormal];
_cancleButton.titleLabel.font = [UIFont systemFontOfSize:14.f];
[_cancleButton addTarget:self action:@selector(actionButton:) forControlEvents:UIControlEventTouchUpInside];
[_cancleButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_pushView addSubview:_cancleButton];
_confirmButton = [[UIButton alloc]init];
[_confirmButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_confirmButton setTitle:@"确认" forState:UIControlStateNormal];
_confirmButton.titleLabel.font = [UIFont systemFontOfSize:14.f];
[_confirmButton addTarget:self action:@selector(actionButton:) forControlEvents:UIControlEventTouchUpInside];
[_pushView addSubview:_confirmButton];
UIView *line = [[UIView alloc]initWithFrame:CGRectMake(0,CGRectGetHeight(_pushView.frame)-40, CGRectGetWidth(_pushView.frame), 1)];
line.backgroundColor = [UIColor groupTableViewBackgroundColor];
[_pushView addSubview:line];
UIView *line1 = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetWidth(_pushView.frame)/2,CGRectGetHeight(_pushView.frame)-40,1, 40)];
line1.backgroundColor = [UIColor groupTableViewBackgroundColor];
[_pushView addSubview:line1];
_phoneFiled = [[UITextField alloc]initWithFrame:CGRectMake(20,_titleLabel.frame.origin.y+CGRectGetHeight(_titleLabel.frame),CGRectGetWidth(_pushView.frame)-20,30)];
_phoneFiled.placeholder = @"请输入手机号";
_phoneFiled.font = [UIFont systemFontOfSize:14.f];
_phoneFiled.keyboardType = UIKeyboardTypeNumberPad;
[_phoneFiled addTarget:self action:@selector(valueChange:) forControlEvents:UIControlEventEditingChanged ];
[_pushView addSubview:_phoneFiled];
_valiteView = [[UIView alloc]initWithFrame:CGRectMake(0,_phoneFiled.frame.origin.y+CGRectGetHeight(_phoneFiled.frame),CGRectGetWidth(_pushView.frame),30)];
[_pushView addSubview:_valiteView];
_valitedCode = [[UITextField alloc]initWithFrame:CGRectMake(20,0,60,30)];
_valitedCode.placeholder = @"验证码";
_valitedCode.font = [UIFont systemFontOfSize:14.f];
_valitedCode.keyboardType = UIKeyboardTypeNumberPad;
[_valitedCode addTarget:self action:@selector(ValiteCode:) forControlEvents:UIControlEventEditingChanged];
[_valiteView addSubview:_valitedCode];
self.receiveCheckNumButton = [[UIButton alloc]initWithFrame:CGRectMake(100,0,80, 30)];
[self.receiveCheckNumButton addTarget:self action:@selector(receiveCheckNum) forControlEvents:UIControlEventTouchUpInside];
[_receiveCheckNumButton setTitle:@"获取验证码" forState:UIControlStateNormal];
[_receiveCheckNumButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.receiveCheckNumButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentRight];
self.receiveCheckNumButton.titleLabel.font = [UIFont systemFontOfSize:15];
[_valiteView addSubview:self.receiveCheckNumButton];
}
return self;
}
- (void)layoutSubviews{
[super layoutSubviews];
_cancleButton.frame = CGRectMake(0,CGRectGetHeight(_pushView.frame)-40,CGRectGetWidth(_pushView.frame)/2,40);
_confirmButton.frame = CGRectMake(CGRectGetWidth(_pushView.frame)/2,CGRectGetHeight(_pushView.frame)-40,CGRectGetWidth(_pushView.frame)/2,40);
}
- (void)valueChange:(UITextField *)textFiled{
if ([_delegate respondsToSelector:@selector(popView:changeValue:)]) {
[_delegate popView:self changeValue:textFiled.text];
}
if (textFiled.text.length > 11) {
textFiled.text = [textFiled.text substringToIndex:11];
}
}
- (void)ValiteCode:(UITextField *)textFiled{
if ([_delegate respondsToSelector:@selector(popView:valiteCodechange:)]) {
[_delegate popView:self valiteCodechange:textFiled.text];
}
}
- (void)setTitle:(NSString *)title{
if (_title !=title ) {
_title = title;
}
_titleLabel.text =_title;
}
- (void)show{
self.frame = [kAppDelegate window].bounds;
[[kAppDelegate window] addSubview:self];
WEAKSELF
[UIView animateWithDuration:0.25 animations:^{
weakSelf.pushView.frame = CGRectMake(0, 0, SCREEN_WIDTH-100,130);
weakSelf.pushView.center = self.center;
weakSelf.bgView.alpha = 0.5f;
}];
}
- (void)dismiss{
WEAKSELF
[UIView animateWithDuration:0.25 animations:^{
weakSelf.bgView.alpha = 0.0;
weakSelf.pushView.frame =CGRectMake(50,SCREEN_HEIGHT,SCREEN_WIDTH-100,130);
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}
- (void)clickScreen{
[self dismiss];
}
//获取验证码倒计时
- (void)receiveCheckNum{
if ([_delegate respondsToSelector:@selector(popView:didClickButton:)]) {
[_delegate popView:self didClickButton:2];
}
__block int timeout=60; //倒计时时间
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
dispatch_source_set_event_handler(_timer, ^{
if(timeout<=0){ //倒计时结束,关闭
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示 根据自己需求设置
[self.receiveCheckNumButton setTitle:@"重新获取" forState:UIControlStateNormal];
self.receiveCheckNumButton.userInteractionEnabled = YES;
});
}else{
int seconds = timeout;
NSString *strTime = [NSString stringWithFormat:@"%.2d", seconds];
dispatch_async(dispatch_get_main_queue(), ^{
//让按钮变为不可点击的灰色
self.receiveCheckNumButton.userInteractionEnabled = NO;
//设置界面的按钮显示 根据自己需求设置
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[self.receiveCheckNumButton setTitle:[NSString stringWithFormat:@"%@秒后重发",strTime] forState:UIControlStateNormal];
[UIView commitAnimations];
});
timeout--;
}
});
dispatch_resume(_timer);
}
- (void)actionButton:(UIButton *)button{
if (button == _cancleButton) {
if ([_delegate respondsToSelector:@selector(popView:didClickButton:)]) {
[_delegate popView:self didClickButton:0];
}
}else{
if ([_delegate respondsToSelector:@selector(popView:didClickButton:)]) {
[_delegate popView:self didClickButton:1];
}
}
}
@end
这里没有使用 masonry 是因为还是有很多项目中没有使用masonry 的。