一个模拟推送Segue的自定义Segue将VC变成Zombie [英] a Custom Segue that Simulates a Push Segue turns VC into Zombie

查看:180
本文介绍了一个模拟推送Segue的自定义Segue将VC变成Zombie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个自定义的segue。

I've written a custom segue.

-(void)perform {
UIView *preV = ((UIViewController *)self.sourceViewController).view;
UIView *newV = ((UIViewController *)self.destinationViewController).view;

[preV.window insertSubview:newV aboveSubview:preV];
newV.center = CGPointMake(preV.center.x + preV.frame.size.width, newV.center.y);
[UIView animateWithDuration:0.4
 animations:^{
     newV.center = CGPointMake(preV.center.x, newV.center.y);
     preV.center = CGPointMake(0- preV.center.x, newV.center.y);}
    completion:^(BOOL finished){ [preV removeFromSuperview]; }];
}

当触发segue时,没有异常。但是它会解除分配 destinationViewController

When the segue is triggered there is no exception. However it would deallocate destinationViewController.

当点击 destinationViewController 中触发另一个segue的按钮时,应用程序会崩溃。

The app would crash when a button, that triggers another segue, in destinationViewController is clicked.

我尝试删除 [preV removeFromSuperview] 但无济于事。

I tried removing [preV removeFromSuperview] but to no avail.

我最近开始使用Object-C,并编写了一个模拟推送segue的自定义segue。

I've recently started working with Object-C and I wrote a custom segue that simulates a push segue.

第一次被触发时,一切正常。

The first time it is been triggered, everything works fine.

但在那之后,无论触发了什么segue,
应用程序崩溃,我会收到 EXC_BAD_ACCESS 错误。

But after that, no matter what segue is been triggered, the app crashes and I would receive a EXC_BAD_ACCESS error.

我的第一个猜测是这与内存管理有关。那里的东西必须要解除分配,但我不知道它是什么。

My first guess is that this has to do with memory management. Something out there has to be deallocated but I have no idea what it is.

我的第二个猜测是,这与 UIView 和 UIWindow 。但是再一次,由于我缺乏知识和经验,我无法弄清楚真正的问题是什么。

My second guess is that this has to do with the infrastructure provided by UIView and UIWindow . But once again, due to my lack of knowledge and experience, I can't figure out what the real problem is.

我知道我实际上可以采取一种简单的方法通过使用 rootviewcontroller 创建一个推送segue并简单地隐藏导航栏,但我真的想知道我看似构造良好的自定义segue究竟出了什么问题,并了解什么是在代码结构下面进行。

I know I can actually take an easy approach and create a push segue by using a rootviewcontroller and simply hiding the navigation bar, but I really want to know what exactly is wrong with my seemingly well-constructed custom segue and learn what is going on underneath the fabric of codes.

感谢Phillip Mills& Joachim Isaksson的建议,在进行了一些实验并利用断点和僵尸工具之后,

Thank Phillip Mills & Joachim Isaksson for the suggestions, after conducting some experiments and making use of breakpoints and the Zombie tool,

这是我意识到的:


  1. 在按钮触发自定义segue后,应用程序只会在按钮触发下一个segue时崩溃。使用 viewDidAppear 触发下一个segue不会导致任何崩溃。

  1. After the custom segue has been triggered by a button,the app would only crash when the next segue is also triggered by a button. Triggering the next segue using viewDidAppear would not lead to any crash.

崩溃背后的主要原因:

将Objective-C邮件发送到已解除分配的对象(僵尸)

[#,事件类型,refCt,图书馆,来电者]

[#, event type, refCt, Library, Caller]

0   Malloc  1   UIKit   -[UIClassSwapper initWithCoder:]
1   Retain  2   UIKit   -[UIRuntimeConnection initWithCoder:]
2   Retain  3   UIKit   -[UIRuntimeConnection initWithCoder:]
3   Retain  4   UIKit   -[UIRuntimeConnection initWithCoder:]
4   Retain  5   UIKit   -[UIRuntimeConnection initWithCoder:]
5   Retain  6   UIKit   -[UIRuntimeConnection initWithCoder:]
6   Retain  7   UIKit   -[UIRuntimeConnection initWithCoder:]
7   Retain  8   UIKit   -[UIRuntimeConnection initWithCoder:]
8   Retain  9   UIKit   UINibDecoderDecodeObjectForValue
9   Retain  10  UIKit   UINibDecoderDecodeObjectForValue
10  Retain  11  UIKit   -[UIStoryboardScene setSceneViewController:]
11  Retain  12  UIKit   -[UINib instantiateWithOwner:options:]
12  Release 11  UIKit   -[UINibDecoder finishDecoding]
13  Release 10  UIKit   -[UINibDecoder finishDecoding]
14  Release 9   UIKit   -[UIRuntimeConnection dealloc]
15  Release 8   UIKit   -[UIRuntimeConnection dealloc]
16  Release 7   UIKit   -[UIRuntimeConnection dealloc]
17  Release 6   UIKit   -[UIRuntimeConnection dealloc]
18  Release 5   UIKit   -[UINibDecoder finishDecoding]
19  Release 4   UIKit   -[UIRuntimeConnection dealloc]
20  Release 3   UIKit   -[UIRuntimeConnection dealloc]
21  Release 2   UIKit   -[UIRuntimeConnection dealloc]
22  Retain  3   UIKit   -[UIStoryboardSegue initWithIdentifier:source:destination:]
23  Retain  4   ProjectX    -[pushlike perform]
24  Retain  5   UIKit   -[UINib instantiateWithOwner:options:]
25  Retain  6   UIKit   +[UIProxyObject addMappingFromIdentifier:toObject:forCoder:]
26  Retain  7   UIKit   -[UIProxyObject initWithCoder:]
27  Retain  8   UIKit   -[UIRuntimeConnection initWithCoder:]
28  Retain  9   UIKit   UINibDecoderDecodeObjectForValue
29  Retain  10  UIKit   UINibDecoderDecodeObjectForValue
30  Release 9   UIKit   -[UINib instantiateWithOwner:options:]
31  Release 8   UIKit   +[UIProxyObject removeMappingsForCoder:]
32  Release 7   UIKit   -[UINibDecoder finishDecoding]
33  Release 6   UIKit   -[UIRuntimeConnection dealloc]
34  Release 5   UIKit   -[UINibDecoder finishDecoding]
35  Release 4   UIKit   -[UINibDecoder finishDecoding]
36  Release 3   ProjectX    -[pushlike perform]
37  Retain  4   libsystem_sim_blocks.dylib  _Block_object_assign
38  Retain  5   UIKit   -[UIApplication _addAfterCACommitBlockForViewController:]
39  Release 4   UIKit   -[UIStoryboardSegue dealloc]
40  Release 3   UIKit   _UIApplicationHandleEvent
41  Release 2   UIKit   -[UIStoryboardScene dealloc]
42  Retain  3   UIKit   _applyBlockToCFArrayCopiedToStack
43  Release 2   UIKit   _applyBlockToCFArrayCopiedToStack
44  Release 1   UIKit   __destroy_helper_block_739
45  Release 0   UIKit   _applyBlockToCFArrayCopiedToStack
46  Zombie  -1  UIKit   -[UIApplication sendAction:to:from:forEvent:]

这意味着(如果我没有错误

自定义segue以某种方式触发了释放对象的内容,按钮后会发送一条Objective-C消息(在 destinationViewController 中)点击触发另一个segue。

the custom segue has somehow triggered something that deallocates objects, to which an objective-C message would be sent after button (in destinationViewController) that triggers another segue is clicked.

由于我不需要在视图之间传递数据,因此没有调用 prepareForSegue

Not a single prepareForSegue is been called since I don't need to pass data between views.

我的segues都以相同的方式触发:

My segues are all triggered the same way:

- (void)viewDidLoad
{
    [super viewDidLoad];
    CGRect buttonFrame = CGRectMake( 10, 40, 200, 50 );
    UIButton *button = [[UIButton alloc] initWithFrame: buttonFrame];
    [button setTitle: @"Go" forState: UIControlStateNormal];
    [button addTarget:self action:@selector(nextView) forControlEvents:UIControlEventTouchUpInside];
    [button setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
    [self.view addSubview:button]; 
}

- (void)nextView{
    [self performSegueWithIdentifier:@"push" sender:self];
}

我启用了ARC,所以我没有真正做任何解除分配我自己..

I have my ARC enabled so I didn't really do any of the deallocation myself..

[更新2]

已经变成僵尸的对象是自定义segue的 destinationViewController

The object that has been turned into a zombie is the destinationViewController of the custom segue.

在自定义segue中不调用 removeFromSuperview 不会阻止对象变成僵尸。

Not calling removeFromSuperview in the custom segue does not stop the object from turning into zombie.

只要我使用一个普通的模型segue或push segue(用rootViewController)而不是我自己制作的那个,不会有任何僵尸,一切都会正常工作。

As long as I use a regular model segue or a push segue (with rootViewController) instead the custom one I made, there won't be any zombie and everything would work fine.

推荐答案

你的崩溃只是因为你的新控制器在segue执行后没有保留。

You're getting a crash just because your new controller not retained after segue execution.

你做的是:


  • src和dest控制器被实例化

  • 你执行你的动画

  • in完成删除src视图

  • 哟你的src控制器被释放了,但是窗口的 rootViewController 仍然指向它并且你的目标视图控制器被添加到窗口的层次结构中。

  • src and dest controllers are instantiated
  • you perform your animations
  • in completion you remove src view
  • your src controller gets released, but window's rootViewController still pointing to it and your destination view controller not added to window's hierarchy.

这将按预期工作:

-(void)perform {
  UIView *preV = ((UIViewController *)self.sourceViewController).view;
  UIView *newV = ((UIViewController *)self.destinationViewController).view;

  UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
  newV.center = CGPointMake(preV.center.x + preV.frame.size.width, newV.center.y);
  [window insertSubview:newV aboveSubview:preV];

  [UIView animateWithDuration:0.4
                   animations:^{
                       newV.center = CGPointMake(preV.center.x, newV.center.y);
                       preV.center = CGPointMake(0- preV.center.x, newV.center.y);}
                   completion:^(BOOL finished){
                       [preV removeFromSuperview];
                       window.rootViewController = self.destinationViewController;
                   }];
}

这篇关于一个模拟推送Segue的自定义Segue将VC变成Zombie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆