史上最全的iOS之訪問(wèn)自定義cell的textField.text的N種方法

前言

問(wèn)題背景:自定義cell中有一個(gè)UITextField類型的子控件。我們經(jīng)常要在tableView中拿到某個(gè)cell內(nèi)textField的文本內(nèi)容進(jìn)行一些操作。比如某些app的注冊(cè)界面就是以tableView的形式存在的,注冊(cè)時(shí)往往需要注冊(cè)姓名、昵稱、郵箱、地址、聯(lián)系方式等信息。然后點(diǎn)擊注冊(cè)或者提交,這些信息就會(huì)被提交到遠(yuǎn)程服務(wù)器。有人說(shuō),注冊(cè)頁(yè)面就那么固定的幾行cell,沒(méi)必要搞得那么復(fù)雜,完全可以用靜態(tài)cell實(shí)現(xiàn)。但還有一些情況,當(dāng)前頁(yè)面的tableView的cell的行數(shù)是不確定的(比如當(dāng)前頁(yè)面顯示多好行cell由上一個(gè)頁(yè)面決定或者由用戶決定),這種情況下不太適合使用靜態(tài)cell。也不能夠通過(guò)分支語(yǔ)句的方式一一枚舉出各個(gè)case。所以需要一中通用的動(dòng)態(tài)的方法。那么我們?cè)趺丛趖ableView中準(zhǔn)確的拿到每一行cell中textField的text呢?以下我將要分四個(gè)方法分別介紹并逐一介紹他們的優(yōu)缺點(diǎn),大家可以在開(kāi)發(fā)中根據(jù)實(shí)際情況有選擇的采用不同的方法。
如下圖,就是我之前開(kāi)發(fā)的一個(gè)app中用xib描述的一個(gè)cell,當(dāng)用戶點(diǎn)擊“注冊(cè)”或者“提交”button時(shí)候,我需要在控制器中拿到諸如“法人姓名”這一類的信息:

cellWithXib.png

四個(gè)方法告訴你如何在tableView中拿到每一個(gè)cell中的textField.text
四個(gè)方法分別如下:

  • 通過(guò)控制器的textField屬性來(lái)拿到每一個(gè)cell內(nèi)textField.text
  • 通過(guò)系統(tǒng)默認(rèn)發(fā)送的通知來(lái)拿到每一個(gè)cell內(nèi)textField.text
  • 通過(guò)自定義的通知來(lái)拿到每一個(gè)cell內(nèi)textField.text
  • 通過(guò)block來(lái)拿到每一個(gè)cell內(nèi)textField.text

方法一(方法1請(qǐng)略過(guò))

1.cell的.h文件聲明一個(gè)IBOutlet的屬性,使其和xib描述的cell中的textField進(jìn)行關(guān)聯(lián)。
1.在tableViewController.m的類擴(kuò)展中聲明為每一個(gè)cell的textField都聲明一個(gè)UITextField類型的屬性,一一對(duì)應(yīng)。
2.在cellForRowAtIndexPath:數(shù)據(jù)源方法中給控制器的每個(gè)UITextField類型屬性賦值為cell.textField。

TableViewCell.h文件中的contentTextField引用xib中的textField:

#import <UIKit/UIKit.h>

@interface TableViewCell : UITableViewCell
/**
 *  cell的標(biāo)題
 */
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;

/**
 *  cell的文本框
 */
@property (weak, nonatomic) IBOutlet UITextField *contentTextField;
@end

控制器中聲明UITextField類型的屬性。

@interface YQBInfoViewController ()
/**
 *  標(biāo)題
 */
@property(nonatomic, strong) NSArray *titles;
/**
 *  占位文字
 */
@property(nonatomic, strong) NSArray *placeHolders;

/**
 *  姓名
 */
@property(nonatomic, weak) UITextField *nameTextField;

/**
 *  年齡
 */
@property(nonatomic, weak) UITextField *ageTextField;

/**
 *  地址
 */
@property(nonatomic, weak) UITextField *addressTextField;
@end

數(shù)據(jù)源方法cellForRowAtIndexPath:中給控制器的UITextField類型屬性賦值。

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

    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    // 在這里把每個(gè)cell的textField 賦值給 事先聲明好的UITextField類型的屬性
    // 以后直接操作控制器的這些屬性就可以拿到每個(gè)textField的值
    switch (indexPath.row) {
        case 0:
            // 姓名
            self.nameTextField = cell.contentTextField;
            break;
        case 1:
            // 年齡
            self.ageTextField = cell.contentTextField;
            break;
        case 2:
            // 地址
            self.addressTextField = cell.contentTextField;
            break;
        default:
            break;
    }
    
    return cell;
}

但是,這個(gè)方法還是有一些小問(wèn)題,因?yàn)閏ell被重用時(shí),存在存在的內(nèi)容錯(cuò)亂的現(xiàn)象。有人說(shuō),因?yàn)槲覀冊(cè)赾ellForRowAtIndexPath用一個(gè)UITextField屬性引用了cell的contentTextfield,我們可以在willDisplayCell:方法中對(duì)cell的contentTextField的內(nèi)容再次配置回來(lái)。而事實(shí)上,因?yàn)閏ell此時(shí)被重用了,所以,我們的tableViewController的那些分別指向每一行cell的UITextField的屬性此時(shí)也指向了其他行。所以,這個(gè)方法對(duì)于cell存在重用的情況是不適合的!

以下是方法一的demo地址

方法二(發(fā)送系統(tǒng)通知)

我們知道UITextField內(nèi)容改變時(shí)會(huì)發(fā)送通知。與UITextField相關(guān)的通知有三個(gè),如下:

UIKIT_EXTERN NSString *const UITextFieldTextDidBeginEditingNotification;
UIKIT_EXTERN NSString *const UITextFieldTextDidEndEditingNotification;
UIKIT_EXTERN NSString *const UITextFieldTextDidChangeNotification;

1.我們只需要讓tableVeiw控制器注冊(cè)UITextFieldTextDidChangeNotification/UITextFieldTextDidEndEditingNotification通知。
2.在數(shù)據(jù)源方法cellForRowAtIndexPath:中對(duì)cell.textField.tag賦值為indexPath.row。這樣就可以區(qū)分每一行的textField。
3.然后在監(jiān)聽(tīng)到通知后調(diào)用的方法中,根據(jù)textField.tag拿到textField的內(nèi)容。

但是,問(wèn)題來(lái)了,如果tableView是grouped樣式的呢?這樣就有可能存在兩個(gè)textField具有相同的tag!所以,以上提供的思路只適用于plained樣式的tableView。grouped樣式的tableView建議用下面的方法。
解決方法:自定義textField,給textField添加NSIndexPath類型的屬性indexPath。我們這次給textField的indexPath賦值而不是tag。這樣就可以在監(jiān)聽(tīng)到通知后調(diào)用的方法中,根據(jù)indexPath來(lái)區(qū)分不同的section和row。

自定義UITextField

#import <UIKit/UIKit.h>

@interface CustomTextField : UITextField
/**
 *  indexPath屬性用于區(qū)分不同行cell
 */
@property (strong, nonatomic) NSIndexPath *indexPath;
@end

注意:如果你自定義的cell是用xib描述的,不要忘記給cell的textField指定類型為你自定義的textField,此例中我自定義的是CustomTextField,如下圖:

Snip20160503_2.png

控制器注冊(cè)通知

// 注冊(cè)通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentTextFieldDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];

給自定義的textField的indexPath屬性賦值

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    AliyunSalesUnifiedEditCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    
    // 如果不止一個(gè)section,那么傳遞indexPath.row有可能沖突
    // cell.contentTextField.tag = indexPath.row;

    // 所以傳遞indexPath,相當(dāng)于把section也傳遞給contentTextField
    cell.contentTextField.indexPath = indexPath;
    return cell;
}

監(jiān)聽(tīng)到通知后調(diào)用的方法

// 在這個(gè)方法中,我們就可以通過(guò)自定義textField的indexPath屬性區(qū)分不同行的cell,然后拿到textField.text
- (void)contentTextFieldDidEndEditing:(NSNotification *)noti {
    CustomTextField *textField = noti.object;
    if (textField.indexPath.section == 0) {
        NSString *text = textField.text;
        NSInteger row =textField.indexPath.row;
        
        if (text && text.length) {
            [self.contents replaceObjectAtIndex:row withObject:text];
        }
    } else if (textField.indexPath.section == 1) {
        // 同上,請(qǐng)自行腦補(bǔ)
    } else if (textField.indexPath.section == 2) {
        // 同上,請(qǐng)自行腦補(bǔ)
    } else {
        // 同上,請(qǐng)自行腦補(bǔ)
    }
}

切記:對(duì)于cell的重用,當(dāng)在willDisplayCell方法中重新配置cell時(shí)候,有if,就必須有else。因?yàn)橹捌聊簧铣霈F(xiàn)的cell離開(kāi)屏幕被緩存起來(lái)時(shí)候,cell上的內(nèi)容并沒(méi)有清空,當(dāng)cell被重用時(shí),系統(tǒng)并不會(huì)給我們把cell上之前配置的內(nèi)容清空掉,所以我們?cè)趀lse中對(duì)contentTextField內(nèi)容進(jìn)行重新配置或者清空(根據(jù)自己的業(yè)務(wù)場(chǎng)景而定)

以下是方法二的demo地址

方法三(發(fā)送自定義通知)

其實(shí)方法三和方法二很像,都需要給自定義的textField添加indexPath屬性,也需要發(fā)送通知,然后在通知中心對(duì)這個(gè)通知注冊(cè)監(jiān)聽(tīng)。區(qū)別在于,方法二發(fā)送的是系統(tǒng)自帶的通知UITextFieldTextDidEndEditingNotification,而方法三將要發(fā)送自定義通知。
1>給CustomTextField添加indexPath屬性。
2>給自定義cell添加CustomTextField類型contentTextField屬性。
3>cell遵守UITextFieldDelegate協(xié)議,成為textField屬性的delegate。
4>cell實(shí)現(xiàn)協(xié)議方法-textFieldDidEndEditing:(UITextField *)textField
5>textFieldDidEndEditing:協(xié)議方法中發(fā)送一個(gè)自定義的通知,并且把textField.text通過(guò)userInfo字典發(fā)出去。

具體實(shí)現(xiàn)代碼:

給CustomTextField添加indexPath屬性

#import <UIKit/UIKit.h>

@interface CustomTextField : UITextField
/**
 *  indexPath屬性用于區(qū)分不同的cell
 */
@property (strong, nonatomic) NSIndexPath *indexPath;
@end

給自定義cell添加CustomTextField類型contentTextField屬性

#import <UIKit/UIKit.h>
@class CustomTextField;

@interface TableViewCell : UITableViewCell
/**
 *  cell的標(biāo)題
 */
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;

/**
 *  cell的文本框
 */
@property (weak, nonatomic) IBOutlet CustomTextField *contentTextField;

@end

遵守協(xié)議,設(shè)置delegate,實(shí)現(xiàn)協(xié)議方法

#import "TableViewCell.h"
#import "CustomTextField.h"

@interface TableViewCell ()<UITextFieldDelegate>

@end

@implementation TableViewCell
- (void)awakeFromNib {
    [super awakeFromNib];
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    self.contentTextField.delegate = self;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 使contentTextField聚焦變成第一響應(yīng)者
    [self.contentTextField becomeFirstResponder];
    
}

#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField
{
    NSDictionary *userInfo = @{
                               @"textFieldText":self.contentTextField.text
                               };
    [[NSNotificationCenter defaultCenter] postNotificationName:@"CustomTextFieldDidEndEditingNotification" object:self.contentTextField userInfo:userInfo];
}

6>控制器注冊(cè)并監(jiān)聽(tīng)該通知
7>在監(jiān)聽(tīng)到通知的方法中通過(guò)userInfo拿到textField的text屬性
8>- (void)viewWillDisappear:(BOOL)animated方法中移除監(jiān)聽(tīng)
9>完畢

注冊(cè)通知

// 如果不能保證控制器的dealloc方法肯定會(huì)被調(diào)用,不要在viewDidLoad方法中注冊(cè)通知。
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
   
    // 注意:此處監(jiān)聽(tīng)的通知是:UITextFieldTextDidEndEditingNotification,textField結(jié)束編輯發(fā)送的通知,textField結(jié)束編輯時(shí)才會(huì)發(fā)送這個(gè)通知。
    // 想實(shí)時(shí)監(jiān)聽(tīng)textField的內(nèi)容的變化,你也可以注冊(cè)這個(gè)通知:UITextFieldTextDidChangeNotification,textField值改變就會(huì)發(fā)送的通知。
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cellTextFieldDidEndEditing:) name:@"CustomTextFieldDidEndEditingNotification" object:nil];
    
    //    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentTextFieldDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];
}

移除通知


- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    // 在這個(gè)方法里移除通知,因?yàn)椋?    // 防止控制器被強(qiáng)引用導(dǎo)致-dealloc方法沒(méi)有調(diào)用
    // 其他界面也有textField,其他界面的textField也會(huì)發(fā)送同樣的通知,導(dǎo)致頻繁的調(diào)用監(jiān)聽(tīng)到通知的方法,而這些通知是這個(gè)界面不需要的,所以在視圖將要消失的時(shí)候移除通知 同樣,在視圖將要顯示的時(shí)候注冊(cè)通知
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"CustomTextFieldDidEndEditingNotification" object:nil];
}

接收到通知回調(diào)方法

// 接收到注冊(cè)監(jiān)聽(tīng)的通知后調(diào)用
- (void)cellTextFieldDidEndEditing:(NSNotification *)noti {
    CustomTextField *textField = noti.object;
    if (!textField.indexPath) {
        return;
    }
    
    NSString *userInfoValue = [noti.userInfo objectForKey:@"textFieldText"];
    NSLog(@"text:%@,userInfoValue:%@",textField.text,userInfoValue);
    // 如果涉及到多個(gè)section,可以使用二維數(shù)組,此處不再贅述
    if (textField.indexPath.section == 0) {
        [self.contents replaceObjectAtIndex:textField.indexPath.row withObject:userInfoValue];

    } else if (textField.indexPath.section == 1) {
        // 同上,請(qǐng)自行腦補(bǔ)
    } else if (textField.indexPath.section == 2) {
        // 同上,請(qǐng)自行腦補(bǔ)
    } else {
        // 同上,請(qǐng)自行腦補(bǔ)
    }
}

切記:對(duì)于cell的重用,當(dāng)在willDisplayCell方法中重新配置cell時(shí)候,有if,就必須有else。因?yàn)橹捌聊簧铣霈F(xiàn)的cell離開(kāi)屏幕被緩存起來(lái)時(shí)候,cell上的內(nèi)容并沒(méi)有清空,當(dāng)cell被重用時(shí),系統(tǒng)并不會(huì)給我們把cell上之前配置的內(nèi)容清空掉,所以我們?cè)趀lse中對(duì)contentTextField內(nèi)容進(jìn)行重新配置或者清空(根據(jù)自己的業(yè)務(wù)場(chǎng)景而定)

以下是方法三的demo地址
方法三相對(duì)于方法二的好處在于:方法三發(fā)送的是自定義通知,而方法二發(fā)送的是系統(tǒng)自帶的通知。
因?yàn)轫?xiàng)目開(kāi)發(fā)中,受項(xiàng)目復(fù)雜度影響,難免會(huì)出現(xiàn)不同的控制器界面都會(huì)有UITextField類型(或者其子類型)的對(duì)象而沒(méi)有釋放,當(dāng)textField開(kāi)始編輯、內(nèi)容發(fā)生改變、結(jié)束編輯時(shí),都會(huì)發(fā)送相同的通知。此時(shí)如果我們采用監(jiān)聽(tīng)系統(tǒng)自帶的通知的方法,就有可能監(jiān)聽(tīng)到我們不需要的改變從而影響了業(yè)務(wù)數(shù)據(jù)。
舉個(gè)例子:A和B控制器都是UITableViewController類型的對(duì)象,A、B控制器界面上都有UITextField類型(或者其子類型)的子控件。并且A、B控制器都注冊(cè)了系統(tǒng)自帶的UITextField的通知UITextFieldTextDidChangeNotification,且監(jiān)聽(tīng)到通知后都會(huì)調(diào)用各自的contentTextFieldTextDidChange:方法。當(dāng)A控制器pushB控制器后,我們?cè)贐控制器界面上的TextField編輯內(nèi)容,A控制器此時(shí)也監(jiān)聽(tīng)了該通知,所以,A控制器上的contentTextFieldTextDidChange:方法也會(huì)被調(diào)用。這是我們不想得到的,所以,采用自定義通知的方法可以避免這一問(wèn)題。
當(dāng)然,我們也可以在viewWillAppear:方法中注冊(cè)通知,然后在viewWillDisAppear:方法中移除通知,這樣同樣可以避免這一為題。
另外,值得提醒的是,如果我們不能保證控制器被pop時(shí)肯定會(huì)調(diào)用dealloc方法,那么建議在控制器的viewWillDisAppear:方法中移除通知,而非dealloc方法中移除。否則,用戶反復(fù)push、pop控制器時(shí),控制器可能會(huì)注冊(cè)多份相同的通知。

方法四(使用block)

1>給cell添加一個(gè)block屬性,該block屬性帶有一個(gè)NSString *類型的參數(shù)。
2>給cell的textField添加target,觸發(fā)方法的事件是UIControlEventEditingChanged
3>textField觸發(fā)的方法中調(diào)用cell的這個(gè)block屬性,并把contentTextField.text作為block的參數(shù)傳進(jìn)去
4>數(shù)據(jù)源方法cellForRowAtIndexPath:中對(duì)cell的block屬性賦值(也就是拿到cell.contentTextField.text)
5>數(shù)據(jù)源方法willDisplayCell:中對(duì)cell重新配置。

給cell添加一個(gè)block屬性

#import <UIKit/UIKit.h>

@interface TableViewCell : UITableViewCell
/**
 *  block 參數(shù)為textField.text
 */

@property (copy, nonatomic) void(^block)(NSString *);
/**
 *  cell的標(biāo)題
 */

@property (weak, nonatomic) IBOutlet UILabel *titleLabel;

/**
 *  cell的文本框
 */
@property (weak, nonatomic) IBOutlet UITextField *contentTextField;

@end

給textField addTarget
在事件觸發(fā)方法中調(diào)用block并傳遞參數(shù)

#import "TableViewCell.h"

@interface TableViewCell ()

@end

@implementation TableViewCell

- (void)awakeFromNib {
    [super awakeFromNib];
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    [self.contentTextField addTarget:self action:@selector(textfieldTextDidChange:) forControlEvents:UIControlEventEditingChanged];
// 注意:不是 UIControlEventValueChanged
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.contentTextField becomeFirstResponder];
}

#pragma mark - private method
- (void)textfieldTextDidChange:(UITextField *)textField
{
    self.block(self.contentTextField.text);
}
@end

在cellforRowAtIndexPath:方法中為每個(gè)cell的block賦值

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

    TableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    __weak typeof(self) weakSelf = self;
    if (indexPath.section == 0) {
        customCell.block = ^(NSString * text) {
            // 更新數(shù)據(jù)源
            [weakSelf.contents replaceObjectAtIndex:indexPath.row withObject:text];
        };
    } else if (indexPath.section == 1) {
        // 同上,請(qǐng)自行腦補(bǔ)
    } else {
        // 同上,請(qǐng)自行腦補(bǔ)
    }
    return customCell;
}

在willDisplayCell:方法中對(duì)cell進(jìn)行配置:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    TableViewCell *customCell = (TableViewCell *)cell;
    customCell.titleLabel.text = self.titles[indexPath.row];
    customCell.contentTextField.placeholder = self.placeHolders[indexPath.row];
    if (indexPath.section == 0) {
        customCell.contentTextField.text = [self.contents objectAtIndex:indexPath.row];
        // 必須有else!
    } else {
        // 切記:對(duì)于cell的重用,有if,就必須有else。因?yàn)橹捌聊簧铣霈F(xiàn)的cell離開(kāi)屏幕被緩存起來(lái)時(shí)候,cell上的內(nèi)容并沒(méi)有清空,當(dāng)cell被重用時(shí),系統(tǒng)并不會(huì)給我們把cell上之前配置的內(nèi)容清空掉,所以我們?cè)趀lse中對(duì)contentTextField內(nèi)容進(jìn)行重新配置或者清空(根據(jù)自己的業(yè)務(wù)場(chǎng)景而定)
        customCell.contentTextField.text = [NSString stringWithFormat:@"第%ld組,第%ld行",indexPath.section,indexPath.row];
    }
}

切記:對(duì)于cell的重用,當(dāng)在willDisplayCell方法中重新配置cell時(shí)候,有if,就必須有else。因?yàn)橹捌聊簧铣霈F(xiàn)的cell離開(kāi)屏幕被緩存起來(lái)時(shí)候,cell上的內(nèi)容并沒(méi)有清空,當(dāng)cell被重用時(shí),系統(tǒng)并不會(huì)給我們把cell上之前配置的內(nèi)容清空掉,所以我們?cè)趀lse中對(duì)contentTextField內(nèi)容進(jìn)行重新配置或者清空(根據(jù)自己的業(yè)務(wù)場(chǎng)景而定)

以下是方法四的demo地址
方法四相對(duì)于方法二和方法三的好處在于:方法四沒(méi)有采用通知的方式來(lái)獲取contentTextField.text,而是采用靈活的block。并且方法四也無(wú)需自定義textField。

方法五(使用delegate實(shí)現(xiàn))

方法五和方法四很像,只不過(guò)方法五采用了delegate方式,更好的做到了解耦。
0>和方法二、方法三一樣,cell的textField屬性都需要使用自定義類型,因?yàn)槲覀冃枰otextField綁定indexPath屬性。
1>給cell制定一份協(xié)議,協(xié)議中有一個(gè)方法,帶有兩個(gè)參數(shù),一個(gè)是textField的text,另一個(gè)是indexPath。同時(shí)給cell添加一個(gè)delegate屬性。
2>給cell的textField添加target,觸發(fā)方法的事件是UIControlEventEditingChanged
3>textField觸發(fā)的方法中調(diào)用cell的協(xié)議方法,并把contentTextField.indexPath作為協(xié)議方法的參數(shù)傳進(jìn)去
4>數(shù)據(jù)源方法cellForRowAtIndexPath:中對(duì)cell的indexPath賦值為當(dāng)前的indexPath。對(duì)cell的delegate賦值為當(dāng)前controller
5>控制器實(shí)現(xiàn)cell的協(xié)議方法,在協(xié)議方法里可以拿到textField的文本。
6>在tableView:willDisplayCell:forRowAtIndexPath:方法內(nèi)刷新tableView。

#import <UIKit/UIKit.h>
@class CustomTextField;
@protocol CustomCellCellDelegate <NSObject>

@required
// cell 的contentTextField的文本發(fā)生改變時(shí)調(diào)用
- (void)contentDidChanged:(NSString *)text forIndexPath:(NSIndexPath *)indexPath;

@end
@interface TableViewCell : UITableViewCell
/**
 *  cell的標(biāo)題
 */
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;

/**
 *  cell的文本框
 */
@property (weak, nonatomic) IBOutlet CustomTextField *contentTextField;
/**
 *  delegate
 */
@property (weak, nonatomic) id<CustomCellCellDelegate> delegate;

cell.m文件


- (void)awakeFromNib {
    [super awakeFromNib];
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    [self.contentTextField addTarget:self action:@selector(contentDidChanged:) forControlEvents:UIControlEventEditingChanged];
}

- (void)contentDidChanged:(id)sender {
    // 調(diào)用代理方法,告訴代理,哪一行的文本發(fā)生了改變
    if (self.delegate && [self.delegate respondsToSelector:@selector(contentDidChanged:forIndexPath:)]) {
        [self.delegate contentDidChanged:self.contentTextField.text forIndexPath:self.contentTextField.indexPath];
    }
}

controller.m


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

    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    cell.contentTextField.indexPath = indexPath;
    cell.delegate = self;
    return cell;
}
// cell的代理方法中拿到text進(jìn)行保存
- (void)contentDidChanged:(NSString *)text forIndexPath:(NSIndexPath *)indexPath {
    [self.contents replaceObjectAtIndex:indexPath.row withObject:text];
}
// 更新UI
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    TableViewCell *customCell = (TableViewCell *)cell;
    customCell.titleLabel.text = self.titles[indexPath.row];
    customCell.contentTextField.placeholder = self.placeHolders[indexPath.row];
    customCell.contentTextField.text = self.contents[indexPath.row];
}

以下是方法五的demo地址
文/VV木公子(簡(jiǎn)書作者)
PS:如非特別說(shuō)明,所有文章均為原創(chuàng)作品,著作權(quán)歸作者所有,轉(zhuǎn)載轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),并注明出處,所有打賞均歸本人所有!
如果您是iOS開(kāi)發(fā)者,請(qǐng)關(guān)注本人,或者對(duì)本篇文章感興趣,請(qǐng)點(diǎn)擊喜歡,后續(xù)會(huì)更新更多相關(guān)文章!敬請(qǐng)期待!

如果有技術(shù)問(wèn)題,歡迎加入QQ群進(jìn)行交流,群聊號(hào)碼:194236752。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 概述在iOS開(kāi)發(fā)中UITableView可以說(shuō)是使用最廣泛的控件,我們平時(shí)使用的軟件中到處都可以看到它的影子,類似...
    liudhkk閱讀 9,090評(píng)論 3 38
  • *7月8日上午 N:Block :跟一個(gè)函數(shù)塊差不多,會(huì)對(duì)里面所有的內(nèi)容的引用計(jì)數(shù)+1,想要解決就用__block...
    炙冰閱讀 2,547評(píng)論 1 14
  • 一.UITextField屬性 0.enablesReturnKeyAutomatically 默認(rèn)為No,如果設(shè)...
    奮斗ing0310閱讀 1,688評(píng)論 0 2
  • 我只是在此處重述一個(gè)在我的夢(mèng)境中真實(shí)發(fā)生的故事。 時(shí)間,黃梅時(shí)節(jié)。地點(diǎn),一個(gè)拍攝古裝的電影城。人物,一個(gè)男人和...
    不耕田的牛閱讀 273評(píng)論 0 0
  • 韓建河山的封板是預(yù)料之外的,因?yàn)槲腋静恢浪菚?huì)漲還是會(huì)跌。 雄安繼續(xù)成為資金的戰(zhàn)場(chǎng),有分化,有沖高。龍頭是操作...
    天涯別院閱讀 216評(píng)論 0 0