Well. That certainly is a pickle.
And I don't see straightforward solution to it. Let's think through this a bit:
Right now, you presumably have a large code base where you use this logging macro. It's great, except that it's creating some memory leaks due to the retain cycles created by referring to self
in blocks. (Or, if it isn't creating memory leaks, it's threatening to.)
So, you just need to make sure this reference to self
(conceptually) is weak. Sounds reasonable enough.
Let's look at your requirements:
First Requirement
Can be a multiline macro which defines a __weak reference to self. You suggest that the tricky part to this is that it could potentially redefine the weak reference (presumably by being used multiple times in the same block of code). This is relatively easily worked around by wrapping the macro in a do { something(); } while(0)
construct.
#define JELogVerbose(fmt, ...)
do
{
__weak __typeof(self) weakSelf = self;
DDLogVerbose((@"%@ %@ - " fmt), NSStringFromClass([weakSelf class]),
NSStringFromSelector(_cmd), ##__VA_ARGS__)
} while (0)
Which is a very common macro pattern. And if you call the macro two times in a row, there will still be no redefinition of the weakSelf variable. However, you may notice that this does absolutely nothing to actually solve your issue, as you have to refer to self in order to get a weak reference to it. You actually have to have the weakSelf reference before the block is created, and then in the block ONLY refer to the weak reference. In fact, generally, you want to make another strong reference to it so that it's not removed out of underneath you. Like this:
__weak typeof(self) weakSelf = self;
[someObj block:^{
__strong __typeof(weakSelf) strongSelf = weakSelf;
MyLog(strongSelf);
}];
In order to fix that, you'll have to ALREADY have a weak reference to self, or have a macro that spans over the creation of a block. (That'd be quite a trick.)
Second Requirement
We can't use these helpful preprocessor standard macros, because they don't tell you what's happening at runtime, rather compile time (more technically, a preprocess (?) time). You also rejected another answer (correctly) because it gives you the information from compile time (closer, but still no cigar) rather than runtime.
Unfortunately, I don't think you can get the runtime information from self
you're looking for without actually referring to it during the runtime. We just don't know during compile time what the class of the object is actually going to be. So all of those PRETTY_FUNCTION tricks are right out. And of course, as one would expect, all the runtime functions require a reference to the object you want to find the class for.
Third Requirement
I'm going to boil this down to: I don't want to change my code base. Understandable.
Although, I don't think you have a choice. You're kinda painted into a corner.
Conclusion
I don't think you have any great options (they all require changes outside of the macro, ie changes to your code base):
- Create a block-safe version of the macro by removing any references to self, and always use it in blocks
- Create a block-safe version of the macro that uses
strongSelf
and then whenever you use it, you must also create your weakSelf reference outside the block, and a strongSelf inside the block (as in the example above). This is more work, but it would preserve all your logging as it exists.
Good luck!