tags:

views:

1867

answers:

5

Okay so Here's my issue. I have a table, a bit like Apple's addressBook.app that uses different cell subclasses to display information in different ways. On this particular app I have 3 different UiTableViewCell subclasses, all with their own nibs.

I can't get the code right :-( if I try and access the instance variable of my cell in the CellForRowPath method it says' (ERROR request for member 'type' in something not a structure or union') Now I assume that the word 'something' is the root of my problem.. The code I am about to paste obviously doesn't setup my cell properly. Here is the code:

There are 3 if statements to get the right cell subclass depending on the section being called:

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

static NSString *PoolFacilityCellIdentifier = @"PoolFacilityCellIdentifier";
static NSString *PoolFacilityAddressCellIdentifier = @"PoolFacilityAddressCellIdentifier";
static NSString *PoolFacilityPoolCellIdentifier = @"PoolFacilityPoolCellIdentifier";
NSUInteger section = indexPath.section;

//Creat a generic container for cell which will be cast during one of the next two statements
id cell;

//Change the identifier depending on cell type. MIGHT NEED TO ADD SOMETHING ELSE FOR POOLS AND PRICES
if (section == KAddressIndex) {
 cell = (PoolFacilityAddressCell *)[tableView dequeueReusableCellWithIdentifier:PoolFacilityAddressCellIdentifier];

 if (cell == nil) {

  //Load the appropriate nib for the type of cell being asked for.

   NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"PoolFacilityAddressCell" owner:self options:nil];

   for (id object in nib) {

    if ([object isMemberOfClass:[PoolFacilityAddressCell class]]) 
     cell = (PoolFacilityAddressCell *) object;

   }
 }

}
else if (section == KPoolIndex) {
 cell = (PoolFacilityPoolCell *)[tableView dequeueReusableCellWithIdentifier:PoolFacilityPoolCellIdentifier];

 if (cell == nil) {

  //Load the appropriate nib for the type of cell being asked for.

  NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"PoolFacilityPoolCell" owner:self options:nil];

  for (id object in nib) {

   if ([object isMemberOfClass:[PoolFacilityPoolCell class]]) 
    cell = (PoolFacilityPoolCell *) object;


  }
 }
}
else {
 cell = (PoolFacilityCell *)[tableView dequeueReusableCellWithIdentifier:PoolFacilityCellIdentifier];

 if (cell == nil) {

  //Load the appropriate nib for the type of cell being asked for.

  NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"PoolFacilityCell" owner:self options:nil];

  for (id object in nib) {

   if ([object isMemberOfClass:[PoolFacilityCell class]]) 
    cell = (PoolFacilityCell *) object;
  }
 }

}

Any help would be greatly appreciated!!! I import all the header files for my cell subclasses.

The code that throws my error is this (specifically the cell.type.text = thePool.type) cell.type is an Iboutlet UiLabel:

if (section == KPoolIndex) {

 NSMutableArray *thePools = [allSections objectForKey:sectionAsNumber];

 if ([thePools count] > 0) {
  [cell setPromptMode:NO];
  //Set the label and Pool from the Pool Object
  Pool *thePool = [thePools objectAtIndex:row];
  cell.type.text = thePool.type;


 }

}

Thanks,

Dan

+1  A: 

Matt Gallagher has an article that lays out a cleaner way to accomplish this type of table. He breaks out the cell specific code into their own classes. Makes it alot easier to manage.

cocoawithlove.com - Heterogeneous cells in a UITableViewController

In your code, this line looks like trouble

cell.type.text = thePool.type;

thePool is a "Pool" object, does it have a property named "type" ? Check that the @property and @synthesize are setup correctly for "type" in your "Pool" object.

Ryan Townshend
Thanks Matt. I've had a look at this and will attempt to digest it :-)
Dan Morgan
The problem I see with the approach at that link, is to me it seems to muddy up the clear MVC separation possible with the standard format - in particular, with the PhoneNumbers example what happens if you want a PhoneNumberCellController in multiple tables with slightly different cell types?
Kendall Helmstetter Gelner
Also, for simple uses it disperses responsibility across too many classes - having to move the table row selection out of the view controller and into what is really a data object at heart...
Kendall Helmstetter Gelner
I am working on a table today that has 7 different breeds of cell in it. Using an arch based on this article is what is going to have it done by 5 today. For the next one I am thinking of adding a CellControllerActionDelegate so I can reuse views without duplication.
Ryan Townshend
+1  A: 

I believe it may be due to the fact that your cell is declared as id and you're trying to access a property off one of your cell subclasses. You can send all the messages you want to an object of type id, but trying to access properties on an object of type id will fail at compile time. Also, be sure to import the .h files containing your subclasses.

drewh
A: 

I might have a few answers to my own question:

1 - As drew has mentioned the cell remains of type ID. I thought my following if functions would typeCast the cell into being a specific cell type but that doesn't seem to be the case.

2 - A solution would be to have 3 big if statements for each type of cell. Each if statement ending in a

return cell;

call.

3 - The solution I'm going to try now is to have only one cell subclass instead of 3 and have a method in my cell subclass called

-(void)setCellBehaviour:(int)definedNumber

That way I can hide layers/labels etc and customize it how I wish.

update

I've achieved the required results like this:

I only have one cell subclass which has a single NIB with many different UIlabels.

I call this in the cellForRowAtIndexPath: method of my uiviewcontroller, once the cell has been alloc/init.

//Set the behaviour
    [cell setCellBehaviour:KCellBehaviourName];

This references the definitions I set in the header file of the view controller:

//Definitions for cell type behaviour. Passed to cell during creation.

(HASH)define KCellBehaviourStandard 0 (HASH)define KCellBehaviourName 1 (HASH)define KCellBehaviourAddress 2 (HASH)define KCellBehaviourPool 3

(Cant seem to do hashes in this post)

Then my UITableViewCellSubclass has this methos which we called earlier:

-(void)setCellBehaviour:(NSUInteger)definedBehaviour {

switch (definedBehaviour) {
    case KCellBehaviourStandard:
        self.label.hidden = NO;
        self.value.hidden = NO;
        self.length.hidden = YES;
        self.poolType.hidden = YES;
        break;
    case KCellBehaviourName:
        self.label.hidden = NO;
        self.value.hidden = NO;
        self.length.hidden = YES;
        self.poolType.hidden = NO;
        break;
    case KCellBehaviourAddress:
        self.label.hidden = NO;
        self.value.hidden = NO;
        self.length.hidden = YES;
        self.poolType.hidden = YES;
        break;
    case KCellBehaviourPool:
        self.label.hidden = NO;
        self.value.hidden = NO;
        self.length.hidden = NO;
        self.poolType.hidden = YES;
    default:
        break;
}

}

Dan Morgan
+1  A: 

Oh my goodness this is much simpler than all of the answers are making it appear. I'm not going to discuss your overall design, just focus on why your code is not working.

This is the line that is triggering the error:

cell.type.text = thePool.type;

You can fix it by replacing that with these lines:

PoolFacilityCell* poolCell = (PoolFacilityCell *)cell;
poolCell.type.text = thePool.type;

The dot-syntax for accessing properties only works if the compiler knows what class you are working with. It can't deal with cell.type because cell is declared as type id, so at compile time it doesn't know that type is supposed to be an Objective-C property. The error message calls it "something not a structure or union" because it thinks you are treating cell like a plain C struct, which it is not, hence the error.

Incidentally, the lines where you write:

cell = (PoolFacilityAddressCell *) object;

are meaningless. Since cell is declared as id (any generic object), there is no need for the cast. Based on an earlier comment, you seem to think that type casting like that affects the cell variable somehow. It does not. The line above compiles into instructions that simply copy the memory address of the instance from object to cell. Type casting is there to avoid warnings and errors at compile time.

benzado
A: 

CGRect frame = cell.contentView.bounds; frame.origin.x = frame.origin.x + 10.0f;

    UILabel *textLabel = [[UILabel alloc] initWithFrame:frame];
    [textLabel setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
    textLabel.tag = 1;
    textLabel.textAlignment = UITextAlignmentLeft;
    textLabel.backgroundColor = [UIColor clearColor];
    textLabel.textColor = [UIColor blackColor];
    textLabel.font = [UIFont boldSystemFontOfSize:20.0];
    textLabel.numberOfLines = 1;
    textLabel.highlightedTextColor = [UIColor whiteColor];
    [cell.contentView addSubview:textLabel];
    [textLabel release];