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();
}
};