Подтвердить что ты не робот

Хранить блоки внутри словаря

У меня есть свой собственный метод, который принимает блок как аргумент. Я хочу отслеживать этот блок внутри NSDictionary. Каков наилучший способ добавить блок в словарь?

Я пробовал этот код, но после выполнения строки ниже (setObject...) словарь по-прежнему пуст. Я предполагаю, что это потому, что блок не относится к типу NSObject. Но как правильно это сделать?

- (void)startSomething:(NSURLRequest*)request block:(void (^)(NSURLResponse*, NSData*, NSError*))handler {

    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];

    [pendingRequests setObject:handler forKey:connection];
}

EDIT:

Ничего. Я не знаю, о чем я думал. 3 очка:

  • Блоки являются объектами objc
  • Typo: setObject должен быть установленValue
  • forKey - это строка, поэтому должно быть [описание соединения] или что-то вроде этого

В любом случае я исправил свою проблему сейчас следующим образом:

- (void)startSomething:(NSURLRequest*)request block:(void (^)(NSURLResponse*, NSData*, NSError*))handler {

    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
    [pendingRequests setValue:handler forKey:[connection description]];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

        void (^handler)(NSURLResponse*, NSData*, NSError*);
        handler = [pendingRequests valueForKey:[connection description]];
        handler(nil, nil, nil);
    });
}
4b9b3361

Ответ 1

Это все еще не сработает или, в лучшем случае, будет работать только по совпадению.

Вам нужно скопировать handler, прежде чем вставлять его в словарь. Что-то вроде:

void (^handlerCopy)(NSURLResponse*, NSData*, NSError*) = Block_copy(handler);
[dict setObject:handlerCopy forKey:@"foo"];
Block_release(handlerCopy); // dict will -retain/-release, this balances the copy.

И да, это должно быть setObject:forKey: и objectForKey:.

Ответ 2

Если вы используете ARC, используйте -copy:

 void (^handlerCopy)(NSURLResponse*, NSData*, NSError*) = [handler copy];
 [dict setObject:handlerCopy forKey:@"foo"];

Ответ 3

"Typo: setObject должен быть установленValue"

НЕТ, вы всегда должны использовать setObject: вместо setValue:. setValue: для кодирования с ключом и по совпадению работает аналогично setObject: для словаря (даже тогда это не то же самое, например, когда ключ "@something"), а setObject: - правильный метод для размещения вещей в словаре, и который правильно принимает все типы в качестве ключей. (Кстати, я не уверен, что вы хотите использовать connection как ключ, так как он его скопирует.)

Реальная проблема заключается в том, что блоки нужно копировать, прежде чем хранить их в том, что может длиться дольше, чем исходная область блока (это особая проблема для блоков, а не для других объектов), поскольку блоки (в отличие от другие объекты) изначально находятся в стеке, и, таким образом, сохранение его не препятствует его освобождению. Помещение чего-то в словарь обычно сохраняет его, но в этом случае этого недостаточно.

[pendingRequests setObject:[[handler copy] autorelease] forKey:connection];

Ответ 4

На самом деле с ARC вы можете просто добавить блок в NSDictionary, как и с любым другим объектом. Вам не нужно делать ничего особенного, например Block_copy или [block copy], и это будет неправильно и вызовет утечку.