Ios self.completionBlock=^{}和(void)(^completionBlock)(void)=^{}之间的差异

Ios self.completionBlock=^{}和(void)(^completionBlock)(void)=^{}之间的差异,ios,objective-c-blocks,weak-references,retain-cycle,Ios,Objective C Blocks,Weak References,Retain Cycle,最近在苹果的文档之后 我使用了以下约定来避免保留周期问题 __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-

最近在苹果的文档之后

我使用了以下约定来避免保留周期问题

__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();
        }
    }
};
__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在调用块之前被释放

当我使用以下工具时,发现它是有效的

__block __typeof(self) block_self = self;
void(^completionBlock)(void) = ^(){

     if (block_self->_completion != NULL) {
         block_self->_completion();
     }
};
现在我很困惑我们什么时候应该使用弱引用。仅在以下情况下使用“self.completionBlock

对这种情况的任何了解都将对我非常有用

下面给出了我的实现代码

=================================================

文件MyViewController =================================================

文件MyViewControllerTransitioning
@实现MyViewControllerTransitioning
-(instancetype)initWithCompletion:(completionHandler)completionHandler
{
if(self=[super init])
{
if(completionHandler!=NULL){
_completion=completionHandler;
}
}
回归自我;
}
-(id)导航控制器:(UINavigationController*)导航控制器
AnimationControllerOperation:(UINavigationControllerOperation)操作
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
{
id animationTransitioning=nil;
//在这里撞车
__块uu类型(自)块u self=self;
void(^completionBlock)(void)=^(){
if(块自->块完成!=NULL){
块_self->_completion();
}
};
//如果推送,则显示演示文稿动画
if(操作==UINavigationControllerOperationPush){
animationTransitioning=[[MyAnimator alloc]initWithAnimationCompletion:completionBlock];
}
返回动画转换;
}
-(无效)解除锁定{
//在调用completionBlock之前调用dealloc
}
@结束
=================================================

文件MyAnimator
@实现MyAnimator
-(instancetype)initWithAnimationCompletion:(presentationUpCompletion)completionHandler
{
if(self=[super init])
{
if(completionHandler!=NULL){
_completion=completionHandler;
}
}
回归自我;
}
-(NSTimeInterval)transitionDuration:(id)transitionContext
{
返回我的持续时间;
}
-(void)animateTransfion:(id)transitionContext{
//动画逻辑
[UIView animateWithDuration:持续时间动画:^{
//动画逻辑
}完成:^(布尔完成){
[transitionContext completeTransition:![transitionContext transitionWasCancelled];
}];
}
-(void)animationEnded:(BOOL)转换已完成{
if(transitionCompleted&&u completion!=NULL){
_完成();
}
}
@结束
自完成块

self
强引用了
completionBlock
(它是一个属性变量),那么您需要弱引用
self
,以避免循环

(void)(^completionBlock)(void)=^{}

self
没有对
completionBlock
的强引用(它是一个局部变量),不需要创建对self的弱引用


您添加的
\uu block
之所以有效,是因为“
\uu block
导致变量被强引用。”

在我的原始答案中,下面,我将介绍标准的
弱自我
模式(以及
弱自我
-
强自我
“舞蹈”)。我的结论是,您参考的演示幻灯片对于
weakSelf
模式是绝对正确的(尽管该演示文稿在风格上是过时的)

随后,您提供了一个更完整的代码示例,结果表明它遇到了一个不同的、不相关的问题。(更糟糕的是,这是一个只有在解决强引用循环时才会出现的问题。lol。)总之,代码将导航控制器的委托设置为超出范围的本地对象。因为导航控制器没有保留其委托,所以您最终得到了指向此解除分配对象的悬空指针

如果您保留自己对该委托对象的
strong
引用(防止其被解除分配),问题就会消失


我的原始答案如下


你说:

使用以下约定来避免保留周期问题

__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();
        }
    }
};
__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在调用块之前被释放

不,这是一种非常常见的模式(通常被戏称为“弱自我,强自我舞蹈”)。这没什么错。如果它崩溃了,那是因为其他原因

当然,我会使用现代命名约定(
weakSelf
strongSelf
而不是
weakSelf
strongSelf
)。我会删除
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我不倾向于去引用和ivar,而是使用一个属性。所以,我可能会得到这样的结果:

__weak typeof(self) weakSelf = self;

void(^completionBlock)(void) = ^(){
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        if (strongSelf.completion != NULL) {
            strongSelf.completion();
        }
    }
};
但是,尽管如此,如果这是崩溃,你还有一些其他的问题。坦白地说,你有一个积木叫做积木,所以你很难猜测你的问题在哪里,但问题并不在“弱自我”模式中

稍后,您会继续建议使用:

__block __typeof(self) block_self = self;
这并不像你想象的那样。“弱自我”模式的目标是打破强参考循环(以前称为保留循环),但在ARC中,此
\u块
参考对解决强参考循环没有任何作用。注意,在非ARC代码中,此
block_self
模式用于中断保留循环,但在ARC中它不会执行此操作

最后,您继续建议:

__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){
     if (weak_self->_completion != NULL) {
         weak_self->_completion();
     }
};
这有两个严重问题。首先,您正在解引用一个弱变量。如果
弱_self

__block __typeof(self) block_self = self;
__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){
     if (weak_self->_completion != NULL) {
         weak_self->_completion();
     }
};