1、私人通信錄windows
什麼是Segue數組
● Storyboard上每⼀一根⽤用來界⾯面跳轉的線,都是⼀一個UIStoryboardSegue對象(簡稱Segue)服務器
"【登陸界面】"網絡
1.掌握UIStoryboardSegue對象ide
(1)在storyboard中,能夠經過連線完成多個界面間的跳轉,每一連線咱們稱爲segue性能
(2)掌握storyboard中的segue連線有兩種,一是自動跳轉、二是手動跳轉動畫
自動跳轉從按鈕連線,無論帳號和密碼是否是正確,就直接跳到下一個界面,而手動跳轉,是用控制器開始連線。並設置segue的Identifier.atom
(3)掌握如何使用代碼跳轉頁面手動segue -->【[self performSegueWithIdentifier:@"contactSegue" sender:nil];】spa
(4)掌握UIStoryboardSegue對象的源控制器和目標控制器3d
2.掌握MBProgressHUD的使用,給用戶一個友好的提示
3.掌握控制器的數據傳遞
(1) 在控制器的【-(void)prepareForSegue:sender:】的方法中獲取目標控制器
(2) 設置目標控制器的屬性,能夠實現數據的傳遞
4.掌握文件框文字改變的監聽
方法1 使用通知中心
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.passwordField];
方法2 往文本輸入框添加事件
【addTarget: action: forControlEvents:UIControlEventEditingChanged】
方法3 storybaord連線
5.掌握記住密碼與自動登陸邏輯
(1)記住密碼爲關閉的狀況下,若是自動登陸爲開啓狀態,應該關閉
(2)若是自動登陸爲關閉狀態,記住密碼必需爲開啓狀態
"【添加聯繫人頁面】"
1.掌握數據的逆向傳遞
(1)若是想向上一個控制器傳遞數據,可使用代理的方法
(2)向上個控制器傳遞數據時,能夠傳遞字符串或者模型
2.掌握表格的局部刷新,性能更好,使用【self.tableView insertRowsAtIndexPaths:withRowAnimation:】方法
"【編輯聯繫人】"
1.使用代理的方法通知上一個控制器聯繫個編輯完成,並保存
2.刷新數據使用局部刷新【[self.tableView reloadRowsAtIndexPaths:withRowAnimation】
Main.storyboard
cell的ID和添加聯繫人時能夠防止cell右面沒有數據(在Style中設置)
LoginViewController.m
//
// LoginViewController.m
// 08.私人通信錄
//
// Created by huan on 16/1/21.
// Copyright © 2016年 huanxi. All rights reserved.
//
#import "LoginViewController.h"
#import "ContactsViewController.h"
#import "MBProgressHUD+CZ.h"
//定義用戶偏好設置的key 防止寫錯
#define rememberPwdKey @"rememberPwd" //記錄密碼
#define autoLoginKey @"autoLogin"//自動登陸
#define accountKey @"account"//帳號
#define passwordKey @"password"//密碼
@interface LoginViewController ()
@property (weak, nonatomic) IBOutlet UITextField *accoutField;
@property (weak, nonatomic) IBOutlet UITextField *passwordField;
- (IBAction)loginBtnClick;
@property (weak, nonatomic) IBOutlet UIButton *loginBtn;
@property (weak, nonatomic) IBOutlet UISwitch *rememberPwdSwitch;
@property (weak, nonatomic) IBOutlet UISwitch *autoLoginSwitch;
@end
@implementation LoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
#pragma mark 輸入框裏沒有值,禁用登陸按鈕有3種方法(1)通知(2)添加事件(3)連線
//使用通知中心來監聽文本(TextField)的變化
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.accoutField];
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.passwordField];
//textField 添加事件
// [self.accoutField addTarget:self action:@selector(textChange) forControlEvents:UIControlEventEditingChanged];
// [self.passwordField addTarget:self action:@selector(textChange) forControlEvents:UIControlEventEditingChanged];
//設置 「開關」 默認值
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.rememberPwdSwitch.on = [defaults boolForKey:rememberPwdKey];
self.autoLoginSwitch.on = [defaults boolForKey:autoLoginKey];
//設置帳號和密碼 默認值
self.accoutField.text = [defaults objectForKey:accountKey];
NSLog(@"++++++++++%@", NSHomeDirectory());
if (self.rememberPwdSwitch.isOn) {
self.passwordField.text = [defaults objectForKey:passwordKey];
}
//調用 文本 變化 的方法
[self textChange];//解決登陸按鈕禁止的問題
//若是 「自動登陸」 勾選,讓自動登陸
if (self.autoLoginSwitch.isOn) {
[self loginBtnClick];
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// [self loginBtnClick];
// });
}
NSLog(@"viewDidLoad 打印窗口%@",[UIApplication sharedApplication].windows);
}
// UITextEffectsWindow 給鍵盤,只有view顯示完成以後纔會建立
-(void)viewDidAppear:(BOOL)animated{
NSLog(@"viewDidAppear打印窗口%@", [UIApplication sharedApplication].windows);
;
}
//控制器已經銷燬,不須要監聽
-(void)dealloc{
//移除通知者中心
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (IBAction)textChange:(id)sender {
self.loginBtn.enabled = (self.accoutField.text.length != 0 && self.passwordField.text.length != 0);
}
-(void)textChange{
NSLog(@"%s",__func__);
//判斷輸入有沒有值
// if (self.accoutField.text.length != 0 && self.passwordField.text.length != 0) {
// self.loginBtn.enabled = YES;
// }else{
// self.loginBtn.enabled = NO;
//
// }
self.loginBtn.enabled = (self.accoutField.text.length != 0 && self.passwordField.text.length != 0);
//沒有值,禁用登陸按鈕
}
- (IBAction)loginBtnClick {
//判斷用戶名密碼是否正確,只有正確的狀況下,才能進行下一個界面
NSString *accout = self.accoutField.text;
NSString *password = self.passwordField.text;
//不添加toView參數,提示框是添加在window上,toView表明提示框添加到哪一個view上
[MBProgressHUD showMessage:@"正在登陸中。。。"];
// [MBProgressHUD showMessage:@"正在登陸中。。。" toView:self.view];//self.view 就是LoginViewController的view
// [MBProgressHUD showMessage:@"正在登陸中。。。" toView:self.navigationController.view];
//模擬登陸有一個等待過程
//通常登陸是網絡的請求,而不是本地的請求,不少數據都保存在 雲(服務器) 上面去的
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//登陸完成 隱藏提示框
[MBProgressHUD hideHUD];
// [MBProgressHUD hideHUDForView:self.view];
if ([accout isEqualToString:@"zhangsan"] && [password isEqualToString:@"123"]) {//帳號與密碼正確
NSLog(@"帳號與密碼正確");
//執行一個segue,就會進入segue所指的控制器
[self performSegueWithIdentifier:@"toContactsSegue" sender:nil];
//保存用戶帳號和密碼
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:accout forKey:accountKey];
//只有「記住密碼」開啓的狀態,纔要保存
if (self.rememberPwdSwitch.isOn) {
[defaults setObject:password forKey:passwordKey];
}
[defaults synchronize];
}else{
NSLog(@"帳號或者密碼不正確");
//給一個錯誤的提示
[MBProgressHUD showError:@"帳號或者密碼不正確"];
}
});
}
// 記錄密碼開關的值的變化
- (IBAction)rememberPwdSwitchChange {
//若是記住密碼 爲 關閉狀態,而且 自動登陸爲 開啓的狀態,此時,自動登陸 應該爲關閉
if (self.rememberPwdSwitch.isOn == NO && self.autoLoginSwitch.isOn == YES) {
// self.autoLoginSwitch.on = NO;
//添加動畫
[self.autoLoginSwitch setOn:NO animated:YES];
}
//保存開關數據
[self saveSwitchToPreference];
}
//自動登陸開關的值的變化
- (IBAction)autoLoginSwitchChange {
//若是 自動登陸 爲 開啓狀態 而且 記住密碼 關閉狀態,此時,記住密碼應該爲開啓
if (self.rememberPwdSwitch.isOn == NO && self.autoLoginSwitch.isOn == YES) {
[self.rememberPwdSwitch setOn:YES animated:YES];
}
[self saveSwitchToPreference];
}
-(void)saveSwitchToPreference{
//保存開關數據
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:self.rememberPwdSwitch.isOn forKey:rememberPwdKey];
[defaults setBool:self.autoLoginSwitch.isOn forKey:autoLoginKey];
[defaults synchronize];
}
//使用segue跳轉下一個界面以前會調用
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(@"%s", __func__);
NSLog(@"源控制器 %@", [segue sourceViewController]);
NSLog(@"目標控制器 %@", segue.destinationViewController);
//能夠傳遞數據給下一個控制器
//目標控制器
id destVc = segue.destinationViewController;
//判斷控制器的類型
if ([destVc isKindOfClass:[ContactsViewController class]]) {
ContactsViewController *contactsVc = destVc;
//設置名字屬性
contactsVc.name = self.accoutField.text;
}
}
@end
ContactsViewController.h
#import <UIKit/UIKit.h>
@interface ContactsViewController : UITableViewController
@property (nonatomic, copy) NSString *name;
@end
ContactsViewController.m
//
// ContactsViewController.m
// 08.私人通信錄
//
// Created by huan on 16/1/21.
// Copyright © 2016年 huanxi. All rights reserved.
//
/**
* 保存聯繫人 使用NSKeyedArcheiver
* 1.Contact要遵照 NScoding
* 2.文件保存的路徑
* 3.NSKeyedArcheiver 保存
* 4.NSKeyedUnArcheiver 讀取數據
*/
#import "ContactsViewController.h"
#import "AddContactViewController.h"
#import "EditContactViewController.h"
#import "Contact.h"
@interface ContactsViewController ()<AddContactViewControllerDelegate, UITableViewDataSource, UITableViewDelegate, EditContactViewControllerDelegate>
@property (nonatomic, strong) NSMutableArray *contacts;
/**
* 聯繫人數據保存的路徑
*/
@property (nonatomic, copy) NSString *contactPath;
@end
@implementation ContactsViewController
-(NSString *)contactPath{
if (!_contactPath) {
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
_contactPath = [doc stringByAppendingPathComponent:@"contacts.archiver"];
}
return _contactPath;
}
-(NSMutableArray *)contacts{
if (!_contacts) {
//先從「沙盒」獲取數據
_contacts = [NSKeyedUnarchiver unarchiveObjectWithFile:self.contactPath];
//程序第一次使用,沙盒沒有聯繫人數據
if (!_contacts) {
_contacts = [NSMutableArray array];
}
}
return _contacts;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//設置標題
self.title = [NSString stringWithFormat:@"%@的聯繫人",self.name];
NSLog(@"%@", self.contactPath);
///Users/huan/Library/Developer/CoreSimulator/Devices/37683403-6248-4A9A-863A-53CB9C1361FD/data/Containers/Data/Application/28527B3B-9CCB-4DA4-B3FE-45A8958805EC/Documents/contacts.archiver
//懶加載中 那個Yes改成NO ~/Documents/contacts.archiver
//在導航欄右邊加個按鈕
// UIBarButtonItem *deleteItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self.navigationItem action:@selector(delete:)];
// self.navigationItem.rightBarButtonItems = @[deleteItem, self.navigationItem.rightBarButtonItem];//在iOS8上只有這樣寫,用代碼的方式,可是iOS9做出改進,能夠在Main.storyboard中添加UIBarButtonItem.
}
- (IBAction)delete:(id)sender {
//設置表格的「編輯」屬性
// self.tableView.editing = YES;
//添加動畫
// [self.tableView setEditing:YES animated:YES];
[self.tableView setEditing:!self.tableView.editing animated:YES];//點擊「垃圾」按鈕可回去。
}
#pragma mark 返回表格的「編輯」狀態
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
if (indexPath.row == 0) {
return UITableViewCellEditingStyleInsert;
}
return UITableViewCellEditingStyleDelete;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"%s", __func__);
if (editingStyle == UITableViewCellEditingStyleDelete) {
//獲取行
//刪除聯繫人
[self.contacts removeObjectAtIndex:indexPath.row];
//刷新表格
NSIndexPath *deleteIndex = [NSIndexPath indexPathForRow:indexPath.row inSection:0];
[self.tableView deleteRowsAtIndexPaths:@[deleteIndex] withRowAnimation:UITableViewRowAnimationFade];
//同步數據
[NSKeyedArchiver archiveRootObject:self.contacts toFile:self.contactPath];
}else if (editingStyle == UITableViewCellEditingStyleInsert){
//添加一個10086聯繫人
Contact *contact = [[Contact alloc] init];
contact.tel = @"10086";
//保存數據,刷新表格
[self.contacts insertObject:contact atIndex:indexPath.row + 1];
NSIndexPath *insertIndex = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[insertIndex] withRowAnimation:UITableViewRowAnimationFade];
//同步數據
[NSKeyedArchiver archiveRootObject:self.contacts toFile:self.contactPath];
}
}
#pragma mark 表格的數據
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.contacts.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"%s", __func__);
static NSString *ID = @"ContactCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
//顯示數據
Contact *contact = self.contacts[indexPath.row];
cell.textLabel.text = contact.name;
cell.detailTextLabel.text = contact.tel;
return cell;
}
- (IBAction)logoutBtnClick:(id)sender {
//註銷
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"確認" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
//直接返回上一個控制器
[self.navigationController popViewControllerAnimated:YES];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}]];
//彈出提示框
[self presentViewController:alert animated:true completion:nil];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
//獲取目標控制器
id destVc = segue.destinationViewController;
//判斷類型
if ([destVc isKindOfClass:[AddContactViewController class]]) {
AddContactViewController *addContactVc = destVc;
addContactVc.delegate = self;
}else if ([destVc isKindOfClass:[EditContactViewController class]]){
//1.獲取目標控制器
EditContactViewController *editVc = destVc;
//2.獲取對應索引的聯繫人
NSInteger selectedRow = self.tableView.indexPathForSelectedRow.row;
Contact *contact = self.contacts[selectedRow];
//3.設置編輯聯繫人控制器的contact屬性
editVc.contact = contact;
//4.設置編輯聯繫人的代理
editVc.delegate = self;
}
}
//-(void)addContactViewController:(AddContactViewController *)addContactVc didSaveContactWithName:(NSString *)name tel:(NSString *)tel{
// //刷新表格
// Contact *contact = [[Contact alloc] init];
// contact.name = name;
// contact.tel = tel;
// //添加聯繫人數組
// [self.contacts addObject:contact];
// //刷新表格
// [self.tableView reloadData];
//
// //隱藏添加聯繫人的控制器
// [self.navigationController popViewControllerAnimated:YES];
//}
#pragma mark 添加聯繫人控制器的代理
-(void)addContactViewController:(AddContactViewController *)addContactVc didSaveContact:(Contact *)contact{
//把模型添加到聯繫人數組
[self.contacts addObject:contact];
//刷新
// [self.tableView reloadData];
//局部刷新
NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.contacts.count - 1 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[lastPath] withRowAnimation:UITableViewRowAnimationFade];
//隱藏添加聯繫人的控制器
[self.navigationController popViewControllerAnimated:YES];//這句代碼也能夠寫在添加聯繫人控制器保存按鈕操做中,由於官方文檔說,誰打開誰銷燬。可是也能夠寫在本控制器刷新前面。這個位置不定,隨本身的喜愛而定。
// 同步數據 到沙盒
[NSKeyedArchiver archiveRootObject:self.contacts toFile:self.contactPath];
}
#pragma mark 編輯聯繫人控制器的代理
-(void)editContactViewController:(EditContactViewController *)editContactVc didFinishedSaveConatct:(Contact *)contact{
//局部刷新
//當前刷新的行
NSInteger row = [self.contacts indexOfObject:contact];
NSIndexPath *refreshIndex = [NSIndexPath indexPathForRow:row inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[refreshIndex] withRowAnimation:UITableViewRowAnimationFade];
//隱藏添加聯繫人的控制器
[self.navigationController popViewControllerAnimated:YES];
// 同步數據 到沙盒
[NSKeyedArchiver archiveRootObject:self.contacts toFile:self.contactPath];
}
@end
AddContactViewController.h
#import <UIKit/UIKit.h>
@class AddContactViewController, Contact;
@protocol AddContactViewControllerDelegate<NSObject>
//-(void)addContactViewController:(AddContactViewController *)addContactVc didSaveContactWithName:(NSString *)name tel:(NSString *)tel;
//直接返回一個聯繫人模型
-(void)addContactViewController:(AddContactViewController *)addContactVc didSaveContact:(Contact *)contact;
@end
@interface AddContactViewController : UIViewController
@property (weak, nonatomic) id<AddContactViewControllerDelegate>delegate;
@end
//
// AddContactViewController.m
// 08.私人通信錄
//
// Created by huan on 16/1/21.
// Copyright © 2016年 huanxi. All rights reserved.
//
#import "AddContactViewController.h"
#import "Contact.h"
@interface AddContactViewController ()
@property (weak, nonatomic) IBOutlet UITextField *nameField;
@property (weak, nonatomic) IBOutlet UITextField *telField;
@end
@implementation AddContactViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)saveBtnClick:(id)sender {
//獲取姓名和電話
// NSString *name = self.nameField.text;
// NSString *tel = self.telField.text;
//通知上一個控制器,完成聯繫人保存 經過代理
// if ([self.delegate respondsToSelector:@selector(addContactViewController:didSaveContactWithName:tel:)]) {
// [self.delegate addContactViewController:self didSaveContactWithName:name tel:tel];
// }
if ([self.delegate respondsToSelector:@selector(addContactViewController:didSaveContact:)]) {
Contact *contact = [[Contact alloc] init];
contact.name = self.nameField.text;
contact.tel = self.telField.text;
[self.delegate addContactViewController:self didSaveContact:contact];
}
//上一個控制器刷新表格
}
@end
EditContactViewController.h
#import <UIKit/UIKit.h>
@class Contact, EditContactViewController;
@protocol EditContactViewControllerDelegate<NSObject>
-(void)editContactViewController:(EditContactViewController *)editContactVc didFinishedSaveConatct:(Contact *)contact;
@end
@interface EditContactViewController : UIViewController
//聯繫人
@property (nonatomic, strong) Contact *contact;
@property (weak, nonatomic) id<EditContactViewControllerDelegate>delegate;
@end
EditContactViewController.m
//
// EditContactViewController.m
// 08.私人通信錄
//
// Created by huan on 16/1/21.
// Copyright © 2016年 huanxi. All rights reserved.
//
#import "EditContactViewController.h"
#import "Contact.h"
@interface EditContactViewController ()
@property (weak, nonatomic) IBOutlet UITextField *nameField;
@property (weak, nonatomic) IBOutlet UITextField *telField;
@property (weak, nonatomic) IBOutlet UIButton *saveBtn;
@end
@implementation EditContactViewController
- (void)viewDidLoad {
[super viewDidLoad];
//設置文本框默認值
self.nameField.text = self.contact.name;
self.telField.text = self.contact.tel;
}
- (IBAction)editBtnClick:(UIBarButtonItem *)item {
//1.若是當前是不可用狀態 設置文本輸入框爲可用,按鈕可見
// if (self.nameField.enabled) {
// self.nameField.enabled = NO;
// }
self.nameField.enabled = !self.nameField.enabled;
self.telField.enabled = !self.telField.enabled;
self.saveBtn.hidden = !self.saveBtn.hidden;
//2.改變「編輯」按鈕的文字
if (self.nameField.enabled) {
item.title = @"取消";
}else{
item.title = @"編輯";
}
}
- (IBAction)saveBtnClick:(id)sender {
//3.經過代理通知上一個控制器 「完成」 聯繫人編輯
if ([self.delegate respondsToSelector:@selector(editContactViewController:didFinishedSaveConatct:)]) {
//更改聯繫人的模型
self.contact.name = self.nameField.text;
self.contact.tel = self.telField.text;
//調用代理
[self.delegate editContactViewController:self didFinishedSaveConatct:self.contact];
}
}
@end
Contact.h
#import <Foundation/Foundation.h>
@interface Contact : NSObject<NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *tel;
@end
Contact.m
#import "Contact.h"
@implementation Contact
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.tel forKey:@"tel"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
//必定要賦值
self.name = [aDecoder decodeObjectForKey:@"name"];
self.tel = [aDecoder decodeObjectForKey:@"tel"];
}
return self;
}
@end