Производительность UIImageView в UITableViewCell с использованием ASIHTTPRequest - PullRequest
0 голосов
/ 21 февраля 2012

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

Вот мой метод инициализации:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
      [[self layer] setMasksToBounds:NO];
      [[self layer] setShouldRasterize:YES];
      [[self layer] setRasterizationScale:[[UIScreen mainScreen] scale]];
      [[self layer] setCornerRadius:10];

      _bgCoverView = [[UIImageView alloc] initWithFrame:CGRectZero];
      [_bgCoverView setClipsToBounds:YES];
      [[_bgCoverView layer] setCornerRadius:10];
      [_bgCoverView setContentMode:UIViewContentModeScaleAspectFill];
      [self.contentView addSubview:_bgCoverView];
      [_bgCoverView release];

      //Init other parts of the cell, but they're not pertinent to the question
    }
    return self;
}

Это мои подпредставления макета:

- (void)layoutSubviews{
  [super layoutSubviews];

  if (!self.editing){

    [_bgCoverView setFrame:CGRectMake(0, 0, tableViewCellWidth, self.contentView.frame.size.height)];
  }
}

Этомой установщик для ячейки:

- (void)setGroup:(Group*)group{
  //Set background cover for the contentView
  NSSet *usableCovers = [[group memories] filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"pictureMedData != nil || pictureFullData != nil || (pictureMedUrl != nil && NOT pictureMedUrl contains[cd] '/missing.png')"]];
  Memory *mem = [usableCovers anyObject];

  [_bgCoverView setImage:[UIImage imageWithContentsOfFile:@"no_pics_yet.png"]];
  if (mem != nil){
    [Folio cacheImageAtStringURL:[mem pictureMedUrl] forManagedObject:mem withDataKey:@"pictureMedData" inDisplay:_bgCoverView];
  }
}

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

Итак, это в значительной степени оставляет мой метод кэширования (который находится в классе помощника).Вот метод:

+(void)cacheImageAtStringURL:(NSString *)urlString forManagedObject:(NSManagedObject*)managedObject withDataKey:(NSString*)dataKey inDisplay:(NSObject *)obj{
  int objType = 0;        //Assume UIButton
  if (obj == nil)
    objType = -1;
  else if ([obj isKindOfClass:[UIImageView class]])
    objType = 1;          //Assign to UIImageView

  NSData *data = (NSData*)[managedObject valueForKey:dataKey];
  if ([data bytes]){
    if (objType == 0)       [(UIButton*)obj setBackgroundImage:[UIImage imageWithData:data] forState:UIControlStateNormal];
    else if (objType == 1)  [(UIImageView*)obj setImage:[UIImage imageWithData:data]];
    return;
  }

  //Otherwise, do an ASIHTTPRequest and set the image when it's returned, save the data into core data so that we get a cache hit the next time.
}

Независимо от того, кэшируются ли изображения или нет, существуют серьезные проблемы с производительностью при прокрутке этого представления.Если я закомментирую метод кеширования, он работает довольно хорошо.Кроме того, другие представления, вызывающие этот метод, являются вялыми, поэтому я почти уверен, что это что-то здесь.

Однако я также скажу, что я также с подозрением отношусь к коду cornerRadius, однако я слышал, чтоесли вы установили значение yesRasterize на YES, это приведет к увеличению производительности.Тем не менее, я не уверен, что это на 100% верно или моя реализация выключена.

Любая помощь будет принята с благодарностью.


ОБНОВЛЕНИЕ

Пока еще не исправлено на 100%, но мы находимся там.

Эти переменные должны быть установлены по запросу:

[request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];

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

Это дало мне часть пути.Некоторые изображения загружались мгновенно, тогда как другие казались вялыми.Я провел дополнительные исследования и добавил в свой делегат приложения следующие строки кода:

[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];

Первая строка имеет решающее значение.Действие ASIHTTPRequest по умолчанию - следовать указаниям веб-сервера.Так что, если он скажет вам в своих заголовках не кэшировать ответ, он не будет.Эта строка переопределяет это.Теперь это отлично сработало на моем симуляторе iOS.Затем я попробовал его на своем 4S, и он снова был медленным.

Причина была в том, что я настроил блок кода в своем запросе, чтобы при успешном извлечении изображения я сохранял его в CoreДанные.Этот вызов вызывался каждый раз, даже для кэшированных запросов.

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

if ([request didUseCachedResponse])   return;

Это очень хорошо работает на 4S и 4. Однако 3GS все еще катастрофически медленен: - (.

Это потому, что ASIHTTPRequest использует кэшированную копию моего NSData, а не моего UIImage. Поэтому ему нужно пересоздавать изображение каждый раз, когда он использует кэш. Это имеет смысл, потому что ASIHTTPRequest только возвращает данные и не знаетто, что вы собираетесь делать с данными впоследствии, так что он всегда будет вызывать ваш код, настроенный при возврате запроса.И поскольку мой блок кода преобразует изображение из данных, это то, что я получаю.

A WAY FORWARD

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

Ответы [ 2 ]

2 голосов
/ 21 февраля 2012

Подсказка с shouldRasterize действительна, хотя по моему опыту это значительно снижает качество графики.Кроме того, поскольку, как и iOS4.3 или около того (больше не помню), они значительно улучшили вызов cornerRadius, прошло очень много времени с тех пор, как мне в последний раз приходилось активировать растеризацию для такого рода проблем.Вы всегда можете отключить cornerRadius и посмотреть, как он работает.

Однако я действительно хочу вам сказать, что ASIHTTPRequest имеет встроенную поддержку кэша, см.

http://allseeing-i.com/ASIHTTPRequest/How-to-use#using_a_download_cache

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

Да, и что-то еще ... ASIHTTPRequest больше не разрабатываетсяВы можете рассмотреть возможность перехода на другую среду (например, AFNetworking).Например, ASIHTTPRequest не поддерживает ARC.

1 голос
/ 21 февраля 2012

Проверить это сообщение .Я использую блоки и GCD для загрузки изображений (особенно полезно в TableViewCell).Это загружает изображения на лету, если вы поместите вызов метода в метод cellForRowAtIndexPath.У меня нет медленного интерфейса.

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