Как установить вспомогательное представление ячейки табличного представления, чтобы сохранить ранее инициализированный UIImageView? - PullRequest
7 голосов
/ 07 июля 2010

Допустим, у меня есть свойство в контроллере представления, определенное следующим образом:

@property (nonatomic, retain) UIImageView *checkmarkOffAccessoryView;

I @synthesize это в реализации, release это в -dealloc и инициализация его в -viewDidLoad следующим образом:

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

Пока все хорошо.

Когда я использую его в моем делегате табличного представления в качестве вспомогательного представления для нескольких ячеек, происходят две вещи:

  1. Изображение только одной ячейки показывает изображение
  2. Интерфейс приложения зависает.

Приложение не падает, насколько я могу судить, пользовательский интерфейс просто перестает отвечать на запросы.Это как в симуляторе, так и на устройстве.

Вот как я использую инициализированное свойство с моей ячейкой:

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

    // initialize or dequeue cell...

    if (condition)
        cell.accessoryView = self.checkmarkOffAccessoryView;
    else
        cell.accessoryView = nil;
}

С вышеупомянутым кодом, только одна ячейка показывает вспомогательный види пользовательский интерфейс зависает.

Если я инициализирую экземпляр UIImageView непосредственно в методе делегата, я получаю все удовлетворяющие условию ячейки, показывающие вспомогательное представление, и я не испытываю зависания пользовательского интерфейса:

- (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;
}

Моя цель - инициализировать как можно меньше объектов и повторно использовать один UIImageView.Мне любопытно, почему первый кусок кода проблематичен и что я мог сделать, чтобы это исправить.

Кажется, что свойство accessoryView ячейки должно просто увеличивать число retain на self.checkmarkOffAccessoryView, но, похоже, мне не хватает некоторых деталей.

Что я упустил?Спасибо за ваш совет.

РЕДАКТИРОВАТЬ

Я думаю, что:

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

совпадает с:

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

В любом случае, у меня один и тот же симптом замораживания.

Ответы [ 4 ]

9 голосов
/ 16 июля 2010

Вы не можете добавить один и тот же вид несколько раз.Обработчик пользовательского интерфейса сойдет с ума.Чтобы убедиться в этом, я попытался сделать то, что вы сказали выше, и у меня возникла та же проблема.Пользовательский интерфейс зависает, изображение появляется только для одной из ячеек.

Лучшее, что вы можете сделать, это сохранить ваше изображение как выделенный UIImage и иметь вспомогательную функцию, которая возвращает новый UIImageView для каждой ячейки.

Используя ваш текущий метод (без сохраненногоUIImage) вы можете сделать:

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

и затем сделать

cell.accessoryView = [self makeCheckmarkOffAccessoryView];

Как вы, возможно, знаете, UIImages с другой стороны может использоваться любое количество раз.UIImageView не занимает много места, так что вы можете легко получить кучу таких, не беспокоясь.

Чтобы раскрыть только одну сделку, представьте, что вы добавляете UIView в два места вв то же время.

Что [ob removeFromSuperview] сделает для этого объекта?Будет ли это удалить вид из обоих мест?Только от одного из них?Какое значение будет возвращено при запросе [ob superview]?Очевидно, что пользовательский интерфейс не предназначен для обработки того, что вы просите.

0 голосов
/ 22 июля 2010

Сокращая ваш случай до самого необходимого (я собирался предложить поместить два "тонких" UIView объекта вокруг UIImageView ...), я обнаружил, что это, скорее всего, невозможно.

Создайте 2 пустых UIView объекта в IB, подключите их до bareView1 и bareView2.Тогда

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

Вы никогда не сможете получить изображение на сцене более одного раза, как это.Как правило, я думаю, что первый объект в строке, который не наследуется от UIView, может использоваться несколько раз, то есть UIImage.Как сказал Калле, у UIView может быть только один родительский элемент в иерархии представления.

Отсрочка второго addSubview только заставляет UIImageView перейти с bareView1 на bareView2.

Заморозка происходит, возможно, из-за того, что обработка событий перепутана: аксессуар может быть интерактивным, как бы вы узнали, какой из них был нажат, если это один и тот же объект?Таким образом, код предполагает, что объекты уникальны, и вам удается нарушить это предположение.

0 голосов
/ 13 июля 2010

возможно это поможет

- (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 голосов
/ 07 июля 2010

Попробуйте без авто-релиза в инициализаторе.Я подозреваю, что вы чрезмерно выпускаете.

Кстати, ваша консоль, вероятно, показывает ошибку BAD_ACCESS, когда она зависает.Если вы включите NSZombieEnabled, я предполагаю, что вы увидите, что он вызывает освобожденный UIImage.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...