Я хотел бы рекурсивно вызывать блок изнутри самого себя. В объекте obj-c мы используем «self», есть ли что-то подобное, чтобы ссылаться на экземпляр блока изнутри самого себя?Есть ли указатель SELF для блоков?
ответ
Веселая история! Блоки фактически являются объектами Objective-C. Тем не менее, нет открытого API для получения указателя блоков self
.
Однако, если вы объявите блоки перед их использованием, вы можете использовать их рекурсивно. В не сборки мусора, вы могли бы сделать что-то вроде этого:
__weak __block int (^block_self)(int);
int (^fibonacci)(int) = [^(int n) {
if (n < 2) { return 1; }
return block_self(n - 1) + block_self(n - 2);
} copy];
block_self = fibonacci;
Это необходимо применить модификатор __block
к block_self
, потому что в противном случае, block_self
ссылка внутри fibonacci
будет ссылаться на него перед ним (сбой вашей программы при первом рекурсивном вызове). __weak
должен обеспечить, чтобы блок не фиксировал значительную ссылку на себя, что могло бы вызвать утечку памяти.
Вы должны объявить переменную блок, как __block
:
typedef void (^MyBlock)(id);
__block MyBlock block = ^(id param) {
NSLog(@"%@", param);
block(param);
};
@Joe Blow ['__block' конкретно это ключевое слово] (http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#// apple_ref/DOC/UID/TP40007502-CH6-SW6). –
Этот код также будет протекать по той же причине, что и код zneak. – Karl
Следующий рекурсивный блок кода будет скомпилировать и запустить с помощью ARC, GC, или ручное управление памятью, без сбоев, утечки или выдачи предупреждений (анализатор или регулярные):
typedef void (^CountdownBlock)(int currentValue);
- (CountdownBlock) makeRecursiveBlock
{
CountdownBlock aBlock;
__block __unsafe_unretained CountdownBlock aBlock_recursive;
aBlock_recursive = aBlock = [^(int currentValue)
{
if(currentValue >= 0)
{
NSLog(@"Current value = %d", currentValue);
aBlock_recursive(currentValue-1);
}
} copy];
#if !__has_feature(objc_arc)
[aBlock autorelease];
#endif
return aBlock;
}
- (void) callRecursiveBlock
{
CountdownBlock aBlock = [self makeRecursiveBlock];
// You don't need to dispatch; I'm doing this to demonstrate
// calling from beyond the current autorelease pool.
dispatch_async(dispatch_get_main_queue(),^
{
aBlock(10);
});
}
Важные соображения:
- You необходимо скопировать блок в кучу вручную или попытаться получить доступ к несуществующему стекю, когда вы вызываете его из другого контекста (ARC обычно делает это для вас, но не во всех случаях. Лучше играть в нее безопасно).
- Вам нужны ДВОЙНЫЕ ссылки: один, чтобы удерживать сильную ссылку на блок, и один, чтобы удерживать слабую ссылку для рекурсивного блока для вызова (технически это требуется только для ARC).
- Вы должны использовать квалификатор __block, чтобы блок не фиксировал еще неназначенное значение ссылки на блок.
- Если вы занимаетесь ручным управлением памятью, вам необходимо автоматически авторизовать скопированный блок.
Это не сработает в ARC, но как насчет '' copy] autorelease] '' вместо того, чтобы просто копировать, так что вам не нужно вызывать выпуск внутри блока? Для ARC возможно выполнение '' 'aBlock = nil''' после вызова' '' aBlock (10); '' '? –
На самом деле, пересматривая это решение, оказывается, что сохранение ссылки внутри блока вызовет утечку, если блок не будет вызван. Теперь я обновил ответ, чтобы он работал правильно, называете ли вы его или нет. – Karl
У меня есть проблема, которая добавляет к этому сложный уровень сложности, но я не совсем уверен, что моя проблема разрешима. Я хотел бы иметь возможность повторять вызовы API через AFNetworking. Я думаю, что этот pastebin упрощает и иллюстрирует проблему. http://pastebin.com/xRPJuckZ Небезопасный рекурсивный блок вызывается изнутри другого блока внутри себя, а его вызов приводит к ошибке плохого доступа. Не могли бы вы представить, как это решить? –
Для блоков (пока) нет self
. Вы можете построить один такой (предполагается, что ARC):
__block void (__weak ^blockSelf)(void);
void (^block)(void) = [^{
// Use blockSelf here
} copy];
blockSelf = block;
// Use block here
__block
необходимо, чтобы мы могли установить blockSelf
к блоку после создания блока. Требуется __weak
, потому что в противном случае блок будет содержать сильную ссылку на себя, что вызовет сильный опорный цикл и, следовательно, утечку памяти. copy
необходим, чтобы убедиться, что блок скопирован в кучу. Это может быть ненужным с новыми версиями компилятора, но это не повредит.
- 1. Есть ли последствия для #define this self?
- 2. Есть ли служба Android-блоков?
- 3. Нужно ли использовать слабый указатель при использовании блоков C++ `function` (в отличие от блоков Objective C)
- 4. Есть ли модернизированный способ получить слабую самооценку для блоков?
- 5. Есть ли указатель vm_area_struct для процессов ядра?
- 6. Есть ли причина использовать ключевое слово self?
- 7. static :: vs. self :: - есть ли недостатки?
- 8. Есть ли случаи, когда [self сохраняются]?
- 9. Есть ли C++ ленивый указатель?
- 10. Есть ли умный указатель CUDA?
- 11. Есть ли указатель на направление?
- 12. Сохранять циклы для блоков внутри блоков
- 13. В Python, возвращает ли 'self' экземпляр объекта или указатель?
- 14. Есть ли альтернатива для выбора блоков блоков, которые я могу использовать в этой ситуации?
- 15. Должен ли я использовать слабый self-указатель, если метод, вызванный из блока, использует self?
- 16. в объективе-c, есть (self) {[self initFOO]} избыточный?
- 17. Дождитесь завершения блоков асинхронных блоков
- 18. Есть ли у чтения (размер) встроенный указатель?
- 19. Есть ли в STL файл-указатель?
- 20. F # детский агент. Есть ли указатель 'this'
- 21. Есть ли способ сделать указатель на ссылку?
- 22. Есть ли механизм для постоянного указателя на указатель в C?
- 23. Есть ли способ создать «Self-размещенный» веб-сайт в .Net?
- 24. Есть ли способ изменить цель symlink/proc/self/exe?
- 25. Есть ли тип «SELF» в scala, который представляет текущий тип?
- 26. Instagram API: есть ли/users/self/media/недавняя конечная точка?
- 27. Есть ли способ запросить, сколько блоков имеет критическая секция?
- 28. Передать по ссылке для блоков
- 29. Почему мне нужно создать поточную версию self для некоторых блоков завершения, а не для других?
- 30. Почему мы все проверяем, есть ли (self) в методах init?
Отличный ответ. модификатор __block заставил бы меня некоторое время подумать самостоятельно. Благодаря тонну! Rep вам! –
Если вы передадите его функции, которая завершит ее копирование (например, 'dispatch_async()'), вам также потребуется скопировать блок в область назначения. –
Этот код будет протекать, даже если у вас есть условие завершения. Добавьте переменную обратного отсчета и запустите ее с помощью проверочной проверки инструментов.Кроме того, компилятор выдает следующее предупреждение, если у вас есть правильные предупреждения: «Захват« myBlock »в этом блоке, вероятно, приведет к циклу сохранения« – Karl