“正常”UIButton导致obj_stack_overflow或EXC_BAD_ACCESS异常 [英] “Normal” UIButton causing obj_stack_overflow or EXC_BAD_ACCESS exception

查看:156
本文介绍了“正常”UIButton导致obj_stack_overflow或EXC_BAD_ACCESS异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

肯定看起来很无害。在我的App Delegate中,我检查 NSUserDefaults 是否有标志以显示启动时的提示。如果已设置,则在 applicationDidFinishLaunching:结束时,我执行此操作:

  TipsViewController * vc = [[TipsViewController alloc] 
initWithNibName:@TipsViewbundle:nil];
[window addSubview:vc.view];
[vc release];

这个想法是暂时显示这个视图。(注意它不是模态VC。没有导航控制器在这一点,加上在这个视图中没有导航栏。)



一旦这个视图被解除,我们将添加我们的预占的 UITabBarController 查看窗口并转换到它,然后从主窗口中删除提示视图。我还没有进入视图解雇点,因为,好吧,继续阅读。



我的TipsView的VC连接或多或少如此:

  UIView  - > view  - > ;文件所有者(TipsViewController)
UIImageView - >背景图片
UIView - > tipView - >文件所有者
UIImageView - >背景图片
UIScrollView
UILabel(提示文字)
UIButton - >触摸内部 - > - (IBAction)button1:
UIButton - >触摸内部 - > - (IBAction)button2:
UIButton - >触摸内部 - > - (IBAction)button3:

源包含所有三个 IBAction的声明和定义打电话。现在他们两个什么都不做。第三个更改提示文本,调整其大小以适应,并调整滚动视图的 contentSize 以匹配。



当我运行应用程序时, TipsViewController 视图显示就好了。我甚至可以滚动提示文字。但是,当我在任何 UIButton 上触发内部触摸时,Xcode开始在源中植入我(我在每个 IBAction 处放置了一个断点)...然后使用 EXC_BAD_ACCESS obj_stack_overflow 退出。



<我已将此与应用程序的其他部分进行了比较,其中包含VC,视图和按钮。它在各方面都是相同的,除了在这种情况下,我添加了VC的视图作为应用程序窗口的子视图,而不是将VC推送到导航控制器。此外,适用于iPhone OS的View Controller编程指南文档说这是公平的游戏:


如果您使用的话单个视图控制器在
您的应用程序中,您将其视图添加到
a窗口,而不是将视图
控制器添加到标签栏或导航
控制器。


是的,我有一个 UITabBarController 等待它,它有标签UINavigationControllers (和其他VC)。但是,如果显示提示视图,则选项卡栏控制器的视图 not 尚未添加到窗口中。目的是在我们完成提示后交换它。换句话说,就所有意图和目的而言,我们暂时表现得就像我们在游戏中有一个VC。然后,我们切换到标签栏并拆掉小费VC。



也许我正在做一些巧妙的错误?有没有更好的办法? (必须有更好的方法!)



样本堆栈跟踪:

 #0 0x992b6f52 in objc_exception_throw 
#1 0x302d6ffb in - [NSObject doesNotRecognizeSelector:]
#2 0x3026e056 in ___forwarding___
#3 0x3024a0a2 in __forwarding_prep_0___
#4 0x308f79d1 in - [UIApplication sendAction:to:from:forEvent:]
#5 0x309598b1 in - [UIControl sendAction:to:forEvent:]
#6 0x3095bad2 in - [UIControl(Internal)_sendActionsForEvents:withEvent:]
#7 0x3095a81e in - [UIControl touchesEnded:withEvent:]
#8 0x30910fdf in - [UIWindow _sendTouchesForEvent:]
#9 0x308faecb in - [UIApplication sendEvent:]
#10 0x309013e1 in _UIApplicationHandleEvent
#11 0x32046375 in PurpleEventCallback
#12 0x30245560 in CFRunLoopRunSpecific
#13 0x30244628 in CFRunLoopRunInMode
#14 0x32044c31 in GSEventRunModal
#15 0x32044cf6 in GSEventRun
#16 0x309021ee在UIApplicationMain
#17 0x00002888 in main在main.m:1 4

从跟踪中可以看出,我们最终在 doesNotRecognizeSelector: ...除了我可以清楚地看到我的提示VC源中的方法。而且,它们都是有线的。 (在IB中没有多条布线或类似的东西。那里的一切看起来都很好,直到文件所有者的关系。)



欢迎/赞赏线索!

解决方案

问题出现在你的第一个代码片段中:你正在创建一个TipsViewController实例,保留它的视图,然后释放视图控制器 - 这会导致它被解除分配。所以现在按钮的目标是指向解除分配的视图控制器的指针。



视图不保留其查看控制器,也不保留其代理或目标。



您必须保留视图控制器实例 - 可能在 retain property-for,只要您希望显示视图。完成视图后,可以将其从父视图中删除,然后释放视图控制器。


It sure looks innocuous enough. In my App Delegate, I check NSUserDefaults for a flag to show tips at startup. If it’s set then, at the end of applicationDidFinishLaunching:, I do this:

TipsViewController *vc = [[TipsViewController alloc]
  initWithNibName:@"TipsView" bundle:nil];
[window addSubview:vc.view];
[vc release];

The idea is to show this view temporarily. (Note that it’s not a modal VC. No Navigation Controller at this point, plus there’s no navigation bar in this view anyway.)

Once this view is dismissed, we’ll add our pre-empted UITabBarController’s view to the window and transition over to it, then remove the tip view from the main window. I haven’t made it to the view dismissal point yet because, well, keep reading.

My TipsView’s VC is wired up more or less like so:

UIView -> view -> File’s Owner (TipsViewController)
  UIImageView -> background image
  UIView -> tipView -> File’s Owner
    UIImageView -> background image
    UIScrollView
      UILabel (tip text)
    UIButton -> touch-up-inside -> -(IBAction)button1:
    UIButton -> touch-up-inside -> -(IBAction)button2:
    UIButton -> touch-up-inside -> -(IBAction)button3:

The source contains declarations and definitions for all three IBAction calls. Right now two of them do nothing. The third one changes the tip text, resizes it to fit, and adjusts the scroll view’s contentSize to match.

When I run the app, the TipsViewController view shows up just fine. I can even scroll through the tip text. However, when I trigger a touch-up-inside on any UIButton, Xcode starts to plant me in the source (where I’ve placed a breakpoint at each IBAction) … and then bails out with either a EXC_BAD_ACCESS or obj_stack_overflow.

I have compared this with other parts of the app where I have a VC, a view, and buttons. It is identical in every way except that, in this case, I’ve added a VC’s view as a subview of the app’s window instead of pushing the VC onto a navigation controller. Moreover, the View Controller Programming Guide for iPhone OS docs say this is fair game:

If you use a single view controller in your application, you add its view to a window instead of adding the view controller to a tab bar or navigation controller.

True, I do have a UITabBarController waiting in the wings, and it has tabs with UINavigationControllers (and other VCs) in it. However, if the tip view is being shown, the tab bar controller’s view has not yet been added to the window. The intent is to swap it in after we’re done showing tips. In other words, for all intents and purposes, we’re temporarily acting like we have a single VC in play. Afterward, we switch to the tab bar and tear down the tip VC.

Perhaps I’m doing something subtly wrong? Is there a better way? ("There’s got to be a better way!")

Sample stack trace:

#0  0x992b6f52 in objc_exception_throw
#1  0x302d6ffb in -[NSObject doesNotRecognizeSelector:]
#2  0x3026e056 in ___forwarding___
#3  0x3024a0a2 in __forwarding_prep_0___
#4  0x308f79d1 in -[UIApplication sendAction:to:from:forEvent:]
#5  0x309598b1 in -[UIControl sendAction:to:forEvent:]
#6  0x3095bad2 in -[UIControl(Internal) _sendActionsForEvents:withEvent:]
#7  0x3095a81e in -[UIControl touchesEnded:withEvent:]
#8  0x30910fdf in -[UIWindow _sendTouchesForEvent:]
#9  0x308faecb in -[UIApplication sendEvent:]
#10 0x309013e1 in _UIApplicationHandleEvent
#11 0x32046375 in PurpleEventCallback
#12 0x30245560 in CFRunLoopRunSpecific
#13 0x30244628 in CFRunLoopRunInMode
#14 0x32044c31 in GSEventRunModal
#15 0x32044cf6 in GSEventRun
#16 0x309021ee in UIApplicationMain
#17 0x00002888 in main at main.m:14

As you can see from the trace, we end up at doesNotRecognizeSelector: … except I can clearly see the methods in my tip VC source. Plus, they’re all wired up. (No multiple wirings or anything like that in IB. Everything looks good there, down to the File’s Owner relationships.)

Clues welcome/appreciated!

解决方案

The problem is right there in your first code snippet: you’re creating an instance of TipsViewController, retaining its view, then releasing the view controller--which will cause it to be deallocated. So now the target of the buttons is a pointer to the deallocated view controller.

A view does not retain its view controller, nor do they retain their delegates or targets.

You'll have to keep the view controller instance retained—perhaps in a retain property—for as long as you want the view to be displayed. When you're done with the view, you can remove it from its parent view, and release the view controller.

这篇关于“正常”UIButton导致obj_stack_overflow或EXC_BAD_ACCESS异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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