UITableViewCell with UITextField


Gerriet M. Denkmann
 

iOS 12, Xcode 10

I have a subclass of UITableViewController.

The UITableView should use UITableViewCells with UITextFields (for data entry).

So I created MyTableViewCellWithTextField which has:
@property IBOutlet UITextField *textField;
Changed the class of the Prototype Cell to MyTableViewCellWithTextField
added a UITextField to the ContentView and tried to connect the outlet to this textField.

But no luck.

So I have to do:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellId forIndexPath: indexPath];

UITextField *badHack = cell.contentView.subviews.firstObject;
badHack.keyboardType = …
badHack. placeholder = …
badHack. text = …
}

But I have a nagging feeling that this is *not* quite the right way.

What should I do instead ?

Gerriet.


Alex Zavatone
 

Use an XIB for the subclass of tableViewCell, create a UIOutlet property for the UITextField, assign the subclass to the XIB’s class and wire up the UIOutlet property to the UITextField. Don’t forget to give the UITableViewCell an Identifier keyword.

Make sure to set the tableView to register the subclass for the cell if needed. I can dig up my working source, but it will be about 8 hours.

On Sep 26, 2018, at 2:25 AM, Gerriet M. Denkmann <g@mdenkmann.de> wrote:

iOS 12, Xcode 10

I have a subclass of UITableViewController.

The UITableView should use UITableViewCells with UITextFields (for data entry).

So I created MyTableViewCellWithTextField which has:
@property IBOutlet UITextField *textField;
Changed the class of the Prototype Cell to MyTableViewCellWithTextField
added a UITextField to the ContentView and tried to connect the outlet to this textField.

But no luck.

So I have to do:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellId forIndexPath: indexPath];

UITextField *badHack = cell.contentView.subviews.firstObject;
badHack.keyboardType = …
badHack. placeholder = …
badHack. text = …
}

But I have a nagging feeling that this is *not* quite the right way.

What should I do instead ?

Gerriet.




Gerriet M. Denkmann
 

On 26 Sep 2018, at 14:30, Alex Zavatone via Groups.Io <zav=mac.com@groups.io> wrote:

Use an XIB for the subclass of tableViewCell, create a UIOutlet property for the UITextField, assign the subclass to the XIB’s class and wire up the UIOutlet property to the UITextField. Don’t forget to give the UITableViewCell an Identifier keyword.

Make sure to set the tableView to register the subclass for the cell if needed. I can dig up my working source, but it will be about 8 hours.

@interface TextTableCell : UITableViewCell
@property IBOutlet UITextField *textField;
@end


TableCellView.xib

File’s Owner = TextTableCell
Outlet textField = UITextField

View UIView contains
TextTableCell
Content View
UITextField


MyTableViewController

- (void)viewDidLoad
{
[super viewDidLoad];
UINib *nib = [ UINib nibWithNibName: @"TableCellView" bundle: nil ];
[ self.tableView registerNib: nib forCellReuseIdentifier: kTextCell ];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
NSLog(@"%s will dequeueReusableCellWithIdentifier: \"%@\"",__FUNCTION__, cellId);
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellId forIndexPath: indexPath];
}


Result:

[tableView:cellForRowAtIndexPath:] will dequeueReusableCellWithIdentifier: "Cell with TextField"
*** Terminating app due to uncaught exception ‘NSUnknownKeyException', reason: '[<NSObject 0x6000032aeb80> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key textField.'

0 CoreFoundation 0x000000010251129b __exceptionPreprocess + 331
1 libobjc.A.dylib 0x0000000101a51735 objc_exception_throw + 48
2 CoreFoundation 0x0000000102510e09 -[NSException raise] + 9
3 Foundation 0x000000010147e0b4 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 292
4 UIKitCore 0x0000000105176ada -[UIRuntimeOutletConnection connect] + 109
5 CoreFoundation 0x00000001024fcddd -[NSArray makeObjectsPerformSelector:] + 317
6 UIKitCore 0x00000001050906d1 -[UINib instantiateWithOwner:options:] + 1814
7 UIKitCore 0x00000001052ded16 -[UITableView _dequeueReusableViewOfType:withIdentifier:] + 611


I guess my TableCellView.xib is not quite right (or rather: absolutely messed up).
How to fix this?

Gerriet.


Alex Zavatone
 

Try adding nonatomic and strong to your property.

@property (nonatomic, strong) IBOutlet UITextField *textField;

Also, did you set the XIB in the storyboard to your subclass and drag the UITextField to your property?

On Sep 26, 2018, at 4:25 AM, Gerriet M. Denkmann <g@mdenkmann.de> wrote:



On 26 Sep 2018, at 14:30, Alex Zavatone via Groups.Io <zav=mac.com@groups.io> wrote:

Use an XIB for the subclass of tableViewCell, create a UIOutlet property for the UITextField, assign the subclass to the XIB’s class and wire up the UIOutlet property to the UITextField. Don’t forget to give the UITableViewCell an Identifier keyword.

Make sure to set the tableView to register the subclass for the cell if needed. I can dig up my working source, but it will be about 8 hours.

@interface TextTableCell : UITableViewCell
@property IBOutlet UITextField *textField;
@end


TableCellView.xib

File’s Owner = TextTableCell
Outlet textField = UITextField

View UIView contains
TextTableCell
Content View
UITextField


MyTableViewController

- (void)viewDidLoad
{
[super viewDidLoad];
UINib *nib = [ UINib nibWithNibName: @"TableCellView" bundle: nil ];
[ self.tableView registerNib: nib forCellReuseIdentifier: kTextCell ];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
NSLog(@"%s will dequeueReusableCellWithIdentifier: \"%@\"",__FUNCTION__, cellId);
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellId forIndexPath: indexPath];
}


Result:

[tableView:cellForRowAtIndexPath:] will dequeueReusableCellWithIdentifier: "Cell with TextField"
*** Terminating app due to uncaught exception ‘NSUnknownKeyException', reason: '[<NSObject 0x6000032aeb80> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key textField.'

0 CoreFoundation 0x000000010251129b __exceptionPreprocess + 331
1 libobjc.A.dylib 0x0000000101a51735 objc_exception_throw + 48
2 CoreFoundation 0x0000000102510e09 -[NSException raise] + 9
3 Foundation 0x000000010147e0b4 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 292
4 UIKitCore 0x0000000105176ada -[UIRuntimeOutletConnection connect] + 109
5 CoreFoundation 0x00000001024fcddd -[NSArray makeObjectsPerformSelector:] + 317
6 UIKitCore 0x00000001050906d1 -[UINib instantiateWithOwner:options:] + 1814
7 UIKitCore 0x00000001052ded16 -[UITableView _dequeueReusableViewOfType:withIdentifier:] + 611


I guess my TableCellView.xib is not quite right (or rather: absolutely messed up).
How to fix this?

Gerriet.




Gerriet M. Denkmann
 

On 26 Sep 2018, at 20:21, Alex Zavatone via Groups.Io <zav=mac.com@groups.io> wrote:

Try adding nonatomic and strong to your property.

@property (nonatomic, strong) IBOutlet UITextField *textField;

Also, did you set the XIB in the storyboard to your subclass and drag the UITextField to your property?
I found a solution without an extra xib file: just using a Prototype Cell in the tableView.

Class: MyTableViewCell
Style: Custom
Identifier: “Cell with TextField”

The Prototype Cell has in it’s Connections Inspector an Outlet named “textField”;
Control-Drag from the empty circle at the right to the UITextField.

This Control-Dragging from the Connections Inspector was a new trick (for me). Took me a while to find this.



On Sep 26, 2018, at 4:25 AM, Gerriet M. Denkmann <g@mdenkmann.de> wrote:



On 26 Sep 2018, at 14:30, Alex Zavatone via Groups.Io <zav=mac.com@groups.io> wrote:

Use an XIB for the subclass of tableViewCell, create a UIOutlet property for the UITextField, assign the subclass to the XIB’s class and wire up the UIOutlet property to the UITextField. Don’t forget to give the UITableViewCell an Identifier keyword.

Make sure to set the tableView to register the subclass for the cell if needed. I can dig up my working source, but it will be about 8 hours.

@interface TextTableCell : UITableViewCell
@property IBOutlet UITextField *textField;
@end


TableCellView.xib

File’s Owner = TextTableCell
Outlet textField = UITextField

View UIView contains
TextTableCell
Content View
UITextField


MyTableViewController

- (void)viewDidLoad
{
[super viewDidLoad];
UINib *nib = [ UINib nibWithNibName: @"TableCellView" bundle: nil ];
[ self.tableView registerNib: nib forCellReuseIdentifier: kTextCell ];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
NSLog(@"%s will dequeueReusableCellWithIdentifier: \"%@\"",__FUNCTION__, cellId);
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellId forIndexPath: indexPath];
}


Result:

[tableView:cellForRowAtIndexPath:] will dequeueReusableCellWithIdentifier: "Cell with TextField"
*** Terminating app due to uncaught exception ‘NSUnknownKeyException', reason: '[<NSObject 0x6000032aeb80> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key textField.'

0 CoreFoundation 0x000000010251129b __exceptionPreprocess + 331
1 libobjc.A.dylib 0x0000000101a51735 objc_exception_throw + 48
2 CoreFoundation 0x0000000102510e09 -[NSException raise] + 9
3 Foundation 0x000000010147e0b4 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 292
4 UIKitCore 0x0000000105176ada -[UIRuntimeOutletConnection connect] + 109
5 CoreFoundation 0x00000001024fcddd -[NSArray makeObjectsPerformSelector:] + 317
6 UIKitCore 0x00000001050906d1 -[UINib instantiateWithOwner:options:] + 1814
7 UIKitCore 0x00000001052ded16 -[UITableView _dequeueReusableViewOfType:withIdentifier:] + 611


I guess my TableCellView.xib is not quite right (or rather: absolutely messed up).
How to fix this?

Gerriet.






Alex Zavatone
 

On Sep 26, 2018, at 9:41 AM, Gerriet M. Denkmann <g@mdenkmann.de> wrote:



On 26 Sep 2018, at 20:21, Alex Zavatone via Groups.Io <zav=mac.com@groups.io> wrote:

Try adding nonatomic and strong to your property.

@property (nonatomic, strong) IBOutlet UITextField *textField;

Also, did you set the XIB in the storyboard to your subclass and drag the UITextField to your property?
I found a solution without an extra xib file: just using a Prototype Cell in the tableView.

Class: MyTableViewCell
Style: Custom
Identifier: “Cell with TextField”

The Prototype Cell has in its Connections Inspector an Outlet named “textField”;
Control-Drag from the empty circle at the right to the UITextField.
Yeah, that’s what I meant by making the class of the XIB to be your class and making the identifier your identifier. Granted, I probably wasn’t super clear at that time of the morning. That control dragging was what I meant by “wire up”.

This Control-Dragging from the Connections Inspector was a new trick (for me). Took me a while to find this.
Yeah, the control dragging is SUPER non-intiutive, ESPECIALLY when considering that it will not work if you try and drag from the storyboard item over to empty circle next to your property - even though that is the thing that changes its appearance once it is connected. : /

You have to drag over the name of the property for the connection to stick.

Knowing how long someone can spend trying to determine how to do this, I’m sorry I wasn’t able to be clearer.


The reason I opt to use XIBs for this is that if you are working on a team where many people will have their hands in the storyboard, this removes the potential of any merge conflicts and that’s just one less thing to worry about.

Glad that it works for you in any case and happy to help.

Cheers,
Alex Zavatone