Cowboy Tech

iOS项目10-通讯录

效果图

项目结构

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

LoginViewController

保存和读取登录信息

//保存
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];

//读取
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.nameField.text = [defaults valueForKey:UserNameKey];
self.pwdField.text = [defaults valueForKey:PwdKey];
self.rembSwitch.on = [defaults boolForKey:RmbPwdKey];

观察者

当文本框里都填有数字时,按钮才可以点击

//添加观察者,如果object为nil,就会检测到所有的变化。因此必须得针对性的设定object监测
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.nameField];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.pwdField];

条件语句设置BOOL值

self.loginBtn.enabled = (self.nameField.text.length && self.pwdField.text.length);

执行Segue进行视图跳转

[self performSegueWithIdentifier:@"LoginToContact" sender:nil];

Segue跳转之前执行

/*
一般在这里给下一个控制器传值
这个sender是当初performSegueWithIdentifier方法传入的sender
*/

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

//1.取得目标控制器
UIViewController *contactVc = segue.destinationViewController;
//2.设置标题(传值)
contactVc.title = [NSString stringWithFormat:@"%@的联系人列表",self.nameField.text];
}

设置字符串

[NSString stringWithFormat:@"%@的联系人列表",self.nameField.text]

MBProgressHUD

if (![self.nameField.text isEqualToString:@"jike"]) {
    [MBProgressHUD showError:@"账号不存在"];
    return;
}
if (![self.pwdField.text isEqualToString:@"qq"]) {
    [MBProgressHUD showError:@"密码错误"];
    return;
}
//显示蒙版(遮盖)
[MBProgressHUD showMessage:@"努力加载中"];

ContactTableViewController

对象的归档和解档

//定义文件的路径
#define ContactFilePath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"contacts.data"]

//每次操作都需要将数据归档
[NSKeyedArchiver archiveRootObject:self.contactArr toFile:ContactFilePath];

//解档
_contactArr = [NSKeyedUnarchiver unarchiveObjectWithFile:ContactFilePath];

懒加载数据

- (NSMutableArray *)contactArr{
if (!_contactArr) {
    _contactArr = [NSKeyedUnarchiver unarchiveObjectWithFile:ContactFilePath];
    if (_contactArr == nil) {
        _contactArr  = [NSMutableArray array];
    }
}
return _contactArr;
}

UIAlertcontroller

- (IBAction)backAction:(id)sender {
//初始化
//UIAlertcontroller = UIAlertView + UIActionSheet , iOS 8以后出现的

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

去掉TableView中多余的线

- (void)clearExtraLine :(UITableView *)tableView{
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor clearColor];
[self.tableView setTableFooterView:view];
}

when reloadData ?

[self.tableView reloadData];

Prepare for multiple segue

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

判断what class

[vc isKindOfClass:[EditViewController class]

确定选中哪一行

NSIndexPath *path = [self.tableView indexPathForSelectedRow]

动态删除一行

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

    //以下也是一个刷新的方法,是全部表格刷新
    //[self.tableView reloadData];
    //3. 归档
    [NSKeyedArchiver archiveRootObject:self.contactArr toFile:ContactFilePath];
}
}

AddViewController

设置代理方法

@protocol AddViewControllerDelegate <NSObject>
@optional
- (void)addContact:(AddViewController *)addVc didAddContact:(JKContactModel *)contact;
@end

@interface AddViewController : UIViewController
//assign类型防止循环引用?
@property (nonatomic, assign) id<AddViewControllerDelegate> delegate;
@end

文本框为第一响应

- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
//让姓名文本框成为第一响应者(叫出键盘)
[self.nameField becomeFirstResponder];
}

代理传值

delegate就相当于是一个信使,适用于视图控制器之间的传值(review 应用程序管理)

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

记得接收方要设置代理对象

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    AddViewController *addVc = segue.destinationViewController;
    addVc.delegate = self;

EditViewController

加载数据

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.nameField.text = self.contactModel.name;
self.phoneField.text = self.contactModel.phone;
}

代理传值

//保存
- (IBAction)saveAction:(id)sender {
//1.关闭当前页面
[self.navigationController popViewControllerAnimated:YES];
//2.通知代理
if ([self.delagate respondsToSelector:@selector(enditViewController:didSaveContact:)]) {
    //更新数据模型
    self.contactModel.name = self.nameField.text;
    self.contactModel.phone = self.phoneField.text;
    [self.delagate enditViewController:self didSaveContact:self.contactModel];
}
}

UIButton & UITextfield & UIView

self.nameField.enabled = NO;
[self.view endEditing:YES];
self.savebtn.hidden = YES;