UIButton 操作在一段时间后不起作用(可能在一些垃圾收集之后)

Posted

技术标签:

【中文标题】UIButton 操作在一段时间后不起作用(可能在一些垃圾收集之后)【英文标题】:UIButton action doesn't work after some time (probably after some garbage collection) 【发布时间】:2012-08-01 13:21:33 【问题描述】:

我有一个 UIView,其中包含大约 60 个调用相同方法的按钮。单击按钮时,我通过这种方法打开不同的图像 - 我使用按钮标签来了解调用了哪个按钮以及要显示哪个图像。把它想象成一个画廊。

由于按钮的绘制很困难,我为此使用了 Interface Builder 并使用该 UIView 创建了一个 XIB。我只是将按钮拖到正确的位置,然后在事件 TouchUpInside 中将它们连接到我的方法。我用它来将视图添加到我的主视图中:

NSArray *xibContents = [[NSBundle mainBundle] loadNibNamed:@"Tour" owner:self options:nil];
UIView *tour = [xibContents lastObject];
[self.view addSubview:tour];

到目前为止一切顺利,乍一看效果很好。不幸的是,当应用程序使用了一段时间时,会出现一些问题。按钮仍然突出显示(所以它们仍然在这里!)但不再调用任何操作。只有亮点,没有动作。

我不知道为什么,但不知何故垃圾收集器似乎破坏了 UIButton 目标。为什么?我该如何解决?

请注意,我没有以编程方式声明按钮。我认为将它们放在 IB 中就足够了。

我也找不到内存警告和 UIButton 目标的破坏之间的联系。内存警告确实出现在我的应用程序中,但大多数时候按钮仍然有效。

但它必须是垃圾收集器,因为错误完全随机出现。无法重现此错误,有时在单击 5 次后发生,有时在我的应用程序中花费 10 分钟后发生。

【问题讨论】:

如果您使用 ARC,则没有垃圾收集,并且按钮与当前视图有很强的链接。如果您不使用 ARC,那么可能是您在释放对象。你所描述的没有任何明显的问题;您需要添加更多细节。 抱歉,描述起来有点复杂。是的,我正在使用 ARC,我只是再次检查了我的项目以确定。不,我不释放我的任何物品。我注意到:当我以编程方式添加选择器时,它会继续工作。所以问题出在某种程度上与 IB 连接的方式有关。我确实可以通过编程方式解决这个问题,但是对于超过 60 个按钮来说,这还有很长的路要走...... 将按钮添加到数组中,然后使用 for 循环添加选择器。 Dustin:可以选择,但我需要通过 IB 手动连接它们,对吧?不是很优雅,但当然可以。还是有更好的选择? 【参考方案1】:

这是向所有按钮添加选择器的最简单方法。

for (UIView* view in self.view.subviews)
    if ([view isKindOfClass:[UIButton class]])
    
         //Add selector
    

【讨论】:

相反,这听起来像是IBOutletCollection 的工作。 @Jesper 如果他有 60 个按钮,则不会 我从未听说过 IBOutletCollection,我不得不尝试一下。对我来说效果很好!当然,其他解决方案也是如此。 @Dustin:无论如何,这都是经过深思熟虑的。虽然我认为首先阅读目标是在掩盖一些东西。【参考方案2】:

您可以尝试像这样加载您的笔尖:

首先,在您的标头中创建一个 IBOutlet 属性。然后,当您创建 Nib 时,将该 UIView IBOutlet 连接到 Nib 中的***视图(所有内容都位于该视图上)。然后在你的实现中,像这样加载它:

 [[NSBundle mainBundle] loadNibNamed:@"Tour" owner:self options:nil];
 // self.view if in a view controller
 [self addSubview:self.tourView]; 

我的猜测是,可能是指向按钮的指针停止工作,但不是来自垃圾收集,因为这种情况不会发生

要调试,您可以尝试以下操作:

 for (UIView* view in self.view.subviews)
     if ([view isKindOfClass:[UIButton class]])
     
               if([self.view respondsToSelector:@selector(myIBAction:)])
                   NSLog(@"it still sees the method");
                

         NSLog(@"Button Rect: .2%f, .2%f, .2%f, .2%f", view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
      

正如我在 cmets 中提到的

【讨论】:

我刚才试过了,但是指针仍然随机停止工作。如前所述,它在第一次加载时工作。奇怪! 哇,我想说@Dustin 刚才提到的在调试方面是个好主意。循环遍历子视图,但不是添加选择器,而是查看按钮是否仍以编程方式显示,以及是否仍附加选择器。记录的另一个有用的东西(使用 NSLog 或断点)是 CGRect...然后你知道指针是否指向实际的接口项 在这种情况下,仅当您稍后在视图生活中寻找子视图时,此搜索子视图才有价值...也许与 [self performSelector:@selector(searchForButton) withObject:nil afterDelay:30 ]【参考方案3】:

当事情出错时重新设定目标就是告诉它做错事的声音稍微大一点或更坚持。

你必须找到这个问题的原因。运行 Instruments (Build → Profile),选择 Allocations 模板并让您的应用启动。运行直到问题发生,然后按左上角的红色录制按钮停止在 Instruments 中录制。

在左侧列表中选择 Allocations 工具,在跨越时间线下方窗口的跳转栏中从 Statistics 更改为 Objects List。现在,每个要分配、保留、释放和释放的对象都有一行。单击小箭头可查看每个对象的历史记录。 (严格来说,它是针对每个内存地址的;许多对象可以在应用程序运行时重用相同的内存地址。)您还可以按右上角的任何内容进行过滤,展开右侧边栏以获得有关所选内容的完整堆栈跟踪双击条目以与源代码关联。

有很多关于乐器的知识;检查文档并搜索网络。但这肯定会告诉您正在发生什么,以便您可以推断为什么会发生或没有发生什么。

【讨论】:

以上是关于UIButton 操作在一段时间后不起作用(可能在一些垃圾收集之后)的主要内容,如果未能解决你的问题,请参考以下文章

Android - 前台在 Oreo 中不起作用。操作系统在一段时间后终止服务

Android模拟器状态栏在一段时间后消失

为啥我的贴纸在(可能)2 周后不起作用?

jquery datepicker ms ajax updatepanel在回发后不起作用

触摸屏诺基亚 C5 -J2ME 的命令操作按钮和滚动在更改系统时间后不起作用

Firebase 推送通知在几周后不起作用