バックグラウンド
_tableViewという名前のUITableViewivarを持つクラスがあります。このクラスは、UITableViewDatasourceとUITableViewDelegate_tableViewを実装します。UITableViewセルは、FormTableCellのインスタンスです。FormTableCellは、UILabelとUITextFieldを持つUITableViewCellのサブクラスです。クラスには、textFieldDelegateというプロパティがあります。tableView:cellForIndexPath:が呼び出されると、現在のtextFieldDelegateが返されたセルのtextFieldプロパティに割り当てられます。また、クラスtextFieldDelegateが変更されたときに、セルのテキストフィールドのデリゲートを更新したいと思います。私はこれを行うための3つの方法を考え出しましたが、最善の方法がわかりません。
- 表示されている各セルのデリゲートを新しいtextFieldDelegateで更新します。
- すべてのセルを繰り返し処理し、新しいtextFieldDelegateを割り当てます
- tableViewsデータをリロードします。
オプション1は適切ですが、tableViewのvisibleCells配列にないセルを表示する前に、tableView:cellForIndexPathが呼び出されることを前提としています。これが起こらない場合は、セルごとにデリゲートが異なる可能性があり、それは私が望んでいることではありません。
オプション2は、セルの数が少ない場合にのみ適切に機能するため、最悪です。FormTablesのセルの数が常に少ないことを願っていますが、私にはわかりません。
オプション3は、非表示のセルを表示する前にtableView:cellForIndexPath:が呼び出されるという私の仮定が無効であり、セルが多いテーブルを処理するため、オプション2よりも優先される場合にオプション1よりも優先されます。
質問
どちらが最良のオプションであり、非表示のセルが表示されるか、正しく操作されない前にtableView:cellForIndexPath:が呼び出されるという私の仮定はどれですか?
コード
- (void)setTextFieldDelegate:(id<UITextFieldDelegate>)textFieldDelegate
{
if(_textFieldDelegate != textFieldDelegate) {
_textFieldDelegate = textFieldDelegate;
//Update _textFieldDelegate for all visible cells.
//!DEV: Assuming non-visible cells will be recreated with tableView:cellForIndexPath:
for (FormTableCell *cell in [_tableView visibleCells]) {
[[cell textField] setDelegate:_textFieldDelegate];
}
//!DEV: This will potentially generate memory issues for a large number of cells
for(NSUInteger i = 0; i < kNumberOfFields; ++i) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:(NSInteger)i inSection:0];
FormTableCell *cell = (FormTableCell*)[_tableView cellForRowAtIndexPath:indexPath];
[[cell textField] setDelegate:_textFieldDelegate];
}
//!DEV: Maybe this is the best method, but it requires the recreation of visibleCells.
[_tableView reloadData];
}
}
最終ステータス
だから、これが私がやったことです。デコレートデリゲート(?)を実装しました
- (void)setTextFieldDelegate:(id<UITextFieldDelegate>)textFieldDelegate
{
if(_textFieldDelegate != textFieldDelegate) {
_textFieldDelegate = textFieldDelegate;
}
}
#pragma mark - UITextFieldDelegate Implementation
//This class forwards UITextFieldDelegate methods on to _textFieldDelegate, if implemented.
//Provides default functionality is not implemented.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if([_textFieldDelegate respondsToSelector:@selector(textFieldShouldBeginEditing:)]) {
return [_textFieldDelegate textFieldShouldBeginEditing:textField];
} //implicit else
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
//Setup _closeKeyboardButton behind _tableView
//view::closeKeyboardButton (_closeKeyboardButton)
NSAssert(_closeKeyboardButton == nil, @"!DEV: Thought _closeKeyboardButton would always be nil here.");
if(_closeKeyboardButton != nil) {
[_closeKeyboardButton removeFromSuperview];
_closeKeyboardButton == nil;
}
CGRect closeKeyboardFrame = {CGPointZero, [self frame].size};
UIButton *closeKeyboardButton = [UIButton buttonWithType:UIButtonTypeCustom];
[closeKeyboardButton setFrame:closeKeyboardFrame];
[closeKeyboardButton addTarget:self
action:@selector(_closeKeyboardButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
[self insertSubview:closeKeyboardButton belowSubview:_tableView];
_closeKeyboardButton = closeKeyboardButton;
if([_textFieldDelegate respondsToSelector:@selector(textFieldDidBeginEditing:)]) {
[_textFieldDelegate textFieldDidBeginEditing:textField];
}
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if([_textFieldDelegate respondsToSelector:@selector(textFieldShouldEndEditing:)]) {
return [_textFieldDelegate textFieldShouldEndEditing:textField];
} //implicit else
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if([_textFieldDelegate respondsToSelector:@selector(textFieldDidBeginEditing:)]) {
[_textFieldDelegate textFieldDidBeginEditing:textField];
}
//Tear down _closeKeyboardButton
NSAssert(_closeKeyboardButton != nil, @"!DEV: Thought _closeKeyboardButton would always exist here.");
[_closeKeyboardButton removeFromSuperview];
_closeKeyboardButton = nil;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if([_textFieldDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
return [_textFieldDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
} //implicit else
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
if([_textFieldDelegate respondsToSelector:@selector(textFieldShouldClear:)]) {
return [_textFieldDelegate textFieldShouldClear:textField];
} //implicit else
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if([_textFieldDelegate respondsToSelector:@selector(textFieldShouldReturn:)]) {
return [_textFieldDelegate textFieldShouldReturn:textField];
} //implicit else
return NO;
}