Skip to content

Instantly share code, notes, and snippets.

@janodev
Created May 16, 2017 14:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janodev/630aeea2f1f7b6f33307b743bb210e50 to your computer and use it in GitHub Desktop.
Save janodev/630aeea2f1f7b6f33307b743bb210e50 to your computer and use it in GitHub Desktop.
Right and wrong ways to call a block property
#import <Foundation/Foundation.h>
#undef X
typedef void (^salute_t)();
@interface Person : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) salute_t salute;
-(void) execute:(salute_t)salute delay:(long long)seconds;
@end
@implementation Person
-(instancetype) initWithName:(NSString*)name {
self = [super init];
if (!self){
return nil;
}
self.name = name;
self.salute = ^{ NSLog(@"block undefined"); };
#ifdef X
// Runs, but creates a retain cycle.
// 1) warning: capturing 'self' strongly in this block is likely to lead to a retain cycle
// 2) note: block will be retained by an object strongly retained by the captured object
/*2*/ self.salute = ^{ NSLog(@"%@", /*1*/ self->_name); };
#endif
#ifdef X
// Compiler error.
// 1) error: dereferencing a __weak pointer is not allowed due to possible null
// value caused by race condition, assign it to strong variable first
__block __weak Person *weakSelf = self;
self.salute = ^{ NSLog(@"%@", /*1*/ weakSelf->_name); };
#endif
#ifdef X
// This shows no warning, but it will dereference nil if the object is nil
// by the time the block is running. Dereferencing nil produces a segmentation fault.
__block __weak Person *weakSelf = self;
self.salute = ^{
__strong Person *strongSelf = weakSelf;
NSLog(@"%@", strongSelf->_name);
};
#endif
#ifdef X
// This executes the code or print a message, but if the object is deallocated when
// the execution starts (#1), it will lead to errors (in this case it prints nil).
__block __weak Person *weakSelf = self;
self.salute = ^{
if (weakSelf){
NSLog(@"%@", [weakSelf name]); /*1*/
} else {
NSLog(@"object deallocated");
}
};
#endif
#ifdef YES
// This executes the code or print a message. If the object is deallocated when
// the execution starts (#1), the strong reference keeps the code running correctly.
__block __weak Person *weakSelf = self;
self.salute = ^{
__strong Person *strongSelf = weakSelf;
if (strongSelf){
NSLog(@"%@", strongSelf->_name); /*1*/
} else {
NSLog(@"can't execute, object is gone");
}
};
#endif
return self;
}
-(void) execute:(salute_t)salute delay:(long long)seconds
{
long long delaySeconds = 1;
long long delayNanoseconds = ((long long) delaySeconds)*NSEC_PER_SEC;
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, delayNanoseconds);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
dispatch_after(delay, queue, ^{
salute();
});
NSLog(@"scheduled");
}
@end
int main(int argc, const char *argv[])
{
@autoreleasepool
{
Person *person = [[Person alloc] initWithName:@"Alice"];
[person execute:person.salute delay:1];
person = nil;
NSLog(@"nil'ed");
for (int i=3; i>0; i--) {
NSLog(@".");
NSDate *oneSecond = [NSDate dateWithTimeIntervalSinceNow:1];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:oneSecond];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment