iphone - 模拟推送 Segue 的自定义 Segue 将 VC 变成僵尸

标签 iphone objective-c runtime-error uistoryboardsegue data-management

[使事情简短明了]

我写了一个自定义转场。

-(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

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

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

[详情]

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

第一次触发,一切正常。

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


我的第一个猜测是这与内存管理有关。必须释放一些东西,但我不知道它是什么。

我的第二个猜测是,这与 UIViewUIWindow 提供的基础设施有关。但是再一次,由于我缺乏知识和经验,我无法弄清楚真正的问题是什么。

我知道我实际上可以采取一种简单的方法并通过使用 rootviewcontroller 并简单地隐藏导航栏来创建推送转场,但我真的很想知道我看似很好的问题到底是什么-构建自定义 segue 并了解代码结构下发生的事情。


[更新]

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

这是我的认识:

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

  2. 崩溃的主要原因:

Objective-C 消息已发送到已释放的对象(僵尸)

[#, 事件类型, refCt, 库, 调用者]

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 以某种方式触发了某些对象,该对象会在单击触发另一个 segue 的按钮(在 destinationViewController 中)后向其发送 Objective-C 消息。


更多详情

没有一个 prepareForSegue 被调用,因为我不需要在 View 之间传递数据。

我的 segues 都是以同样的方式触发的:

- (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,所以我自己并没有真正进行任何重新分配。


[更新 2]

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

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

只要我使用常规模型 segue 或推送 segue(使用 rootViewController)而不是我制作的自定义模型,就不会有任何僵尸,一切都会正常工作。

最佳答案

你遇到崩溃只是因为你的新 Controller 在 segue 执行后没有保留。

你做的是这样的:

  • src 和 dest Controller 被实例化
  • 你执行你的动画
  • 完成后删除 src View
  • 您的 src Controller 被释放,但窗口的 rootViewController 仍然指向它并且您的目标 View Controller 添加到窗口的层次结构中。

这将按预期工作:

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

关于iphone - 模拟推送 Segue 的自定义 Segue 将 VC 变成僵尸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12988081/

相关文章:

iphone - 是否有关于如何在 OpenGL ES 1.1 中使用顶点缓冲区对象 (VBO) 的最小化示例?

iphone - 如何从iOS应用中的SQLite表中删除所有内容

iphone - 如何在 JSON 中发布数组值

ios - 如何从@implementation 外部调用方法?

iphone - 如何在ARC环境中将Parser Delegate设置为Self?

iphone - 我们如何在 iPhone Xcode 中处理多个 NSURLConnection?

objective-c - 是什么原因导致 Category 正在实现一个也将由其主要类实现的方法?

c - 遇到可识别的段错误

c - 尝试从文件读取数据时出现运行时错误

ios - 此类对于键 <key> 不符合键值编码,其中 <key> 不在代码中(swift,Xcode 6)