Утечка данных AFNetworking CF?

У меня проблема с AFNetworking. Я запрашиваю много данных JSON с моего сервера через GET, используя это:

[[SessionResponseClient sharedClient] getPath:kURIRateList parameters:@{...} success:^(AFHTTPRequestOperation *operation, id JSON) {

    [_delegate receivedRateResponse:JSON];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [_delegate receivedRateResponse:nil];
}];

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

Использование памяти

используемая память

Когда я исследую как CFData, так и CFData (хранилище), я получаю следующее:

CFData (хранить)

Память хранилища CFData

CFДанные

Память данных CF

Примечание: мое приложение использует ARC, и все остальное работает нормально.

Теперь мой вопрос: поскольку я не видел нерешенных проблем на странице AFNetworking GitHub и почти никаких других жалоб на это в Интернете, что, черт возьми, я делаю неправильно? Кто-нибудь еще сталкивается с этой проблемой? или я один такой? Не могли бы вы опубликовать свой код, так как я не думаю, что мой код выглядит так неправильно...

Обновление 1

Код для интерфейса:

@protocol RateRequestsDelegate;

@interface RateRequests : NSObject  {
   id<RateRequestsDelegate>  _delegate;
}
@property (nonatomic, strong) id<RateRequestsDelegate> delegate;
- (void)fetchRateList;
@end

@protocol RateRequestsDelegate <NSObject>
- (void)receivedRateResponse:(NSDictionary *)response;
@end

SessionResponseClient — это просто расширенный экземпляр AFHttpClient, как демонстрируют все примеры AFNetworking, см.: Взаимодействие с API

Код для ReceiveRateResponse:

- (void)receivedRateResponse:(NSDictionary *)json {
  if (!json)    {
    return;
  }

  self.moviesToInsert = [NSMutableArray arrayWithArray:[json objectForKey:@"rated"]];

  [self.tableView reloadData];
}

Обновление 2

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

Большое спасибо! Павел


person christopher    schedule 03.06.2013    source источник
comment
покажите нам [_delegate ReceiveRateResponse:JSON]; пожалуйста   -  person Daij-Djan    schedule 03.06.2013
comment
Это на устройстве или симуляторе?   -  person Sanjit Saluja    schedule 03.06.2013
comment
и интерфейс SessionResponseClient   -  person Daij-Djan    schedule 03.06.2013
comment
На устройстве - iPad 1-го поколения, iOS 5.1.1. Добавил запрошенный код...   -  person christopher    schedule 03.06.2013
comment
Вы работаете с включенными зомби? Я видел, что это вызывает проблемы с большими двоичными объектами JSON.   -  person MishieMoo    schedule 03.06.2013
comment
@MishieMoo Да, зомби были включены, но даже после их отключения CFData остается прежним.   -  person christopher    schedule 03.06.2013
comment
Ваш delegate должен быть weak, а не strong. Эта проблема может быть вызвана циклом сохранения.   -  person Aaron Brager    schedule 03.06.2013
comment
@AaronBrager пробовал это через unsafe_unretained, но это тоже не дало никакого эффекта...   -  person christopher    schedule 04.06.2013
comment
Попробуйте переключить инструменты со статистики на дерево вызовов. Включите только Obj-C и скройте системные вызовы. Это может подчеркнуть проблемную область.   -  person Aaron Brager    schedule 04.06.2013
comment
В любом случае, ваш делегат абсолютно не должен быть strong.   -  person Aaron Brager    schedule 04.06.2013
comment
... Глядя на снимок экрана с вашими приборами, мне кажется, что ничего не утекает - все еще есть четкие ссылки на данные. У вас много аллокаций, но нет утечек. Что предполагает, что вы держите данные, когда вам это не нужно.   -  person lxt    schedule 04.06.2013
comment
@lxt Я тоже считаю, что это какая-то утечка...   -  person christopher    schedule 04.06.2013


Ответы (3)


Спасибо, чувак, у меня была точно такая же проблема, твое решение сработало.

Тем не менее, я подумал, что прокомментирую, что в вашем решении вы, по сути, отключаете NSURLCache после получения предупреждения о памяти. Я точно не знаю, как AFNetworking использует NSURLCache, но я предполагаю, что их реализация не будет работать так же эффективно, если вы ее отключите (т. е. установив ее емкость на 0). Это может замедлить скорость запроса после вашего первого предупреждения о памяти. В крайнем случае вы можете даже столкнуться с непредвиденным поведением после нескольких дней использования вашего приложения, поскольку оно может не проявляться до первого предупреждения о памяти.

Вместо этого я предлагаю реализовать что-то, что удаляет кешированные ответы, но сохраняет кеш активным:

-(void)didReceiveMemoryWarning
{
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
}

Единственная проблема заключается в том, что AFNetworking может потребоваться снова создать свой кеш, но я предполагаю, что это не так сильно повлияет на структуру.

Наконец, на всякий случай, если это будет полезно вам или кому-либо, чтобы зарегистрировать свой собственный метод для предупреждения о памяти, вы можете сделать это:

[[NSNotificationCenter defaultCenter] addObserver:self (or pointer to your singleton)
                                         selector:@selector(myMethod)
                                             name:UIApplicationDidReceiveMemoryWarningNotification
                                           object:nil];

Надеюсь, это поможет!

person larromba    schedule 19.06.2013

Хорошо, решение заключалось в том, что CFData (store), по-видимому, отвечает за хранение кеша URL-адресов в памяти при использовании NSURLConnection.

Так что мне оставалось только позвонить...

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];

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

Или вы можете просто вызвать его, когда захотите (хотя эта функция не была профилирована по времени)...

Надеюсь, это поможет кому-то, кто сталкивается с подобной проблемой.

person christopher    schedule 04.06.2013
comment
Это отключит все NSURLCaching в первый раз и не повлияет на будущие вызовы, за исключением того, что вы будете тратить больше памяти (если только вы не создадите другой NSURLCache где-то еще позже). [[NSURLCache sharedURLCache] removeAllCachedResponses]; было бы более целесообразно. - person Aaron Brager; 19.06.2013

Может быть, вы могли бы попробовать @autoreleasepool. Например:

@autoreleasepool {

// your codes below
[[SessionResponseClient sharedClient] getPath:kURIRateList parameters:@{...} success:^(AFHTTPRequestOperation *operation, id JSON) {

    [_delegate receivedRateResponse:JSON];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [_delegate receivedRateResponse:nil];
}];
// your codes above

}
person srjohnhuang    schedule 16.06.2015