Блоки, сохраняющие класс, который они только что получили? - PullRequest
1 голос
/ 06 апреля 2011

У нас есть класс, который оборачивает 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 этого никогда не было.

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

Ответы [ 2 ]

2 голосов
/ 06 апреля 2011

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

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

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
}];
0 голосов
/ 06 апреля 2011

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

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

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

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

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

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

или

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

или

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

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

...