Блоки, сохраняющие класс, к которому они только что перешли?

У нас есть класс, обертывающий NSURLConnection. Он принимает блок, который он вызывает, когда заканчивает загрузку. Чтобы дать вам представление, см. ниже. Когда вы отправляете запрос, он сохраняет обратный вызов в экземпляре. Предположим, мой класс называется Request

// from Request.h
@property (nonatomic, copy) void(^callback)(Request*);
- (void) sendWithCallback:(void(^)(Request*))callback;

Мой код для использования выглядит примерно так:

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
    // do some stuff
}]

Мой вопрос: что блок делает с сохранением счетчика request? Копирует/сохраняет? Обратите внимание, что я не поставил __block перед определением.

Я только что изменил что-то важное в Request (переключился с синхронного NSURLConnection на асинхронный ASIHTTPRequest), и он начал освобождаться почти сразу после отправки (заставляя методы делегата вызывать освобожденный объект). С синхронизацией NSURLConnection этого никогда не происходило.

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


person Sean Clark Hess    schedule 06.04.2011    source источник


Ответы (2)


что блок делает с сохранением количества запросов? Копирует/сохраняет?

Нет, это не так.

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
    // The request argument shadows the request local variable,
    // this block doesn't retain the request instance.
}]

Если блок не имеет аргумента запроса,

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^{
    // If you use the request local variable in this block,
    // this block automatically retains the request instance.
}]

В этом случае это вызовет циклы сохранения (запрос сохраняет блок, блок сохраняет запрос).

Пожалуйста, взгляните на мой класс AsyncURLConnection. NSURLConnection сохраняет экземпляр AsyncURLConnection, поэтому вы не владеете материалом AsyncURLConnection самостоятельно.

Как пользоваться

[AsyncURLConnection request:url completeBlock:^(NSData *data) {
    // Do success stuff
} errorBlock:^(NSError *error) {
    // Do error stuff
}];
person Kazuki Sakamoto    schedule 06.04.2011

Блоки не будут автоматически сохранять или копировать аргументы объекта. Это та же семантика, что и при передаче аргументов объекта методам или функциям — блок, метод или функция должны сохранять свои аргументы, если существует вероятность того, что текущий пул автоматического освобождения будет исчерпан до того, как блок, метод или функция завершит использование аргументов.

Обратите внимание на рабочий процесс в вашем сценарии. Этот код:

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
    // do some stuff
}];

еще не выполняет блок и не передает блоку никаких аргументов. Он создает блок и передает его в качестве аргумента -sendWithCallback:. Блок имеет параметр с именем request типа Request *, но фактический аргумент еще не передан.

В какой-то момент позже в вашем коде, если вы сохранили блок в callback, этот блок будет вызываться как:

callback(someRequest); // or callback(self);

or

self.callback(someRequest); // or self.callback(self);

or

aRequest.callback(someRequest); // or someRequest.callback(someRequest);

в зависимости от того, кто отвечает за его вызов. На этом этапе тот, кто вызывает обратный вызов, должен иметь ссылку на действительный запрос (someRequest), и этот запрос является аргументом, передаваемым в блок.

person Community    schedule 06.04.2011