Created
May 16, 2017 14:32
-
-
Save janodev/630aeea2f1f7b6f33307b743bb210e50 to your computer and use it in GitHub Desktop.
Right and wrong ways to call a block property
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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