#objective-c #memory-management #asihttprequest #nsoperationqueue
#objective-c #управление памятью #asihttprequest #nsoperationqueue
Вопрос:
Я изо всех сил пытаюсь найти решение моей проблемы,
У меня есть класс загрузки, который обрабатывает вызовы моего api, эти вызовы добавляются в NSOperationQueue. Каждому вызову присваивается уведомление о завершении и сбое, которое публикуется при завершении или сбое вызова. Затем я могу корректно обработать завершение / сбой запроса в моем контроллере просмотра.
Проблема, с которой я сталкиваюсь, заключается в следующем, каков правильный способ выделить / инициализировать / освободить мой класс загрузки. Мой первый подход был таким:
выделять инициализацию нового экземпляра класса загрузки каждый раз, когда мне нужно выполнить запрос, тогда у меня может быть уникальный экземпляр класса с уникальными уведомителями о завершении и сбое и другими параметрами, как я пожелаю. Проблема, с которой я столкнулся при таком подходе, заключается в том, когда / как освободить объект. Я не могу просто вызвать запрос на выборку, а затем освободить объект в рамках одного вызова, поскольку у вызова download есть очередь для завершения и уведомления для отправки, я знаю, когда экземпляр класса download завершил свои вызовы из-за уведомления, я просто не знаю правильного способа реализовать его освобождение из другой функции. например:
-(void)downloadLists:(int)page featured:(BOOL)featured {
NSMutableDictionary *postValues = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:page],@"page",@"false",@"is_featured", nil];
if(featured){
[postValues setValue:@"true" forKey:@"is_featured"];
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *destination = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"lists_%i.json",page]];
Download *download = [[Download alloc] init];
[download setCompleteNotifier:@"listsComplete"];
[download setFailedNotifier:@"listsFailed"];
[download downloadPOST:[NSURL URLWithString:@"http://blahblah"] values:postValues destination:destination];
}
Тогда, где мне освободить загрузку и убедиться, что я выпускаю правильный экземпляр, downloadLists может вызываться (n) количество раз в быстрой последовательности.
Мой другой подход заключался в использовании одноэлементного метода загрузки, который был отличным, пока мне не понадобилось добавить userinfo в уведомления, что, конечно, запуталось из-за того, что класс singleton вызывался из разных мест.
Любая помощь будет высоко оценена, вот функция downloadPOST для вашей справки:
-(void)downloadPOST:(NSURL *)path values:(NSDictionary *)keyValues destination:(NSString *)destination {
ASIFormDataRequest *formRequest = [ASIFormDataRequest requestWithURL:path];
for(id key in keyValues){
[formRequest setPostValue:[keyValues objectForKey:key] forKey:key];
}
[formRequest setDownloadDestinationPath:destination];
[formRequest setDelegate:self];
[formRequest setDidFinishSelector:@selector(requestDone:)];
[formRequest setDidFailSelector:@selector(requestWentWrong:)];
[queue addOperation:formRequest];
}
Ответ №1:
Очередь должна быть той, которая обрабатывает освобождение объекта. Здесь есть несколько вариантов.
-
Вы можете использовать NSNotification для публикации вашего конечного состояния, которое прослушивает очередь, и удаления экземпляров, отправляющих это уведомление
-
Вы можете создать частное делегирование между загрузкой и очередью, где очередь получает уведомление
-
Вы можете установить логическое свойство @ в загружаемом классе (т. е.
BOOL completed
). В очереди сохраняется экземпляр загрузки и добавление прослушивателя к завершенному KVC. Когда для параметра completed установлено значение YES, объект освобождается
AFAK, вы используете ASIHTTPRequest, который обрабатывает все это за вас, поэтому я не уверен, зачем вы это переделываете
Комментарии:
1. Хм, однако моя проблема заключается в освобождении объекта, содержащего очередь, если вы не предлагаете мне вызвать [self release], когда очередь завершена?
2. Извините, забыл об этом вопросе : ( Во-первых, вы никогда не вызываете release самостоятельно, это не имеет смысла. Я думаю, вам было бы лучше использовать синглтон или статическую переменную, доступную для всего вашего загружаемого класса, некоторое время назад я опубликовал в своем блоге сообщение именно об этом варианте использования. Возможно, стоит взглянуть: pothibo.com/2011/02/06 /…
Ответ №2:
Похоже, что вы оборачиваете функциональность, уже включенную в ASIHTTPRequest по умолчанию. В классы ASI встроены делегаты для уведомления вас о завершении или сбое:
- (void)requestFinished:(ASIHTTPRequest *)request;
- (void)requestFailed:(ASIHTTPRequest *)request;
Есть ли какая-либо другая причина, по которой вы не можете просто создать запрос в своем основном классе без создания класса загрузки, а затем позволить делегату сообщить вам, когда это будет сделано?
Комментарии:
1. Я пытался сделать его как можно более гибким и повторно используемым, но, похоже, я сделал обратное и сделал его излишне сложным. Я удалю свой класс загрузки.