Каков наиболее эффективный способ обработки UIButton Photo Grid в UITableView? - PullRequest
0 голосов
/ 20 июня 2011

У меня есть приложение для iOS, над которым я работаю, которое получает кучу URL-адресов фотографий из базы данных MySQL по запросу JSON.Получив эти фотографии и связанную с ними информацию, я использую их для заполнения источника данных для UITableView.Я хочу создать сетку из UIB-кнопок, сделанных из фотографий, по 4 на строку.Этот текущий код работает, однако он очень медленный, и мой телефон / симулятор зависает, пока я прокручиваю таблицу.Таблицы, содержащие только пару строк, работают нормально, но как только я достигну 10 или более строк, он замедлится почти до сбоя.Я новичок в iOS и цель-c, поэтому я предполагаю, что это неэффективно в моем коде.Какие-либо предложения?Спасибо !!

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
static NSString *CompViewCellIdentifier = @"CompViewCellIdentifier";

UITableViewCell *cell = [tableView
                         dequeueReusableCellWithIdentifier: CompViewCellIdentifier];

if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CompViewCellIdentifier] autorelease];
}

// The photo number in the photos array that we'll need to start off with.
NSUInteger photoNumber = (row * 4);

// Assemble the array of all 4 photos we'll need for this table row (for this cell).
NSMutableArray *rowPhotos = [[[NSMutableArray alloc] initWithObjects:[self.photos objectAtIndex:photoNumber], nil] retain];

NSInteger counter = 1;
while ([self.photos count] > photoNumber+counter && counter<4) {
    [rowPhotos addObject:[self.photos objectAtIndex:photoNumber+counter]];
    counter = counter+1;
}

NSLog(@"The rowPhotos array: %@", rowPhotos);

for (int i=0; i<[rowPhotos count]; i++) {

    // Set which photo we're dealing with for this iteration by grabbing it from our rowPhotos array we assembled. Use i as the index.
    NSDictionary *photoRow = [[NSDictionary alloc] initWithDictionary:[rowPhotos objectAtIndex:i]];

    // Get the photo.
    NSString *photoPath = [[NSString alloc] initWithFormat:@"http://localhost/photorious%@", [photoRow objectForKey:@"path"]];
    NSURL *url = [NSURL URLWithString: photoPath];
    [photoPath release];
    UIImage *cellPhoto = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:url]];

    // Figure out the container size and placement.
    int xCoordinate = ((i*70)+8*(i+1));
    CGRect containerRect = CGRectMake(xCoordinate, 0, 70, 70);

    // Create the Button
    UIButton *cellPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [cellPhotoButton setFrame:containerRect];
    [cellPhotoButton setBackgroundImage:cellPhoto forState:UIControlStateNormal];
    [cellPhotoButton setTag:(NSInteger)[photoRow objectForKey:@"id"]];

    // Add the button to the cell
    [cell.contentView addSubview:cellPhotoButton];

    // Add the action for the button.

    [cellPhotoButton addTarget:self 
                        action:@selector(viewPhoto:)
              forControlEvents:UIControlEventTouchUpInside];

    [cellPhoto release];
}

[rowPhotos release];
return cell;
}

1 Ответ

4 голосов
/ 20 июня 2011

Это медленно, потому что вы делаете все за tableView:cellForRowAtIndexPath:. tableView:cellForRowAtIndexPath: Называется действительно часто, особенно каждый раз, когда ячейка должна отображаться в вашем табличном представлении, включая, когда вы прокручиваете свой табличный вид. Таким образом, этот метод должен быть быстрым и неблокирующим (особенно не делать синхронных загрузок!)

Кроме того, вы не правильно используете возможность повторного использования ваших ячеек таблицы. Это резко снижает производительность при повторном создании контента (подпредставлений) для каждой ячейки каждый раз.

  • Когда ваша ячейка используется повторно из предыдущей (вы видите, что она «переработана»), вы НЕ должны повторять все, особенно вы не должны повторно добавлять все подпредставления, так как они уже есть в самой ячейке, как это было используется повторно и не является новым!
  • Вместо этого, когда dequeueReusableCellWithIdentifier: возвращает ячейку (= старая ячейка, ранее созданная, но больше не используемая, так что вы можете «перерабатывать» / использовать ее повторно), вам следует изменять только то, что отличается от ячейки к ячейке. В вашем примере обычно вы изменяете только 4 отображаемых изображения, но не не воссоздает UIImageView, не добавляет их в качестве подпредставления (так как эти подпредставления уже существуют) и не влияет на цель / действие.
  • Вам нужно только создать UIImageView, добавить им цель / действие, установить их фрейм и добавить их в качестве подпредставления, когда вы создаете совершенно новую ячейку, с alloc / initWithReuseIdentifier: / autorelease.

Кроме того, вы извлекаете свои изображения из сети прямо в tableView:cellForRowAtIndexPath:, а также синхронно (это означает, что оно блокирует ваше приложение до тех пор, пока оно не завершит загрузку изображения из сети !!). Вместо этого выполните асинхронную загрузку, задолго до tableView:cellForRowAtIndexPath: (когда ваше приложение загружено, например) и сохраните их локально (например, в NSArray или аналогичном sthg) и извлеките только локальный уже загруженный образ в * 1025. *.

То, что вы пытаетесь сделать, - не самая лучшая идея для начала, если вы новичок в программировании на iOS. То, что вы хотите сделать, может показаться простым, но оно подразумевает такие понятия, как асинхронная загрузка, MVC-дизайн вашего приложения и предварительная выборка изображений из сети в вашей модели перед их отображением в представлении, предоставляют способ обновления табличного представления после завершения загрузки. и основные понятия повторного использования ячеек в табличных представлениях.

Считайте Руководство по программированию TableView , прежде чем идти дальше. Это объясняет это в деталях, и это действительно стоит прочитать. Также ознакомьтесь с образцом кода Apple LazyTableImages , в котором объясняется, как загружать изображения в виде таблицы лениво (имеется в виду асинхронная загрузка изображений, когда они необходимы), и Руководство по программированию загрузки URL , в котором объясняется, как это сделать. асинхронная загрузка данных.

Эти руководства и образцы действительно стоит прочитать, если вы хотите сделать то, что объясняете. Есть также много классов для работы с сеточными представлениями в сети, один из них - моя работа ( OHGridView ), но вы должны понять основы, описанные выше и в упомянутых руководствах, прежде чем идти дальше.

...