Difference between self.completionBlock = ^{} and (void)(^completionBlock)(void) = ^{}
最近在关注Apple文档之后
我使用以下约定来避免保留周期问题。
1 2 3 4 5 6 7 8 9 10 11 | __weak __typeof(self) weak_self = self; void(^completionBlock)(void) = ^(){ __typeof(self) strong_self = weak_self; if (strong_self) { if (strong_self->_completion != NULL) { strong_self->_completion(); } } }; |
但是这个代码被发现崩溃,因为在调用块之前self被释放了。
当我使用以下内容时,发现它正在工作。
1 2 3 4 5 6 7 | __block __typeof(self) block_self = self; void(^completionBlock)(void) = ^(){ if (block_self->_completion != NULL) { block_self->_completion(); } }; |
现在我很困惑,我们应该使用__weak引用。 仅在以下"self.completionBlock"的情况下
1 2 3 4 5 6 7 | __weak __typeof(self) weak_self = self; self.completionBlock = ^(){ if (weak_self->_completion != NULL) { weak_self->_completion(); } }; |
在这种条件下的任何亮点对我都非常有用。
我的实现代码如下。
=================================================
文件MyViewController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @implementation MyViewController //starting point - (void)myPushMethod { __weak __typeof(self) weak_self = self; MyViewControllerTransitioning *delegateObj = [[MyViewControllerTransitioning alloc] initWithCompletion:^{ //resetting the delegate __typeof(self) strong_self = weak_self; if (strong_self) { strong_self.navigationController.delegate = nil; } }]; self.navigationController.delegate = delegateObj; [self.navigationController pushViewController:someViewController animated:_animated]; //it is found that delegateObj is getting deallocated while reaches this point } @end |
=================================================
文件MyViewControllerTransitioning
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | @implementation MyViewControllerTransitioning - (instancetype)initWithCompletion:(completionHandler)completionHandler { if(self = [super init]) { if (completionHandler != NULL) { _completion = completionHandler; } } return self; } - (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { id<UIViewControllerAnimatedTransitioning> animationTransitioning = nil; //crashes here __block __typeof(self) block_self = self; void(^completionBlock)(void) = ^(){ if (block_self->_completion != NULL) { block_self->_completion(); } }; //showing presentation-up animation if Push if (operation == UINavigationControllerOperationPush) { animationTransitioning = [[MyAnimator alloc] initWithAnimationCompletion:completionBlock]; } return animationTransitioning; } - (void)dealloc{ //dealloc is called before invoking completionBlock } @end |
=================================================
档案MyAnimator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | @implementation MyAnimator - (instancetype)initWithAnimationCompletion:(presentationUpCompletion)completionHandler { if(self = [super init]) { if (completionHandler != NULL) { _completion = completionHandler; } } return self; } - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext { return my_duration; } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { //animation logic [UIView animateWithDuration:duration animations: ^{ //animation logic } completion: ^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } - (void)animationEnded:(BOOL) transitionCompleted { if (transitionCompleted && _completion != NULL) { _completion(); } } @end |
在下面的原始答案中,我将介绍标准的
您随后提供了一个更完整的代码示例,结果发现它遇到了一个不同的,无关的问题。 (更糟糕的是,这个问题只有在强大的参考周期得到解决时才能体现出来。大声笑。)底线,代码将导航控制器的委托设置为超出范围的本地对象。因为导航控制器没有保留其委托,所以最终会有一个指向此解除分配对象的悬空指针。
如果您对此委托对象保留自己的
我原来的答案如下。
你说:
used the following conventions to avoid retain cycle issues.
1
2
3
4
5
6
7
8
9
10 __weak __typeof(self) weak_self = self;
void(^completionBlock)(void) = ^(){
__typeof(self) strong_self = weak_self;
if (strong_self) {
if (strong_self->_completion != NULL) {
strong_self->_completion();
}
}
};But this code is found to be crashing because self is getting deallocated before invoking the block.
不,这是一种非常普遍的模式(通常被戏称为"弱自我,强烈的自我舞蹈")。这没什么不对。如果它崩溃了,那是出于其他原因。
当然,我会使用现代命名约定(
1 2 3 4 5 6 7 8 9 10 | __weak typeof(self) weakSelf = self; void(^completionBlock)(void) = ^(){ typeof(self) strongSelf = weakSelf; if (strongSelf) { if (strongSelf.completion != NULL) { strongSelf.completion(); } } }; |
但是,如果崩溃,你还有其他一些问题。坦率地说,你有一个块调用一个块,所以有点难以猜测你的问题在哪里,但问题不在于"弱自我"模式。
稍后你继续建议使用:
1 | __block __typeof(self) block_self = self; |
这不符合你的想法。"弱自我"模式的目标是打破强引用周期(以前称为保留周期),但在ARC中,此
最后,你继续建议:
1 2 3 4 5 6 | __weak __typeof(self) weak_self = self; self.completionBlock = ^(){ if (weak_self->_completion != NULL) { weak_self->_completion(); } }; |
这有两个严重的问题。首先,您要取消引用弱变量。如果
最重要的是,该演示文稿中的"弱自我"模式是正确的。同样,你的第一个例子中的"弱自我,强烈的自我舞蹈"也是正确的。如果它正在崩溃,你必须向我们提供一个MCVE来重现问题。但在ARC代码中,这是一个完全有效的模式。
self.completionBlock
(void)(^completionBlock)(void) = ^{}
你添加