主要是针对极客学院的通讯录项目,知识点的整理...点击-> 下载代码
1,实现登陆和密码输入框为空时,为不可用状态
实现方案:使用添加观察者的方式来实现,在viewDidLoad事件当中添加观察者,来监听nameField和pwdField文本框内容发生改变的事件,内容改变后触发当前类的textChange事件
- (void)viewDidLoad { [super viewDidLoad];//添加观察者 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.nameField]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.pwdField]; }
--->textChange方法
- (void)textChange{ //修改按钮的点击状态 self.loginBtn.enabled = (self.nameField.text.length && self.pwdField.text.length); }
2,实现页面之间的转跳
自storyboard出来后苹果公司一直很推荐使用storyboard来实现项目,所以prepareForSegue这个方法一直存在于每一个视图控制器当中。
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
这个方法的意思就是跳转之前的准备工作,参数是UIStoryboardSegue,UIStoryboardSegue内有三个属性,1:是identifier(标识),2:sourceViewController(原控制器),3:destinationViewController(目标控制器)
//登陆 - (IBAction)loginAction { //点击后执行跳转,LoginToContact为storyboard中segue的标识 [self performSegueWithIdentifier:@"LoginToContact" sender:nil]; }
跳转之前调用prepareForSegue方法
/* 一般在这里给下一个控制器传值 这个sender是当初performSegueWithIdentifier方法传入的sender */ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {//1.取得目标控制器 UIViewController *contactVc = segue.destinationViewController; //2.设置标题(传值) contactVc.title = [NSString stringWithFormat:@"%@的联系人列表",self.nameField.text]; }
3,使用第三方控件MBProgressHUD实现进度提示
在使用之前引入头文件#import "MBProgressHUD+MJ.h",MBProgressHUD+MJ.h是对MBProgressHUD的再一次封装,为了方便使用这个+MJ的。
//登陆 - (IBAction)loginAction { if (![self.nameField.text isEqualToString:@"jike"]) { [MBProgressHUD showError:@"账号不存在"]; return; } if (![self.pwdField.text isEqualToString:@"qq"]) { [MBProgressHUD showError:@"密码错误"]; return; } //显示蒙版(遮盖) [MBProgressHUD showMessage:@"努力加载中"]; //模拟2秒跳转,以后要发送网络请求 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //移除遮盖 [MBProgressHUD hideHUD]; [self performSegueWithIdentifier:@"LoginToContact" sender:nil]; }); }
4,使用UIAlertController
自IOS8.0后UIActionSheet和UIAlertView被UIAlertController取代
- (IBAction)backAction:(id)sender { //初始化 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"是否注销?" message:@"真的要注销吗" preferredStyle:UIAlertControllerStyleActionSheet]; //添加按钮 [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { [self.navigationController popViewControllerAnimated:YES]; }]]; //弹出 [self presentViewController:alert animated:YES completion:NULL]; }
5,实现添加页传值
要实现的要点有:a,弹出添加页时弹出小键盘,光标定位到输入框里。来获得更好的用户体验
- (void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; //让姓名文本框成为第一响应者(叫出键盘) [self.nameField becomeFirstResponder]; }
b,建立Model文件夹作为模型层,在该文件夹下添加需要传值的模型
#import <Foundation/Foundation.h> @interface JKContactModel : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *phone; @end
c,定义接口AddViewControllerDelegate,接口内有个方法需要传入AddViewController和JKContactModel
@class 防止相互导入
@property为assign类型,为了防止循环引用
#import <UIKit/UIKit.h> @class AddViewController,JKContactModel; @protocol AddViewControllerDelegate <NSObject> @optional - (void)addContact:(AddViewController *)addVc didAddContact:(JKContactModel *)contact; @end @interface AddViewController : UIViewController @property (nonatomic, assign) id<AddViewControllerDelegate> delegate; @end
d,在AddViewController下面编写AddAction添加按钮点击事件
respondsToSelector判断某个对象是否实现了某方法
//添加数据 - (IBAction)AddAction { //1.关闭当前视图控制器 [self.navigationController popViewControllerAnimated:YES]; //代理传值 //如果它的代理对象响应了我们这个协议方法就进行传值 if ([self.delegate respondsToSelector:@selector(addContact:didAddContact:)]) { JKContactModel *contactModel = [[JKContactModel alloc] init]; contactModel.name = self.nameField.text; contactModel.phone = self.phoneField.text; [self.delegate addContact:self didAddContact:contactModel]; } }
e,最后回到联系人列表控制器ContactTableViewController来响应传值
#pragma mark - AddViewController delagate - (void)addContact:(AddViewController *)addVc didAddContact:(JKContactModel *)contact{ //1.添加数据模型 [self.contactArr addObject:contact]; //2.刷新表视图 [self.tableView reloadData]; }
f,还有一点要在prepareForSegue方法下设置代理为自己本身
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { AddViewController *addVc = segue.destinationViewController; addVc.delegate = self; }
6,实现修改页传值
这个页基本上本上面添加页差不多....没什么知识点好整理的...
这样还是有一个问题,这个ContactTableViewController控制器有两个目标控制器,这样子需要segeue的目标控制器来判断转跳到哪里
修改prepareForSegue方法
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { id vc = segue.destinationViewController; if ([vc isKindOfClass:[AddViewController class]]) {//如果是跳转到添加联系人控制器 //设置代理 AddViewController *addVc = vc; addVc.delegate = self; }else if ([vc isKindOfClass:[EditViewController class]]){ EditViewController *editVc = vc; //取得选中的那一行 NSIndexPath *path = [self.tableView indexPathForSelectedRow]; editVc.contactModel = self.contactArr[path.row]; editVc.delagate = self; } }
7,UITableView实现滑动删除
UITableView有一个方法叫commitEditingStyle,通过这个方法实现删除功能
#pragma mark - UITableView delagate - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ if (editingStyle == UITableViewCellEditingStyleDelete) { //1.删除数据模型 [self.contactArr removeObjectAtIndex:indexPath.row]; //2.刷新表视图 [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop]; } }
8,偏好设置
要实现的要点有:a,在viewDidLoad事件中加载上次配置
- (void)viewDidLoad { [super viewDidLoad]; //读取上次配置 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; self.nameField.text = [defaults valueForKey:UserNameKey]; self.pwdField.text = [defaults valueForKey:PwdKey]; self.rembSwitch.on = [defaults boolForKey:RmbPwdKey]; if (self.rembSwitch.isOn) { self.pwdField.text = [defaults valueForKey:PwdKey]; self.loginBtn.enabled = YES; } }
b,在用户登陆成功后保存配置
//登陆 - (IBAction)loginAction { //存储数据 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:self.nameField.text forKey:UserNameKey]; [defaults setObject:self.pwdField.text forKey:PwdKey]; [defaults setBool:self.rembSwitch.isOn forKey:RmbPwdKey]; //设置同步 [defaults synchronize]; }
9,对象归档
要实现的要点有:a, NSKeyedArchiver 必须实现NSCoding协议方法
#import "JKContactModel.h" @implementation JKContactModel /* 将某个对象写入文件时候会调用 在这个方法中说清楚哪些属性需要存储 */ - (void)encodeWithCoder:(NSCoder *)encoder{ [encoder encodeObject:self.name forKey:@"name"]; [encoder encodeObject:self.phone forKey:@"phone"]; } /* 解析对象会调用这个方法 需要解析哪些属性 */ - (id)initWithCoder:(NSCoder *)decoder{ if (self = [super init]) { self.name = [decoder decodeObjectForKey:@"name"]; self.phone = [decoder decodeObjectForKey:@"phone"]; } return self; } @end
b,然后创建一个归档的文件名,使用到的时候将归档的文件加载至内存当中
#define ContactFilePath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"contacts.data"] @property (nonatomic, strong) NSMutableArray *contactArr; @implementation ContactTableViewController - (NSMutableArray *)contactArr{ if (!_contactArr) { //先重归档的文件中读取,如果不存在,则创建一个array _contactArr = [NSKeyedUnarchiver unarchiveObjectWithFile:ContactFilePath]; if (_contactArr == nil) { _contactArr = [NSMutableArray array]; } } return _contactArr; }
c,需要在数据添加、更新、删除后都应该对数据进行归档
[NSKeyedArchiver archiveRootObject:self.contactArr toFile:ContactFilePath];