1

I am missing something here, where I have a class, EditableCell, and protocol, EditableCellDelegate, defined for handling a table cell for editing. (The original code comes from "iPhone for Programmers" by Paul Deitel).

While I have imported the header for EditableCell into my file ClientEditTVC.h, the properties and methods of EditableCell are not recognized in ClientEditTVC.m.

Here is the prewritten code for EditableCell.h and .m:

#import <UIKit/UIKit.h>

@protocol EditableCellDelegate; // declare EditableCellDelegate Protocol

@interface EditableCell : UITableViewCell <UITextFieldDelegate>
{
   id <EditableCellDelegate> delegate; // this class's delegate
   UITextField *textField; // text field the user edits
   UILabel *label; // label on the left side of the cell
} // end instance variables declaration

// declare textField as a property
@property (nonatomic, retain) UITextField *textField;

// declare label as a property
@property (readonly, retain) UILabel *label;

//declare delegate as a property
@property (nonatomic, assign) id <EditableCellDelegate> delegate;

- (void)setLabelText:(NSString *)text; // set the text of label
- (void)clearText; // clear all the text out of textField
@end // end interface EditableCell

@protocol EditableCellDelegate // protocol for the delegate

// called when the user begins editing a cell
- (void)editableCellDidBeginEditing:(EditableCell *)cell;

// called when the user stops editing a cell
- (void)editableCellDidEndEditing:(EditableCell *)cell;

// called when the user touches the Done button on the keyboard
- (void)editableCellDidEndOnExit:(EditableCell *)cell;
@end // end protocol EditableCellDelegate

And

#import "EditableCell.h"
@implementation EditableCell

@synthesize textField; // synthesize get and set methods for delegate
@synthesize label; // synthesize get and set methods for delegate
@synthesize delegate; // synthesize get and set methods for delegate

// initialize the cell
- (id)initWithStyle:(UITableViewCellStyle)style
    reuseIdentifier:(NSString *)reuseIdentifier
{
   // call the superclass
   if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]))
   {
      // create the label on the left side
      label = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 0, 20)];

      // create the text field to the right of the label
      textField =
         [[UITextField alloc] initWithFrame:CGRectMake(0, 10, 0, 20)];

      [textField setDelegate:self]; // set the delegate to this object

      // call textFieldDidEndOnExit when the Done key is touched
      [textField addTarget:self action:@selector(textFieldDidEndOnExit)
          forControlEvents:UIControlEventEditingDidEndOnExit];
      [self.contentView addSubview:label]; // add label to the cell
      [self.contentView addSubview:textField]; // add textField to cell
   } // end if

   return self; // return this Editable cell
} // end method initWithFrame:reuseIdentifier:

// method is called when the user touches the Done button on the keyboard
- (void)textFieldDidEndOnExit
{
   [textField resignFirstResponder]; // make the keyboard go away
   [delegate editableCellDidEndOnExit:self]; // call the delegate method
} // end method textFieldDidEndOnExit

// set the text of the label
- (void)setLabelText:(NSString *)text
{
   label.text = text; // update the text

   // get the size of the passed text with the current font
   CGSize size = [text sizeWithFont:label.font];
   CGRect labelFrame = label.frame; // get the frame of the label
   labelFrame.size.width = size.width; // size the frame to fit the text
   label.frame = labelFrame; // update the label with the new frame

   CGRect textFieldFrame = textField.frame; // get the frame of textField

   // move textField to 30 pts to the right of label
   textFieldFrame.origin.x = size.width + 30;

   // set the width to fill the remainder of the screen
   textFieldFrame.size.width =
   self.frame.size.width - textFieldFrame.origin.x;
   textField.frame = textFieldFrame; // assign the new frame
} // end method setLabelText:

// clear the text in textField
- (void)clearText
{
   textField.text = @""; // update textField with an empty string
} // end method clearText

// delegate method of UITextField, called when a text field begins editing
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
   [delegate editableCellDidBeginEditing:self]; // inform the delegate
} // end method textFieldDidBeginEditing:

// delegate method of UITextField, called when a text field ends editing
- (void)textFieldDidEndEditing:(UITextField *)textField
{
   [delegate editableCellDidEndEditing:self]; // inform the delegate
} // end method textFieldDidEndEditing:

// free EditableCell's memory
- (void)dealloc
{
  [textField release]; // release the textField UITextField
  [label release]; // release the label UILabel
  [super dealloc]; // call the superclass's dealloc method
} // end method dealloc
@end // end EditableCell class definition

And here is the relevant code from ClientEditTVC.h and .m

#import <UIKit/UIKit.h>
#import "EditableCell.h"


@interface ClientEditTVC : UITableViewController <UITableViewDataSource, EditableCellDelegate> {
    NSArray *fields;
    NSMutableDictionary *data;
    BOOL keyboardShown;
    EditableCell *currentCell;
}


@end

and

#import "ClientEditTVC.h"


@implementation ClientEditTVC

// stuff here

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[EditableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell...
    // get the key for the given index path
    NSString *key =
    [fields objectAtIndex:indexPath.row + indexPath.section * 3];
    [cell setLabelText:key]; // update the cell text with the key

    // update the text in the text field with the value
    //cell.textField.text = [data valueForKey:key];


    return cell;
}

// more stuff here

@end

I get a warning at the line [cell setLabelText:key]; that UITableViewCell may not respond to 'setTableText'. But tracing though with breakpoints, the setTextField code in EditableCell is being executed.

The line (commented out) for cell.textField.text produces an error, Property 'textField' not found on object of type 'UITableViewCell'

Obviously the compiler is not seeing that I have subclassed UITableViewCell, and I'm not sure why. It's even stranger, to me, that the setLableText method is getting executed. I went back to the sample code provided by Deitel, and these problems don't occur. I have looked my code over carefully, and can't seen any significant difference.

I would appreciate suggestions on what I am overlooking.

Jim
  • 5,940
  • 9
  • 44
  • 91

3 Answers3

2

You declared cell like this:

UITableViewCell *cell;

So it is not an EditableCell. If you declare it like so:

EditableCell *cell;

it will not give you the warnings. It will probably warn that you're assigning a UITableViewCell to cell, but you can "fix" that using a cast, i.e.

EditableCell *cell = (EditableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

Also, you need to adjust the return type of the function. This should eliminate all compiler warnings.

mvds
  • 45,755
  • 8
  • 102
  • 111
  • Thanks, that did it. I'm glad it was so simple. I should be able to see this if it occurs again. – Jim Apr 10 '11 at 22:36
1

Redeclare cell as a EditableCell * instead of a UITableViewCell * and that warning should go away.

Jason
  • 28,040
  • 10
  • 64
  • 64
0
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[EditableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

// Configure the cell...
// get the key for the given index path
    NSString *key = [fields objectAtIndex:indexPath.row + indexPath.section * 3];
    [cell setLabelText:key]; // update the cell text with the key

    if ([cell isKindOfClass:[EditableCell class]]) {
        EditableCell* editableCell = (EditableCell*)cell;
// update the text in the text field with the value
        editableCell.textField.text = [data valueForKey:key];
    }
    else {
        assert(0 && "is it alright that this instance is not an EditableCell?");
    }

    return cell;
}
justin
  • 104,054
  • 14
  • 179
  • 226