Skip to content

Instantly share code, notes, and snippets.

@rabovik
Last active December 15, 2021 08:42
Show Gist options
  • Save rabovik/4707815 to your computer and use it in GitHub Desktop.
Save rabovik/4707815 to your computer and use it in GitHub Desktop.
/**
* Several macros simplifying use of weak references to self inside blocks
* which goal is to reduce risk of retain cycles.
*
* Example:
* @code
@interface Example : NSObject{
int _i;
}
@property (nonatomic,copy) void(^block)(void);
@end
@implementation Example
-(void)someMethod{
self.block = weakifySelf(^{
// Self may be nil here
[self doSomeWork];
strongifyAndReturnIfNil(self);
// Self is strong and not nil.
// We can do ivars dereferencing
// and other stuff safely
self->_i = 42;
});
}
@end
* @endcode
*/
/**
* Takes a block of any signature as an argument
* and makes all references to self in it weak.
*/
#define weakifySelf(BLOCK...) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
rs_blockWithWeakifiedSelf(self, ^id(__typeof(self) __weak self) { \
return (BLOCK); \
}) \
_Pragma("clang diagnostic pop")
/**
* Creates a strong reference to a variable
* that will shadow the original
*/
#define strongify(VAR) \
id _strong_##VAR = VAR; \
__typeof(VAR) __strong VAR = _strong_##VAR;
/**
* Creates a strong reference to a variable and returns if it is nil
*/
#define strongifyAndReturnIfNil(VAR) \
strongify(VAR) \
if (!(VAR)){ return;}
id rs_blockWithWeakifiedSelf(id self, id(^intermediateBlock)(id __weak self));
#import "RSWeakifySelf.h"
id rs_blockWithWeakifiedSelf(id self, id(^intermediateBlock)(id __weak self)){
id __weak weakSelf = self;
return intermediateBlock(weakSelf);
}
@avently
Copy link

avently commented Apr 25, 2015

Thank you! Replace all my old code with yours

@n-b
Copy link

n-b commented Jan 20, 2016

Thanks for this sweet little macro! I have been using it for years, and found out today that at some point, you introduced a simpler “version 2” with GCC statement expressions, but when back to the first implementation after a few months.

What went wrong?

@numantariq
Copy link

This is brilliant! It would make the code so much cleaner. However, a side effect that I am seeing for this is that the debugger won't stop at breakpoints with in the passed BLOCK any more. Any idea why that is or a possible work around for it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment