4 iphone runtime-error objective-c data-management uistoryboardsegue
我写了一个自定义的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]; }];
}
Run Code Online (Sandbox Code Playgroud)
触发segue时没有异常.但是它会解除分配 destinationViewController.
当点击一个触发另一个segue的按钮时,应用程序会崩溃destinationViewController.
我尝试删除[preV removeFromSuperview] 但无济于事.
我最近开始使用Object-C,我编写了一个模拟push segue的自定义segue.
它第一次被触发,一切正常.
但在那之后,无论触发什么segue,应用程序崩溃,我都会收到EXC_BAD_ACCESS错误.
我的第一个猜测是,这与内存管理有关.那里的东西必须要解除分配,但我不知道它是什么.
我的第二个猜测是,这与由UIView和提供的基础设施有关UIWindow.但是,由于我缺乏知识和经验,我再也无法弄清楚真正的问题是什么.
我知道我实际上可以采用一种简单的方法,通过使用a rootviewcontroller并简单地隐藏导航栏来创建push segue ,但我真的想知道我看似构造良好的自定义segue究竟出了什么问题,并了解下面发生了什么.代码结构.
感谢Phillip Mills和Joachim Isaksson的建议,在进行了一些实验并利用断点和Zombie工具之后,
这是我意识到的:
在按钮触发自定义segue之后,只有当按钮触发下一个segue时,app才会崩溃.使用触发下一个segue viewDidAppear不会导致任何崩溃.
坠机背后的主要原因:
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:]
Run Code Online (Sandbox Code Playgroud)
这意味着(如果我没错)
自定义segue以某种方式触发了释放对象的内容,在destinationViewController触发另一个segue的按钮(in )之后将向其发送Objective-C消息.
没有一个prepareForSegue被调用,因为我不需要在视图之间传递数据.
我的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];
}
Run Code Online (Sandbox Code Playgroud)
我启用了ARC,所以我自己并没有真正进行任何释放.
[更新2]
已经变成僵尸的对象是destinationViewController自定义segue的对象.
不调用removeFromSuperview自定义segue不会阻止对象变成僵尸.
只要我使用常规模型segue或push segue(使用rootViewController)而不是我制作的自定义模型,就不会有任何僵尸,一切都会正常工作.
你的崩溃只是因为你的新控制器在segue执行后没有保留.
你做的是这样的:
rootViewController 仍然指向它,你的目标视图控制器没有被添加到窗口的层次结构中.这将按预期工作:
-(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;
}];
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2412 次 |
| 最近记录: |