I’m writing an API that involves event handling, and I’d like to be able to use blocks for the handlers. The callbacks will often want to access or modify self. In ARC mode, Clang warns that blocks referencing self are likely to create a retain cycle, which seems like a helpful warning that I want to keep on in general.
However, for this portion of my API, the lifecycle of the callback and the containing object are maintained externally. I know I can break the cycle when the object should be deallocated.
I can turn off the retain cycle warning on a per file basis with #pragma clang diagnostic ignored "-Warc-retain-cycles", but that disables the warning for the entire file. I can surround the blocks with a #pragma clang diagnostic push and pop around that warning, but that makes the blocks ugly.
I can also get the warning to go away by referencing a __weak variable pointing to self instead of referencing self directly, but that makes the blocks far less pleasant to use.
The best solution I’ve come up with is this macro that does the diagnostic disabling around the block:
#define OBSERVE(OBJ, OBSERVEE, PATH, CODE) \
[(OBJ) observeObject:(OBSERVEE) forKeyPath:(PATH) withBlock:^(id obj, NSDictionary *change) { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-retain-cycles\"") \
do { CODE; } while(0); \
_Pragma("clang diagnostic pop") \
}];
That works, but it’s not very discoverable for API users, it doesn’t allow nested observers, and it interacts poorly with XCode’s editor. Is there a better way to disable or avoid the warning?
To begin with, there is a simple way to disable warnings for certain lines of code using
#pragma:But I wouldn’t use it in this particular case because it won’t fix the issue, it’ll just hide it from the developer.
I would rather go with solution that Mark proposed. To create a weak reference, you can do one of the following outside of the block: