How to set the accessory view of a table cell to save a previously initialized UIImageView?

Let's say I have a property in my view controller, which is defined as follows:

@property (nonatomic, retain) UIImageView *checkmarkOffAccessoryView; 

I @synthesize this in the implementation, release in -dealloc and initialize it in -viewDidLoad as follows:

 self.checkmarkOffAccessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]] autorelease]; 

So far so good.

When I use it in my table view view as an auxiliary view for multiple cells, two things happen:

  • Only one kind of cellular accessory shows an image
  • The user interface of the application freezes.

The application does not crash because, as far as I can tell, the user interface simply stops responding. This is both in the simulator and on the device.

This is how I use the initialized property with my cell:

 - (UITableViewCell *) tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { // initialize or dequeue cell... if (condition) cell.accessoryView = self.checkmarkOffAccessoryView; else cell.accessoryView = nil; } 

Using the above code, only one cell shows the appearance of the accessory, and the user interface freezes.

If I initialize the UIImageView instance directly in the delegate method, I get all the UIImageView cells showing the appearance of the accessories, and I don't experience the user interface freezing:

 - (UITableViewCell *) tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { // initialize or dequeue cell... if (condition) cell.accessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]] autorelease]; else cell.accessoryView = nil; } 

My goal is to initialize as few objects as possible and reuse one UIImageView . I am curious why the first piece of code is problematic and what I can do to fix it.

It seems that the cell accessoryView property should just increment the retain self.checkmarkOffAccessoryView counter, but it seems like I'm missing some details.

What did I forget? Thank you for your advice.

EDIT

I think that:

 self.checkmarkOffAccessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]] autorelease]; 

matches with:

 UIImageView *uncheckedView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]]; self.checkmarkOffAccessoryView = uncheckedView; [uncheckedView release]; 

In any case, I experience the same symptom of freezing.

+7
iphone uitableview uiimageview
source share
4 answers

You cannot add the same view multiple times. The user interface handler will be launched. To make sure of this, I tried to do what you said above, and I got the same problem. The user interface freezes, the image appears only for one of the cells.

The best you can do is save the image as a dedicated UIImage and have a helper function that returns a new UIImageView for each cell.

Using your current method (without a stored UIImage), you can do:

 -(UIImageView *) makeCheckmarkOffAccessoryView { return [[[UIImageView alloc] initWithImage: [UIImage imageNamed:@"checkmarkOff.png"]] autorelease]; } 

And then do

 cell.accessoryView = [self makeCheckmarkOffAccessoryView]; 

As you know, UIImages, on the other hand, can be used any number of times. UIImageView does not take up much space, so you can easily get a bunch of those who are not worried.

To expand only one place, imagine you are adding a UIView to two places at a time.

What will [ob removeFromSuperview] do for this object? Will this remove the view from both places? From one of them only? What value will be returned upon request [ob superview]? Obviously, the user interface is not designed to handle what you ask.

+9
source share

Try this without auto-advertisement in the initializer. I suspect you are reissuing.

By the way, your console probably shows a BAD_ACCESS error when it freezes. If you enable NSZombieEnabled, I think you will see that it accesses the freed UIImage.

0
source share

maybe this will help

 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"ShoppingListCell"; HSShoppingListCell *cell = (HSShoppingListCell *)[aTableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { [[NSBundle mainBundle] loadNibNamed:@"ShoppingListCell" owner:self options:nil]; cell = shoppingListCell; } ShoppingListItem *theItem = nil; theItem = [self.fetchedResultsController objectAtIndexPath:indexPath]; UIImage *selected = [UIImage imageNamed:@"listBullet_checked.png"]; UIImage *notSelected = [UIImage imageNamed:@"listBullet.png"]; cell.imageView.image = ([theItem.checkedOff boolValue] ? selected : notSelected); cell.shoppingListLabel.text = theItem.productName; [cell.shoppingListLabel setFont:[UIFont fontWithName:@"Marker Felt" size:26.0]]; return cell; } - (void)toggleCellImage:(NSIndexPath *)indexPath { ShoppingListItem *item = [self.fetchedResultsController objectAtIndexPath:indexPath]; item.checkedOff = ([item.checkedOff boolValue] ? [NSNumber numberWithBool:NO] : [NSNumber numberWithBool:YES]); [HSCoreDataUtilities saveContext:item.managedObjectContext]; [self.tableView reloadData]; } #pragma mark - #pragma mark Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self toggleCellImage:indexPath]; [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; } 
0
source share

Shortening your business to simple objects (I was going to suggest placing two "thin" UIView around a UIImageView ...), I found that this was most likely impossible.

Create 2 empty UIView in IB, hook them up to bareView1 and bareView2 . Then

 UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"test.png"]]; [bareView1 addSubview:imageView]; // it shows either here ... [bareView2 addSubview:imageView]; // ... or here 

You can never get an image on sceen more than once like this. As a rule, I think that the first object in a line that is not inherited from UIView can be used several times, i.e. UIImage . As Calle said, a UIView can only have one parent in a view hierarchy.

addSubview second addSubview only results in a UIImageView transitioning from bareView1 to bareView2 .

The freezing occurs, perhaps because the processing of events is confused: an accessory can be interactive, how would you know which one was used if they are the same object? Thus, the code assumes that the objects are unique, and you manage to violate this assumption.

0
source share

All Articles