iOS:使用代理模式监听开关状态改变事件

记一次解决跨控制器监听开关状态改变的尝试。

  为了统一设置UITableViewCell里的内容,自定义了UITableViewCell类的一个基类,命名为SettingCell。SettingCell里显示的内容由数据模型SettingItem提供:在SettingCell里定义一个属性即可。

@property (nonatomic, strong) SettingItem *item;

  再定义几个SettingItem的子类表示显示不同内容的Cell(如图1).由于所有开关状态的归档和解档都一样,故统一在父类SettingItem里实现。但是点击“手势密码”后跳转到下一个控制(如图2)后,需要单独监听手势密码开关的状态,这就涉及到了跨控制器监听开关状态改变事件的问题。我首先想到了代理模式。

                                       

                                                        图1                                                             图2

  首先在SettingCell.h里声明代理方法和属性:

 1 #import <UIKit/UIKit.h>
 2 
 3 @class SettingItem, SettingCell;
 4 
 5 @protocol SettingCellDelegate <NSObject>
 6 
 7 @optional
 8 
 9 // 监听开关状态改变
10 - (void)settingCell:(SettingCell *)cell switchChanged:(UISwitch *)switchView;
11 
12 @end
13 
14 @interface SettingCell : UITableViewCell
15 
16 // 存放模型数据
17 @property (nonatomic, strong) SettingItem *item;
18 
19 @property (nonatomic, assign, getter = isLastRowInSection) BOOL lastRowInSection;
20 
21 + (instancetype)cellWithTableView:(UITableView *)tableView;
22 
23 // 定义代理属性
24 @property (nonatomic, weak) id<SettingCellDelegate> delegate;
25 
26 @end

  然后,在SettingCell.m里初始化开关并注册ValueChanged事件,在switchStateChange:方法里调用代理方法传递开关状态:

 1 - (UISwitch *)switchView
 2 {
 3     if (_switchView == nil) {
 4         _switchView = [[UISwitch alloc] init];
 5         [_switchView addTarget:self action:@selector(switchStateChange:) forControlEvents:UIControlEventValueChanged];
 6     }
 7     return _switchView;
 8 }
 9 
10 /**
11  *  监听开关状态改变
12  */
13 - (void)switchStateChange:(UISwitch *)switchView
14 {
15 //    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
16 //    [defaults setBool:self.switchView.isOn forKey:self.item.title];
17 //    [defaults synchronize];
18     if ([self.delegate respondsToSelector:@selector(settingCell:switchChanged:)]) {
19         [self.delegate settingCell:self switchChanged:switchView];
20     }
21     
22     [CoreArchive setBool:self.switchView.isOn key:self.item.title];
23 }

  最后,在图2的控制器里实现代理方法:

1 - (void)settingCell:(SettingCell *)cell switchChanged:(UISwitch *)switchView
2 {
3     NSLog(@"手势密码开关状态改变了-------------------");
4 }

  但是发现点击开关后并没有发现打印结果,窘迫~

  检查代理模式的使用方法后发现是没有设置SettingCell的代理为当前控制器(GestureViewController)。问题又来了,在图2的控制器里我根本拿不到SettingCell,无奈只好追本溯源,发现这个控制器又是继承自自定义的一个控制器(BaseSettingViewController),故在父类控制器里的Cell初始化方法里设置代理为当前控制器即可(下面代码第11行)。于是开心地看到打印结果鸟!

 1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 2 {
 3     // 1.创建cell
 4     SettingCell *cell = [SettingCell cellWithTableView:tableView];
 5     
 6     // 2.给cell传递模型数据
 7     SettingGroup *group = self.data[indexPath.section];
 8     cell.item = group.items[indexPath.row];
 9     cell.lastRowInSection =  (group.items.count - 1 == indexPath.row);
10     // 设置代理
11     cell.delegate = self;
12     // 3.返回cell
13     return cell;
14 }

总结思路:

  • 涉及到跨控制器数据访问时首先考虑代理模式;
  • 当类的继承关系复杂时一定要缕清关系:什么事在基类里统一做,什么事在子类里单独做。
原文地址:https://www.cnblogs.com/yif1991/p/5162603.html