Jeffrey Thomas's answer is close, but under ARC he loses the block, and without ARC it will work.
Without ARC, the __block variable __block not save what it refers to. Blocks are created on the stack. Thus, the callback variable points to a block on the stack. When you pass a callback to dispatch_after for the first time (outside the block), dispatch_after successfully makes a copy of the block on the heap. But when this copy is called and goes from callback to dispatch_after again, callback is a dangling pointer (to the now destroyed block on the stack), and dispatch_after will (usually) fail.
With ARC, a variable of type __block type block (e.g. callback ) automatically copies the block to the heap. This way you will not get an accident. But with ARC, the __block variable saves the object (or block) that it refers to. This leads to a save loop: the block refers to itself. Xcode will show you a warning about the recursive call dispatch_after : βCapturing the callbackβ strongly in this block will probably lead to a save loop β.
To fix these problems, you can explicitly copy the block (to move it from the stack to the heap in the MRC) and set callback to nil (in ARC) or release it (in MRC) to prevent it from leaking:
  __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); 
Obviously, you can remove #if and just use a branch suitable for managing your memory.