ответ Джеффри Томас близок, но в АРК, он попадает в блок, и без АРК, он выходит из строя.
Без ARC переменная __block
не сохраняет то, что она ссылается. Блоки создаются в стеке. Таким образом, переменная callback
указывает на блок в стеке. Когда вы передаете callback
в dispatch_after
в первый раз (за пределами блока), dispatch_after
успешно делает копию блока в куче. Но когда эта копия вызывается, а затем возвращается callback
в dispatch_after
, callback
- это оборванный указатель (к теперь уничтоженному блоку в стеке), а dispatch_after
будет (обычно) сбой.
С АРК, A __block
переменных типа блока (например, callback
) автоматически копирует блок в кучу. Таким образом, вы не получите аварии. Но с ARC переменная __block
сохраняет объект (или блок), который он ссылается. Это приводит к циклу сохранения: блок ссылается на себя. Xcode покажет вам предупреждение о рекурсивном вызове dispatch_after
: «Захват« обратного вызова »сильно в этом блоке, вероятно, приведет к циклу сохранения».
Чтобы устранить эти проблемы, вы можете скопировать блок явно (переместить его из стека в кучу под MRC) и установите callback
к нулю (по АРК), либо освободить его (под MRC), чтобы предотвратить утечку его:
__block void (^callback)() = [^{
if(stop_) {
NSLog(@"all done");
#if __has_feature(objc_arc)
callback = nil; // break retain cycle
#else
[callback release];
#endif
} else {
NSLog(@"still going");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
} copy];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
Очевидно, что вы можете удалить #if
и просто использовать ветку, подходящую для управления вашей памятью.
Похоже, вы часто используете цикл GCD. Интересно, в чем преимущества его использования, а не в установке NSTimer? – Gon
@Gon Личные предпочтения, действительно, но есть некоторые отличия. 'dispatch _ *()' позволяет вам жестко управлять очередью, например. Поскольку я ленив, мне также очень нравятся фрагменты, вставленные дополнением кода Xcode. :) – bbum