Got it, I've never actually seen dispatch_main used (as an iOS Developer), from what I am reading, this routine is never really used in any production apps, correct?
ARC works hard to automate this. If it sees that a block might escape it does the copy for you. I think you’ve hit a situation where that’s not working properly.
In regards, to ARC, you mentioned that it works hard to automate things, but it seems this is at the expense of giving up exact control. Is it a bug in the language that it’s not capturing the primitive BOOL variable? In my original example of code, I implemented the Task wrapper object and it seemed the system had no issues seeing changes to the shouldCancel property.
So, my specific advice here is that you change stop from being a simple BOOL to something that’s appropriate to be shared between threads (something protected by locks, an atomic, a Dispatch ‘or’ source, or whatever). I suspect that you’ll end up fixing this problem in the process.
I followed your link and didn’t see a specific problem. The doc has code that uses __block and code that uses queues but it doesn’t seem to mix them in an undefined way.
You mentioned not to use BOOL, and the documentation uses char:
__block char localCharacter;
So, I was just curious as to where you were going with that or if I’m misunderstanding. By primitive, I am referring to things like int, char, BOOL, etc. BOOL is essentially just defined as:
typedef signed char BOOL;
Objective-C code can simply send the -copy message to the block
Like this? I don't think I've ever seen this done in practice, but it seemed to work.
- (void)primitiveStopBlockWithLocalAssignmentAndCopyTest {
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
__block BOOL stop;
[self primitive_cancellable_dispatch_after:delay block:[^{
NSLog(@"Ran primitive implementation with calling inline. (stop: %@ / %p)", @(stop), &stop);
} copy] stop:&stop];
stop = YES;
}
I suspect that the final answer here will be that this pattern — having a __block variable that you access by capturing it in an escaping block and via a pointer — is causing problems and that the way to avoid those problems would be to stop doing that.
This is essentially what I have came to the conclusion as well. The paradigm worked for objects but not primitives unless explicitly creating a local block and referencing it, or just manually send the block the copy message. It just seems messy because if I am essentially passing variables through, I had to locally reference the variables and do a log, if I didn't want that, I pretty much had to do a no-op with the variable to quiet the compiler warnings. Overall, I definitely understand workarounds, solutions, etc. in getting what I am trying to do to work, but I am trying to understand fundamentally why the primitive variable was not captured properly to determine if my mental model of how everything works is flawed.
Is it better practice / safer to send primitive variables as part of the block inline vs. as a function parameter? I don’t understand this part of your question. Please elaborate.
Wondering if it's safer to implement by coalescing the block and primitive variable like this:
typedef void(^MyStoppableBlock)(MyBlock block, BOOL *stop);
- (void)primitive_cancellable_dispatch_after:(dispatch_time_t)delay block:(MyStoppableBlock)block;
Rather than the original:
- (void)primitive_cancellable_dispatch_after:(dispatch_time_t)delay block:(MyBlock)block stop:(BOOL*)stop;
Topic:
Programming Languages
SubTopic:
General
Tags: