首页 > 代码库 > [iOS基础控件 - 6.11.3] 私人通讯录Demo 控制器的数据传递、存储

[iOS基础控件 - 6.11.3] 私人通讯录Demo 控制器的数据传递、存储

A.需求
1.搭建一个“私人通讯录”Demo
2.模拟登陆界面
  • 账号
  • 密码
  • 记住密码开关
  • 自动登陆开关
  • 登陆按钮
3.退出注销
4.增删改查
5.恢复数据(取消修改)
 
B.基本架构
1. 5个控制器
(1)导航控制器 NavigationController
(2)登陆 UIViewController
  • 输入账号密码
  • 记住密码、自动登录开关
  • 登陆跳转按钮
(3)联系人列表 TableViewController
  • 注销功能
  • 添加联系人跳转按钮
(4)添加联系人 UIView
(5)查看、编辑 UIView
 
C.实现步骤
1.搭建
(1)使用NavigationController作为主控制器
(2)使用storyboard构建UI
(3)每个控制器搭配一个相应的类,用以处理各种事件
 
2.登陆界面
(1)账号、密码的输入框
a.使用TextField
技术分享
 
 
b.监听输入事件
<1> 不能使用addTarget方法,因为addTarget只能监听点击事件,不能监听编辑事件
<2> 不能使用代理进行事件监听,代理就是控制器,但是只能监听到开始、结束编辑、允许编辑文字等状态
<3> 使用通知,就能监听到正在编辑的状态了,监听文字的改变
由通知中心转发账号、密码输入框的文字编辑状态信息到控制器,调用指定方法
 1 /* 登陆按钮监听账号、密码输入框的通知 2 * 只有当两者都有内容的时候才能激活登陆按钮 3 */ 4 - (void) loginButtonListening{ 5     // 监听账号输入 6     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.accountText]; 7     8     // 监听密码输入 9     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.pwdText];10 }11 12 // 记得要在自身被销毁的时候取消消息订阅13 - (void)dealloc {14     [[NSNotificationCenter defaultCenter] removeObserver:self];15 }16 17 // 登陆按钮监听的触发事件18 - (void) textChange {19     // 只有当账号、密码不为空的时候,才能使用登陆按钮20     self.loginButton.enabled = self.accountText.text.length && self.pwdText.text.length;21 }
 
(2)登陆
当有账号、密码的时候才能激活登陆按钮
a.验证账号、密码
使用“登陆界面”控制器拖线到“联系人列表”界面控制器:使用Manual Segue
/** 点击登陆 */- (IBAction)login {    // 检测账号    if (![self.accountText.text isEqualToString:@"hw"]) {        NSLog(@"账号不存在");        return;    }       // 检测密码    if (![self.pwdText.text isEqualToString:@"123"]) {        NSLog(@"密码不正确");        return;    }       // 根据Segue ID 执行跳转    [self performSegueWithIdentifier:@"contactList" sender:nil];}
 
技术分享
 
b.使用第三方包实现登陆效果
技术分享
 
c.在登陆时,使用一个遮盖禁止用户操作
 1 /** 点击登陆 */ 2 - (IBAction)login { 3     // 检测账号 4     if (![self.accountText.text isEqualToString:@"hw"]) { 5         [MBProgressHUD showError:@"账号不存在"]; 6         return; 7     } 8     9     // 检测密码10     if (![self.pwdText.text isEqualToString:@"123"]) {11         [MBProgressHUD showError:@"密码错误"];12         return;13     }14    15     // 登陆中,遮盖屏幕,禁止用户进行其他操作16     [MBProgressHUD showMessage:@"正在使劲登录中..."];17    18     // 模拟登陆过程,延迟跳转19     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{20         // 移除遮盖21         [MBProgressHUD hideHUD];22        23         // 根据Segue ID 执行跳转24         [self performSegueWithIdentifier:@"contactList" sender:nil];25     });26 }
 
 
技术分享
 
d. 使用performSegueWithIndentifier:方法执行指定Segue
1         // 根据Segue ID 执行跳转2         [self performSegueWithIdentifier:@"contactList" sender:nil];
 
(3)记住密码 & 自动登陆
a.联动
<1> 取消记住密码,自动取消自动登陆
<2> 勾选了自动登陆,自动勾选记住密码
(使用storyboard拖线也可以完成)
 1 /** 点击记住密码 */ 2 - (IBAction)keepPwdSwitch { 3     if (!self.keepPwd.isOn) { 4         [self.autoLogin setOn:NO]; 5     } 6 } 7  8 /** 点击自动登陆 */ 9 - (IBAction)autoLoginSwitch {10     if (self.autoLogin.isOn) {11         [self.keepPwd setOn:YES];12     }13 }
 
(4)在跳转生效之前,传输数据,设置“联系人列表”标题
使用来源控制器的“prepareForSegue: sender:”方法(需要自行实现)
拿到目标控制器,设置数据
 
 
 
3.联系人列表
(1)注销
a.注销按钮及其功能
技术分享
 
b.提醒警告
使用UIActionSheet控件(这是一个从下往上弹出的底部弹窗控件)
控制器遵守 UIActionSheetDelegate 协议
 1 /** 点击注销 */ 2 - (IBAction)logout:(UIBarButtonItem *)sender { 3     UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"确定要注销?" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:nil, nil]; 4     5     [sheet showInView:self.view]; 6 } 7  8 #pragma mark - ActionSheet delegate function 9 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {10     if (buttonIndex != 0) return;11    12     // 弹出一个栈顶控制器,即本控制器,回到上一页13     [self.navigationController popViewControllerAnimated:YES];14 }
 
(2)添加联系人跳转
a.在右上角添加 “+” 按钮
技术分享
 
b.添加一个“添加联系人”控制器和界面
(下文)
 
4.添加联系人
(1)基础搭建
a.在“联系人列表”界面点击右上角加号跳转,使用自动Segue就可以了
技术分享
 
b.添加姓名、电话输入框
c."添加"按钮
 
技术分享
 
 
d.设置监听事件(姓名、电话和“添加”按钮的监听、事件处理,类似账号、密码和“登陆”按钮)
 1 - (void)viewDidLoad { 2     [super viewDidLoad]; 3     // Do any additional setup after loading the view. 4     5     // 设置“添加”按钮的激活状态 6     self.addButton.enabled = NO; 7     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.nameText]; 8     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.phoneText]; 9 }10  11 - (void)dealloc {12     // 取消订阅消息监听13     [[NSNotificationCenter defaultCenter] removeObserver:self];14 }15 16 /** 姓名、电话文本编辑消息处理 17 * 只有当姓名、电话不为空的时候才能使用“添加”按钮18 */19 - (void) textChange {20     self.addButton.enabled = self.nameText.text.length && self.phoneText.text.length;21 }
 
e.进入即自动弹出键盘
1 // 等界面完全显示完毕,再弹出键盘2 - (void)viewDidAppear:(BOOL)animated {3     [super viewDidAppear:animated];4    5     // 将焦点放在“姓名”输入框6     [self.nameText becomeFirstResponder];7 }
 
(2)数据返传
点击“添加”按钮,把数据传回给“联系人列表”
a.关闭当前控制器(“添加联系人”界面)
b.传递数据(使用代理)
设置源控制器(“联系人列表”控制器)为目标控制器(“添加联系人”控制器)的代理
点击“添加”按钮的时候,使用代理更改“联系人列表”的数据
 
AddViewController:
 1 /** 点击添加按钮 */ 2 - (IBAction)add { 3     // 1.关闭当前控制器 4     [self.navigationController popViewControllerAnimated:YES]; 5     6     // 2.使用模型传递数据给上一个控制器(ContactListViewController),使用代理通知数据更新 7     Contact *contact = [[Contact alloc] init]; 8     contact.name = self.nameText.text; 9     contact.phone = self.phoneText.text;10     [self.delegate addViewController:self didAddedContact:contact];11 }
 
c.“联系人列表”添加数据
ContactListTableViewController:
1 #pragma mark - AddViewController delegate function2 /** 添加联系人后,更新联系人列表数据 */3 - (void)addViewController:(AddViewController *)addViewController didAddedContact:(Contact *)contact {4     NSMutableArray *mcontacts = [NSMutableArray arrayWithArray:self.contacts];5     [mcontacts addObject:contact];6     self.contacts = mcontacts;7     [self.tableView reloadData];8 }
 
5.查看/编辑联系人
(1)拖入一个UIViewController作为“查看/编辑联系人”控制器
a.姓名、电话的TextField
b.“保存”按钮
c."编辑/取消" 按钮
技术分享
 
(2)跳转Segue设置
a.在“联系人列表”控制器中,指定storyboard的cell指定一个ID
技术分享
 
b.给上述的cell设置一个自动Segue,指向“查看/编辑联系人”控制器
技术分享
 
c.利用storyboard中已经绑定了ID的cell创建cell
ContactCell:
1 + (instancetype) cellWithTableView:(UITableView *) tableView {2     // cell ID 要在storyboard中设置好3     static NSString *ID = @"contactCell";4     // 先从缓存池寻找,如果找不到就从storyboard中创建一个5     return [tableView dequeueReusableCellWithIdentifier:ID];6 }
 
d.在“联系人列表”控制器的prepareForSegue方法中,根据目标控制器的类型,区分跳转向“添加联系人”控制器和“编辑联系人”控制器
ContactListTableViewController:
 1 #pragma mark - Segue相关 2 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 3     // 取得目标控制器 4     id controller = segue.destinationViewController; 5     6     // 判断跳转目标 7     if ([controller isKindOfClass:[AddViewController class]]) { 8         // 如果是“添加联系人” 9         AddViewController *addViewController = controller;10         addViewController.delegate = self;11     }12    13     if ([controller isKindOfClass:[EditViewController class]]) {14         // 如果是“查看/编辑联系人”15         EditViewController *editViewController = controller;16        17         // 取出数据18         NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];19         editViewController.contact = self.contacts[indexPath.row];20        21         // 设置代理22         editViewController.delegate = self;23     }24   25 }
 
(3)传输数据
不能在prepareForSegue中设置目标控制器的控件数据,因为目标控制器的view还没有加载
在目标控制器的viewDidLoad方法中做
EditViewController:
 1 - (void)viewDidLoad { 2     [super viewDidLoad]; 3     // Do any additional setup after loading the view. 4     5     // 加载数据 6     self.nameText.text = self.contact.name; 7     self.phoneText.text = self.contact.phone; 8     9     // 设置输入监听10     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.nameText];11     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:self.phoneText];12 }
 
(4)编辑(右上角加上一个“编辑”按钮)
a.激活输入框的编辑状态
b.激活“保存”按钮
c.弹出键盘
d.姓名和电话输入框同时为空的时候,保护“保存”按钮
 
技术分享
 
(5)取消编辑(进入“编辑”状态后,将“编辑”按钮转换成“取消”按钮)
a.改变“取消”按钮为“编辑”按钮
b.改变输入框为不可编辑
c.收回键盘
e.恢复数据
技术分享
 
 1 /** 点击“编辑”或"取消” */ 2 - (IBAction)editOrCancel:(UIBarButtonItem *)sender { 3     // 转变后的状态 4     BOOL isChangedToEditMode = [sender.title isEqualToString:@"编辑"]? YES:NO; 5     6     if (isChangedToEditMode) { 7         // 点击"编辑" 8         // 1.转变title 9         sender.title = @"取消";10        11         // 2.转变编辑状态12         self.nameText.enabled = YES;13         self.phoneText.enabled = YES;14         self.saveButton.hidden = NO;15        16         // 获得输入焦点17         [self.nameText becomeFirstResponder];18     } else {19         // 点击“取消”20         // 1.转变title21         sender.title = @"编辑";22        23         // 2.转变编辑状态24         self.nameText.enabled = NO;25         self.phoneText.enabled = NO;26         self.saveButton.hidden = YES;27        28         // 3.还原数据29         self.nameText.text = self.contact.name;30         self.phoneText.text = self.contact.phone;31        32         // 4.退出键盘33         [self.view endEditing:YES];34     }35    36 }37 38 /** 消息监听事件 */39 - (void) textChange {40     self.saveButton.enabled = self.nameText.text.length && self.phoneText.text.length;41 }
 
(6)保存,返回数据到“联系人列表”
使用代理,和“添加联系人”同理
a.关闭页面
b.传输数据
<1> 更新模型数据
<2> 使用代理方法修改模型数据
c.在“联系人列表”中刷新数据
1 #pragma mark - EditViewController delegate function2 /** “编辑联系人”的“保存”代理方法, 刷新数据 */3 - (void)editViewController:(EditViewController *)editViewController didSavedContact:(Contact *)contact {4     [self.tableView reloadData];5 }
 
6.自定义分割线
有数据的cell才显示分割线
(1)系统自带的分割线实际是一个高度只有1的UIVIew
(2)设置cell的样式为不带分割线,自行在返回的cell加上分割线
a.自定义一个集成UITableViewCell的类
技术分享
 
b.在storyboard设置cell的class为自定义的cell类
技术分享
 
c.重写cell的构造方法
1 + (instancetype) cellWithTableView:(UITableView *) tableView {2     // cell ID 要在storyboard中设置好3     static NSString *ID = @"contactCell";4     // 先从缓存池寻找,如果找不到就从storyboard中创建一个5     return [tableView dequeueReusableCellWithIdentifier:ID];6 }
 
注意:
<1> 从storyboard中创建的cell不会调用initWithStyle: reuseIndentifier:方法,但是也会调用awakeFromNib方法
==>
(1)就算重写initWithStyle: reuseIndentifier:,也不会被调用
(2)把创建分割线的逻辑放在awakeFromNib方法中
 
1 /**2 * 如果cell是通过storyboard或者xib创建,不会调用此方法3 * 如果使用代码创建cell,才会调用这个方法来初始化cell4 */5 - (instancetype) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {6     NSLog(@"initWithStyle");7     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];8     return self;9 }
 
<2> 由于在awakeFromNib中cell的frame还没被初始化(例如高度永远是44),所以重写layoutSubviews来设置分割线的frame
 1 /** 2 * 如果cell是通过storyboard或者xib创建,创建完毕会调用这个方法 3 * 可以在这里初始化cell 4 */ 5 - (void) awakeFromNib { 6     // 自定义一个分割线 7     UIView *divideLine = [[UIView alloc] init]; 8     [divideLine setBackgroundColor:[UIColor blackColor]]; 9     [divideLine setAlpha:0.2];10     [self.contentView addSubview:divideLine];11     self.divideLine = divideLine;12 }13 14 /**15 * 在此方法中,cell的frame确定被初始化完成,可以再这里初始化其子控件的frame16 */17 - (void)layoutSubviews {18     // 切记调用父类方法!19     [super layoutSubviews];20    21     CGFloat lineHeight = 1;22     CGFloat lineWidth = self.frame.size.width;23     CGFloat lineX = 0;24     CGFloat lineY = self.frame.size.height - 1;25    26     self.divideLine.frame = CGRectMake(lineX, lineY, lineWidth, lineHeight);27 }
 
7.持久化数据
有5种方式
  • xml属性列表(plist)归档
  • Preference(偏好设置)
  • NSKeyedArchiver归档
  • SQLite3数据库(关系型数据库)
  • Core Data
 
(1)“添加联系人”、“编辑联系人” 保存之后
a.使用plist保存联系人数据(账号、密码也可以用plist模拟实现)
 1 #pragma mark - AddViewController delegate function 2 /** 添加联系人后,更新联系人列表数据 */ 3 - (void)addViewController:(AddViewController *)addViewController didAddedContact:(Contact *)contact { 4     NSMutableArray *mcontacts = [NSMutableArray arrayWithArray:self.contacts]; 5     [mcontacts addObject:contact]; 6     self.contacts = mcontacts; 7     8     // 保存数据到plist文件 9     [self saveContactsDataToFile];10    11     // 刷新界面数据12     [self.tableView reloadData];13 }14 15 #pragma mark - EditViewController delegate function16 /** “编辑联系人”的“保存”代理方法, 刷新数据 */17 - (void)editViewController:(EditViewController *)editViewController didSavedContact:(Contact *)contact {18     // 保存数据19     [self saveContactsDataToFile];20     // 刷新数据21     [self.tableView reloadData];22 }23 24 #pragma mark - 加载、保存、读取数据25 /** 保存联系人数据到plist */26 - (void) saveContactsDataToFile {27     // 沙盒路径28     NSString *path = NSHomeDirectory();29     // Documents路径30     NSString *docPath = [path stringByAppendingPathComponent:@"Documents"];31     // plist文件路径32     NSString *filePath = [docPath stringByAppendingPathComponent:@"contacts.plist"];33    34     NSMutableArray *dictArray = [NSMutableArray array];35     for (Contact *contact in self.contacts) {36         // 将模型转换成字典进行存储37         NSDictionary *dict = [Contact dictionaryWithContact:contact];38         [dictArray addObject:dict];39     }40     [dictArray writeToFile:filePath atomically:YES];41     NSLog(@"save to : %@", filePath);42 }
 
b.进入“联系人”列表的时候读取数据
 1 /** 加载数据 */ 2 - (NSArray *) contacts { 3     if (nil == _contacts) { 4         // 沙盒路径 5         NSString *path = NSHomeDirectory(); 6         // Documents路径 7         NSString *docPath = [path stringByAppendingPathComponent:@"Documents"]; 8         // plist文件路径 9         NSString *filePath = [docPath stringByAppendingPathComponent:@"contacts.plist"];10        11         // 如果plist文件不存在12         NSFileManager *fileManager = [NSFileManager defaultManager];13         if (![fileManager fileExistsAtPath:filePath]) {14             _contacts = [NSArray array];15             return _contacts;16         }17        18         // 如果plist文件存在,开始读取19         NSArray *contacts = [NSArray arrayWithContentsOfFile:filePath];20         NSMutableArray *mcontacts = [NSMutableArray array];21         for (NSDictionary *dict in contacts) {22             Contact *contact = [Contact contactWithDictionary:dict];23             [mcontacts addObject:contact];24         }25        26         _contacts = mcontacts;27     }28    29     return _contacts;30 }
 
(2)使用preferences自动记住账号、密码
a.进入“登陆”界面,读取登陆状态数据
 1 /** 2 * 把初始化代码放在viewDidAppear 3 * 让view完全呈现之后才进行自动登陆,否则拿不到view,hideHUD的时候会失效 4 */ 5 - (void)viewDidAppear:(BOOL)animated { 6     // 设置登陆状态 7     [self readLoginStatus]; 8     9     // 初始化登陆按钮状态10     if (!self.accountText.text.length || !self.pwdText.text.length) {11         self.loginButton.enabled = NO;12     }13    14     // 登陆按钮开始监听账号、密码输入框15     [self loginButtonListening];16 }17  18 /** 读取登陆状态 */19 - (void) readLoginStatus {20     // 记住密码、自动登录开关状态21     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];22     self.keepPwd.on = [defaults boolForKey:@"keepPwd"]? YES:NO; // 防止键值对为nil23     self.autoLogin.on = [defaults boolForKey:@"autoLogin"]? YES:NO;24    25     // 账号、密码26     if (self.keepPwd.isOn) {27         self.accountText.text = [defaults objectForKey:@"account"];28         self.pwdText.text = [defaults objectForKey:@"pwd"];29     }30    31     // 自动登陆32     if (self.autoLogin.isOn) {33         [self login];34     }35 }
 
b.点击“登陆”保存登陆状态
 1 /** 点击登陆 */ 2 - (IBAction)login { 3     // 检测账号 4     if (![self.accountText.text isEqualToString:@"hw"]) { 5         [MBProgressHUD showError:@"账号不存在"]; 6         return; 7     } 8     9     // 检测密码10     if (![self.pwdText.text isEqualToString:@"123"]) {11         [MBProgressHUD showError:@"密码错误"];12         return;13     }14    15     // 登陆中,遮盖屏幕,禁止用户进行其他操作16     [MBProgressHUD showMessage:@"正在使劲登录中..."];17    18     // 模拟登陆过程,延迟跳转19     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{20         // 移除遮盖21         [MBProgressHUD hideHUD];22        23         // 根据Segue ID 执行跳转24         [self performSegueWithIdentifier:@"contactList" sender:nil];25     });26 27     // 保存登陆状态28     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];29     [defaults setBool:self.keepPwd.isOn forKey:@"keepPwd"];30     [defaults setBool:self.autoLogin.isOn forKey:@"autoLogin"];31    32     // 保存账号、密码信息33     if (self.keepPwd.isOn) {34         [defaults setObject:self.accountText.text forKey:@"account"];35         [defaults setObject:self.pwdText.text forKey:@"pwd"];36     }37 }
 
8.“自动登陆”的细节
(1)模拟登陆的遮盖消除问题
     在登陆控制器中,如果在viewDidLoad中调用登陆方法进行登陆,页面进入到“联系人列表”之后,遮盖的信息并不会隐藏,要在viewDidAppear中调用登陆方法,才能正常运行。
技术分享
 
(2)在“联系人列表”界面,点击“注销”回到“登陆”界面,依然会触发自动登陆
解决:设置一个私有变量保存自动登陆的许可状态,在非初次进入登陆界面的情况禁止自动登陆
 
 1 /** 自动登陆标识 */ 2 @property(nonatomic, assign) BOOL stopAutoLogin; 3   4 - (void)viewDidDisappear:(BOOL)animated { 5     // 当不是初次出现在屏幕上,禁止自动登陆 6     self.stopAutoLogin = YES; 7 } 8   9 /** 读取登陆状态 */10 - (void) readLoginStatus {11     // 记住密码、自动登录开关状态12     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];13     self.keepPwd.on = [defaults boolForKey:@"keepPwd"]? YES:NO; // 防止键值对为nil14     self.autoLogin.on = [defaults boolForKey:@"autoLogin"]? YES:NO;15    16     // 账号、密码17     if (self.keepPwd.isOn) {18         self.accountText.text = [defaults objectForKey:@"account"];19         self.pwdText.text = [defaults objectForKey:@"pwd"];20     }21    22     // 自动登陆23     if (!self.stopAutoLogin && self.autoLogin.isOn) {24         [self login];25     }26 }
 
9.删除数据
在“联系人列表”界面从右往左滑动记录,会弹出“删除”按钮
只需要实现一个tableView协议方法 commitEditingStyle,只需要实现这个方法就会出现“删除”按钮
 1 /** 2 * 如果实现了这个方法,就自动实现了滑动删除功能 3 * 点击了“删除”按钮就会调用 4 * 实质是提交了一个编辑操作导致调用(删除/添加/编辑) 5 * @param editingStyle 编辑行为 6 * @param indexPath 操作行号 7 */ 8 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 9     // 如果是删除操作10     if (editingStyle == UITableViewCellEditingStyleDelete) {11         // 1.删除数据12         NSMutableArray *marray = [NSMutableArray arrayWithArray:self.contacts];13         [marray removeObjectAtIndex:indexPath.row];14         self.contacts = marray;15       16         // 2.刷新界面17 //        [self.tableView reloadData];18         // 只删掉需要删除的一行,不必刷新所有数据19         // 使用这个方法,必须删除对应的模型数据,数量要对应20         [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];21        22         // 3.更改plist数据23         [self saveContactsDataToFile];24     }25 }
 
技术分享
 
 
10.编辑状态
在“联系人列表”界面,点击一个按钮,使所有联系人cell进入编辑状态
技术分享
 
a.添加一个“垃圾桶”按钮
 1 - (void)viewDidLoad { 2     [super viewDidLoad]; 3     4     // 设置无系统自带分割线 5     [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; 6     7     // 取出原来在storyboard中创建的“+”按钮 8     UIBarButtonItem *addItem = self.navigationItem.rightBarButtonItem; 9    10     // 创建一个“垃圾桶”按钮11     UIBarButtonItem *deleteItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(deleteCheck)];12    13     // 都放入到右边的状态栏14     self.navigationItem.rightBarButtonItems = @[deleteItem, addItem];15 }
 
b.编辑状态
1 // 点击状态栏按钮“垃圾桶”,使所有cell进入编辑状态或者退出编辑状态2 - (void) deleteCheck {3 //    self.tableView.editing = !self.tableView.editing;4     [self.tableView setEditing:!self.tableView.editing animated:YES];5 }
 
c.白边编辑状态的功能键
 1 // 改变编辑状态下的编辑按钮 2 - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { 3     if (indexPath.row == 0) { 4         // 这里改为“添加”符号,需要自定义事件 5         return UITableViewCellEditingStyleInsert; 6     } else if (indexPath.row == 1) { 7         // none就是什么都没有,没有作用 8         return UITableViewCellEditingStyleNone; 9     } else {10         // 默认就是“删除”11         return UITableViewCellEditingStyleDelete;12     }13 }
 
技术分享
 
 
 

[iOS基础控件 - 6.11.3] 私人通讯录Demo 控制器的数据传递、存储