記一次解決跨控制器監聽開關狀態改變的嘗試。
為了統一設置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 }
總結思路:
- 涉及到跨控制器數據訪問時首先考慮代理模式;
- 當類的繼承關系復雜時一定要縷清關系:什么事在基類里統一做,什么事在子類里單獨做。