ios-day13-01(私人通讯录。控制器之间的数据传递、保存密码和自动登录的实现、普通对象的归档、UITableView的局部刷新和向左滑动删除功能等等)

源码下载地址:http://download.csdn.net/detail/liu537192/8523613


效果图:

      


核心代码:

//
//  JLLoginViewController.h
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     

@interface JLLoginViewController : UIViewController

@end
//
//  JLLoginViewController.m
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLLoginViewController.h"
#import "MBProgressHUD+MJ.h"

@interface JLLoginViewController ()
/**
 *  “账号”输入框
 */
@property (weak, nonatomic) IBOutlet UITextField *accountField;
/**
 *  “密码”输入框
 */
@property (weak, nonatomic) IBOutlet UITextField *pwdField;
/**
 *  “登录”按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *loginBtn;
/**
 *  "记住密码"开关
 */
@property (weak, nonatomic) IBOutlet UISwitch *remeberPwdSwitch;
/**
 *  "自动登录"开关
 */
@property (weak, nonatomic) IBOutlet UISwitch *autoLoginSwitch;
/**
 *  "记住密码"开关状态改变
 */
- (IBAction)remeberPwdSwitchChange;
/**
 *  "自动登录"开关状态改变
 */
- (IBAction)autoLoginSwitchChange;
/**
 *  "登录"按钮被点击
 */
- (IBAction)loginBtnClick;
@end

@implementation JLLoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 监听“账号”输入框的文本改变。
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.accountField];
    // 监听“密码”输入框的文本改变
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.pwdField];
    
    // 读取上一次的 记住密码、自动登录等个人配置数据
    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    
    self.accountField.text = [def objectForKey:@"JLAccountKey"];
    
    self.remeberPwdSwitch.on = [def boolForKey:@"JLRemeberPwdKey"];
    
    self.autoLoginSwitch.on = [def boolForKey:@"JLAutoLoginKey"];
    // 如果上一次登录时勾选了“记住密码”,才自动填充密码
    if (self.remeberPwdSwitch.isOn) {
        
        self.pwdField.text = [def objectForKey:@"JLPwdKey"];
    }
    // 如果上一次登录时勾选了“自动登录”,才自动登录
    if (self.autoLoginSwitch.isOn) {
        [self loginBtnClick];
    }
    
    
}

- (void)dealloc{

    // 一定要记得移除对通知的监听
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
}

- (void)textChange{
    // 只有当“账号”输入框和“密码”输入框都有文字的时候,“登录”按钮才可用
//    if (self.accountField.text.length > 0 && self.pwdField.text.length > 0) {
//        self.loginBtn.enabled = YES;
//    }else{
//        self.loginBtn.enabled = NO;
//    }
    
    // 以上代码可以简写成:
    self.loginBtn.enabled = (self.accountField.text.length && self.pwdField.text.length);
}
/**
 *  "记住密码"开关状态改变
 */
- (IBAction)remeberPwdSwitchChange {
    // 如果“记住密码”开关关闭,那么“自动登录”开关也应该关闭
    if (self.remeberPwdSwitch.isOn == NO) {
//        self.autoLoginSwitch.on = NO;
        // 下面这句代码相比上面这句这代码,有一个动画的过程,用户体验更好
        [self.autoLoginSwitch setOn:NO animated:YES];
    }
}
/**
 *  "自动登录"开关状态改变
 */
- (IBAction)autoLoginSwitchChange {
    // 如果“自动登录”开关打开,那么“记住密码”开关也应该打开
    if (self.autoLoginSwitch.isOn == YES) {
//        self.remeberPwdSwitch.on = YES;
        [self.remeberPwdSwitch setOn:YES animated:YES];
    }
}
/**
 *  "登录"按钮被点击
 */
- (IBAction)loginBtnClick {
    
    if (![self.accountField.text isEqualToString:@"kobe"]) {
        // 提示用户"账号不存在"
        [MBProgressHUD showError:@"账号不存在"];
        
        return;
    }
    
    if (![self.pwdField.text isEqualToString:@"123"]) {
        // 提示用户"密码错误"
        [MBProgressHUD showError:@"密码错误"];
        
        return;
    }
    
    // 显示一个遮盖
    [MBProgressHUD showMessage:@"玩命加载中..."];
    
    // 模拟网络请求,1秒钟后跳转
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        // 移除遮盖
        [MBProgressHUD hideHUD];
        
        [self performSegueWithIdentifier:@"loginToContact" sender:nil];
        
        // 存储 记住密码、自动登录等个人配置数据
        NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
        // 存储是否记住密码
        [def setBool:self.remeberPwdSwitch.isOn forKey:@"JLRemeberPwdKey"];
        // 存储是否自动登录
        [def setBool:self.autoLoginSwitch.isOn forKey:@"JLAutoLoginKey"];
        // 存储账号
        [def setObject:self.accountField.text forKey:@"JLAccountKey"];
        // 存储密码
        [def setObject:self.pwdField.text forKey:@"JLPwdKey"];
        
        [def synchronize];// 立即同步到文件
        
    });
    
}
@end

    
    
//
//  JLContactViewController.h
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     

@interface JLContactViewController : UITableViewController

@end
//
//  JLContactViewController.m
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLContactViewController.h"
#import "JLContact.h"
#import "JLAddViewController.h"
#import "JLContactsCell.h"
#import "JLEditViewController.h"

#define JLContactsDataFilePath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"contacts.data"]


@interface JLContactViewController ()
     
     
      
      

- (IBAction)loginOut:(UIBarButtonItem *)sender;

@property (nonatomic, strong)NSMutableArray *contactsArray;

@end

@implementation JLContactViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 设置tableView没有分隔线
    // 因为默认是有分隔线的,而且满屏幕的都是分隔线,我们只想让有数据的cell有分隔线
    // 所以先设置tableView没有分隔线,然后在每个cell的底部加一个高度为1的UIView
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}

- (NSMutableArray *)contactsArray{

    if (_contactsArray == nil) {
        // 从文件中读取以前保存的联系人的数据
        _contactsArray = [NSKeyedUnarchiver unarchiveObjectWithFile:JLContactsDataFilePath];
        
        // 如果文件中没有数据或者文件不存在
        if (_contactsArray == nil) {
            _contactsArray = [NSMutableArray array];
        }
    }
    
    
    return _contactsArray;
}

#pragma mark - UITableView的数据源方法

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    return self.contactsArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    JLContactsCell *cell = [JLContactsCell cellWithTableView:tableView];
    
    cell.contact = self.contactsArray[indexPath.row];
    
    return cell;
}

#pragma mark - UITableView的代理方法
/**
 *  如果实现了这个方法,就自动实现了滑动删除的功能
 *  点击了删除按钮就会调用
 *  提交了一个编辑操作就会调用(操作:删除\添加)
 *  @param editingStyle 编辑的行为
 *  @param indexPath    操作的行号
 */
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{

    if (editingStyle == UITableViewCellEditingStyleDelete) { // 提交的是删除操作
        // 1.删除模型数据
        [self.contactsArray removeObjectAtIndex:indexPath.row];
        
        // 2.刷新表格
        // 局部刷新某些行
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
        
        // 3.归档
        [NSKeyedArchiver archiveRootObject:self.contactsArray toFile:JLContactsDataFilePath];
    }
}

/**
 *  左上角的"注销"按钮
 */
- (IBAction)loginOut:(UIBarButtonItem *)sender {
    // 弹框
    UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"确定要注销?" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:nil, nil];
    
    [sheet showInView:self.view];
    
}
#pragma mark -UIActionSheet的代理方法
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{

    if (buttonIndex != 0) return;
    
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark -执行跳转之前会调用
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    
    id vc = segue.destinationViewController;
    
    if ([vc isKindOfClass:[JLAddViewController class]]) {
        // 设置JLAddViewController的代理
        JLAddViewController *addVc = vc;
        addVc.delegate = self;
        
    } else if ([vc isKindOfClass:[JLEditViewController class]]){
        JLEditViewController *editVc = vc;
        // 获取当前选中了哪一行
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        editVc.contact = self.contactsArray[indexPath.row];
        
        editVc.delegate = self;
    }
    
}

#pragma mark -JLAddViewController的代理方法
- (void)addViewController:(JLAddViewController *)addViewController didAddContact:(JLContact *)contact{
    // 添加模型数据
    [self.contactsArray addObject:contact];
    // 刷新列表
    [self.tableView reloadData];
    // 归档(存储)数组
    [NSKeyedArchiver archiveRootObject:self.contactsArray toFile:JLContactsDataFilePath];
}
#pragma mark -JLEditViewController的代理方法
- (void)editViewController:(JLEditViewController *)editVc didSaveContact:(JLContact *)contact{

    [self.tableView reloadData];
    
    // 归档(存储)数组
    [NSKeyedArchiver archiveRootObject:self.contactsArray toFile:JLContactsDataFilePath];
}
@end

     
     
    
    
//
//  JLAddViewController.h
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     
@class JLAddViewController, JLContact;

@protocol JLAddViewControllerDelegate 
     
     
      
      

@optional
- (void)addViewController:(JLAddViewController *)addViewController didAddContact:(JLContact *)contact;

@end

@interface JLAddViewController : UIViewController

@property (nonatomic, weak)id
      
      
       
        delegate;

@end
//
//  JLAddViewController.m
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLAddViewController.h"
#import "JLContact.h"

@interface JLAddViewController ()
/**
 *  "姓名"输入框
 */
@property (weak, nonatomic) IBOutlet UITextField *nameField;
/**
 *  "电话"输入框
 */
@property (weak, nonatomic) IBOutlet UITextField *telNumberField;
/**
 *  "添加"按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *addBtn;
/**
 *  "添加"按钮被点击
 */
- (IBAction)addBtnClick;

@end

@implementation JLAddViewController


- (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.telNumberField];
    
    // 下面这句代码应该放到viewDidAppear方法中
//    [self.nameField becomeFirstResponder];
}

- (void)viewDidAppear:(BOOL)animated{

    [super viewDidAppear:animated];
    
    // 让“姓名”输入框成为第一响应者,在view完全显示的时候自动弹出键盘。
    // 如果把这句代码放到viewDidLoad方法中,会出现view还未完全显示,键盘却已经弹出
    [self.nameField becomeFirstResponder];

}

- (void)dealloc{
    
    // 一定要记得移除对通知的监听
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
}

- (void)textChange{
    // 只有当“姓名”输入框和“电话”输入框都有文字的时候,“添加”按钮才可用
    self.addBtn.enabled = (self.nameField.text.length && self.telNumberField.text.length);
}

/**
 *  "添加"按钮被点击
 */
- (IBAction)addBtnClick {
    // 关闭当前控制器
    [self.navigationController popViewControllerAnimated:YES];
    // 通过代理传递数据给上一个控制器
    if ([self.delegate respondsToSelector:@selector(addViewController:didAddContact:)]) {
        
        JLContact *contact = [[JLContact alloc] init];
        
        contact.name = self.nameField.text;
        contact.telNumber = self.telNumberField.text;
        
        [self.delegate addViewController:self didAddContact:contact];
    }
    
    
    
}
@end

      
      
     
     
    
    
//
//  JLEditViewController.h
//  01-私人通讯录
//
//  Created by XinYou on 15-3-14.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     
@class JLContact, JLEditViewController;

@protocol JLEditViewControllerDelegate 
     
     
      
      

@optional
- (void)editViewController:(JLEditViewController *)editVc didSaveContact:(JLContact *)contact;

@end

@interface JLEditViewController : UIViewController

@property (nonatomic, strong)JLContact *contact;

@property (nonatomic, weak)id
      
      
       
        delegate;

@end
//
//  JLEditViewController.m
//  01-私人通讯录
//
//  Created by XinYou on 15-3-14.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLEditViewController.h"
#import "JLContact.h"

@interface JLEditViewController ()
/**
 *  "姓名"输入框
 */
@property (weak, nonatomic) IBOutlet UITextField *nameField;
/**
 *  "电话"输入框
 */
@property (weak, nonatomic) IBOutlet UITextField *telNumField;
/**
 *  "保存"按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *saveBtn;
/**
 *  导航条右上角的“编辑”按钮
 */
@property (weak, nonatomic) IBOutlet UIBarButtonItem *editBtn;
/**
 *  "保存"按钮被点击
 */
- (IBAction)saveBtnClick;
/**
 *  导航条右上角的“编辑”按钮被点击
 */
- (IBAction)editBtnClick:(UIBarButtonItem *)sender;
@end

@implementation JLEditViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 为什么是在这里设置控件显示的内容而不是在setContact方法中设置呢?
    // 在JLContactViewController的prepareForSegue方法中我们调用了JLEditViewController的setContact方法
    // 但是prepareForSegue是控制器跳转之前执行的方法,也就是说此时还未跳转到JLEditViewController,而控制器的view是延时加载的。
    // 也就是说在JLContactViewController的prepareForSegue中调用JLEditViewController的setContact方法的时候,JLEditViewController的view都还没有存在,
    // 如果view都不存在,那么view中的子控件自然不存在,所以在setContact方法中设置子控件的内容是没有意义的。
    self.nameField.text = self.contact.name;
    self.telNumField.text = self.contact.telNumber;
    
    //
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.nameField];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.telNumField];
}

//- (void)setContact:(JLContact *)contact{

//    self.nameField.text = self.contact.name;
//    self.telNumField.text = self.contact.telNumber;
//}

- (void)dealloc{

    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
}

- (void)textChange{

    self.saveBtn.enabled = (self.nameField.text.length && self.telNumField.text.length);
}

- (IBAction)saveBtnClick {
    // 移除当前控制器
    [self.navigationController popViewControllerAnimated:YES];
    
    if ([self.delegate respondsToSelector:@selector(editViewController:didSaveContact:)]) {
        // 更新模型数据
        self.contact.name = self.nameField.text;
        self.contact.telNumber = self.telNumField.text;
        // 通知代理
        [self.delegate editViewController:self didSaveContact:self.contact];
    }
}

- (IBAction)editBtnClick:(UIBarButtonItem *)sender {
    
    if (self.nameField.enabled) {// 输入框可用,表示当前处于编辑状态,导航条右上角的按钮显示的是“取消”
        self.nameField.enabled = NO;
        self.telNumField.enabled = NO;
        self.editBtn.title = @"编辑";
        self.saveBtn.hidden = YES;
        // 隐藏键盘
        [self.view endEditing:YES];
        
        // 用户点击“取消”,意思是取消了编辑,这时需要还原数据
        self.nameField.text = self.contact.name;
        self.telNumField.text = self.contact.telNumber;
        
    }else{//输入框不可用,表示当前处于查看状态,导航条右上角的按钮显示的是“编辑”
        self.nameField.enabled = YES;
        self.telNumField.enabled = YES;
        self.editBtn.title = @"取消";
        self.saveBtn.hidden = NO;
        
        // 一般情况下,编辑联系人的时候修改的是电话号码
        // 这里让“电话”输入框成为第一响应者,弹出键盘
        [self.telNumField becomeFirstResponder];
    }
}
@end

      
      
     
     
    
    
//
//  JLContact.h
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     

@interface JLContact : NSObject 
     
     
      
      

@property (nonatomic, copy)NSString *name;

@property (nonatomic, copy)NSString *telNumber;

@end
//
//  JLContact.m
//  01-私人通讯录
//
//  Created by XinYou on 15-3-13.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLContact.h"

@implementation JLContact

- (void)encodeWithCoder:(NSCoder *)aCoder{

    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeObject:self.telNumber forKey:@"telNumber"];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder{

    if (self = [super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.telNumber = [aDecoder decodeObjectForKey:@"telNumber"];
    }
    
    return self;
}

@end
//
//  JLContactsCell.h
//  01-私人通讯录
//
//  Created by XinYou on 15-3-14.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
      
      
       
       
@class JLContact;

@interface JLContactsCell : UITableViewCell

+ (instancetype)cellWithTableView:(UITableView *)tableView;

@property (nonatomic, strong)JLContact *contact;

@end
//
//  JLContactsCell.m
//  01-私人通讯录
//
//  Created by XinYou on 15-3-14.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLContactsCell.h"
#import "JLContact.h"

@interface JLContactsCell()
/**
 *  cell之间的分隔线
 */
@property (nonatomic, weak)UIView *divider;

@end

@implementation JLContactsCell


+ (instancetype)cellWithTableView:(UITableView *)tableView{

    static NSString *ID = @"contact";
    // 先从缓存池中取,如果缓存池中没有可循环利用的cell,先去storyboard中找到合适的cell
    // cell是从storyboard中创建出来的
    JLContactsCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    return cell;
}

- (void)setContact:(JLContact *)contact{
    // 固定写法
    _contact = contact;
    
    self.textLabel.text = contact.name;
    self.detailTextLabel.text = contact.telNumber;
}
/**
 *  如果cell是通过storyboard或者xib创建的,就不可能会调用这个方法来初始化cell
 *  如果cell是通过手写代码创建,才会调用这个方法来初始化cell
 */
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}
/**
 *  如果cell是通过storyboard或者xib创建的,就会调用这个方法来初始化cell
 *  这个方法的作用类似于init方法
 */
- (void)awakeFromNib
{
    UIView *view = [[UIView alloc] init];
    
    view.backgroundColor = [UIColor blackColor];
    view.alpha = 0.2;
    
    [self.contentView addSubview:view];
    self.divider = view;
}
/**
 *  在这个方法中设置子控件的frame,因为awakeFromNib(或者init)方法中获取到的cell的frame是不正确的。
 */
- (void)layoutSubviews
{
    [super layoutSubviews];
    
    CGFloat dividerX = 10;
    CGFloat dividerH = 1;
    CGFloat dividerY = self.frame.size.height - dividerH;
    CGFloat dividerW = self.frame.size.width;
    self.divider.frame = CGRectMake(dividerX, dividerY, dividerW, dividerH);
}

@end

      
      
     
     
    
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值