在 iOS 7 上带有 UIBarButtonItem 外观的 EXC_BAD_ACCESS

Posted

技术标签:

【中文标题】在 iOS 7 上带有 UIBarButtonItem 外观的 EXC_BAD_ACCESS【英文标题】:EXC_BAD_ACCESS with UIBarButtonItem appearanceWhenContainedIn on iOS 7 【发布时间】:2013-10-01 19:40:33 【问题描述】:
//Set all cancel buttons in search bars to "Done"
id searchBarButton = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];
if([[[UIDevice currentDevice] systemVersion] floatValue] < 7) 
    [searchBarButton setTitle:@"Done"];
 else 
    //Can't do anything here or i get EXC_BAD_ACCESS

这在viewDidLoad 中调用时会给出 EXC_BAD_ACCESS,仅在 ios 7 Gold Master 和更高版本上。 iOS 7 beta 6 及更早版本都可以。

在 iOS 7 中是否有其他方法可以做到这一点?

NSLog("%@", searchBarButton) 在 iOS7 上会产生这样的结果:

2013-10-01 16:14:25.972 MP Staging[12293:a0b] <_UIBarItemAppearance:0x1aaf72d0> <Customizable class: UIBarButtonItem> when contained in ( UISearchBar ) with invocations (null)>

这在 iOS 6 上

&lt;_UIBarItemAppearance: 0x1c671aa0&gt;

【问题讨论】:

【参考方案1】:

setTitle 在 iOS7 中会失败。

试试下面来自this博客的代码:

-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
    self.searchDisplayController.searchBar.showsCancelButton = YES;
    UIButton *cancelButton;
    UIView *topView = self.searchDisplayController.searchBar.subviews[0];
    for (UIView *subView in topView.subviews) 
        if ([subView isKindOfClass:NSClassFromString(@"UINavigationButton")]) 
            cancelButton = (UIButton*)subView;
        
    
    if (cancelButton) 
      //Set the new title of the cancel button
        [cancelButton setTitle:@"Annuller" forState:UIControlStateNormal];
    

【讨论】:

如果我在cancelButton = (UIButton*)subview 设置断点,它永远不会到达它 我将self.searchDisplayController.searchBar 更改为self.venueSearchBar 并添加了一个断点。两个子视图类是UISearchBarBackgroundUISearchBarTextField 好的,现在试试更新,你需要把这段代码放在searchDisplayControllerWillBeginSearchdelegate中。 如果我将此代码放入searchDisplayControllerWillBeginSearch,它不起作用,但如果我将其放入searchDisplayControllerDidBeginSearch,它会显示“取消”一秒钟,然后淡入“完成” 我将代码放入searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString,它实际上给了我想要的效果。在您开始输入之前,它会显示“取消”,然后在您开始输入时显示完成【参考方案2】:

我在 7.1 中使用它没有任何问题,但是,它似乎在 7.0.x(设备和 sim)上崩溃了 - 希望这意味着他们已经在 7.1 中恢复了该属性,但这也意味着我们对于临时版本,必须使用上述子视图遍历黑客之一。

    id barButtonAppearanceInSearchBar = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];
    [barButtonAppearanceInSearchBar setTitleTextAttributes:@NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue" size:15],
                                                             NSForegroundColorAttributeName : [UIColor blackColor]
                                                              forState:UIControlStateNormal];
    [barButtonAppearanceInSearchBar setTitle:@"Done"];

【讨论】:

【参考方案3】:

UIBarButtonItemtitle 属性无法通过UIAppearance 代理使用。

我不知道为什么它可以在 iOS 6 中运行,但绝对不应该这样。

您似乎唯一的选择是“破解”UISearchBar,方法是爬取其子视图以查找按钮并设置标题,但是:

非常脆弱,因为对子视图结构的任何实现更改都会破坏您的代码 这不是全局的,您必须在任何 UISearchBar 实例上执行此操作

根据this answer,您可以在UISearchDisplayDelegatesearchDisplayControllerWillBeginSearch: 方法中执行此“hack”,如下所示:

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller 
     [theSearchBar setShowsCancelButton:YES animated:NO];

    UIButton *cancelButton;
    UIView *topView = theSearchBar.subviews[0];
    for (UIView *subView in topView.subviews) 
        if ([subView isKindOfClass:NSClassFromString(@"UINavigationButton")]) 
            cancelButton = (UIButton*)subView;
        
    
    if (cancelButton) 
        [cancelButton setTitle:@"YourTitle" forState:UIControlStateNormal];
    

【讨论】:

那么在 ios6 和 ios7 上设置取消按钮文本的最佳做法是什么? 如果我将此代码放入searchDisplayControllerWillBeginSearch,它不起作用,但如果我将其放入searchDisplayControllerDidBeginSearch,它会显示“取消”一秒钟,然后淡入“完成”

以上是关于在 iOS 7 上带有 UIBarButtonItem 外观的 EXC_BAD_ACCESS的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 7 上带有 UIBarButtonItem 外观的 EXC_BAD_ACCESS

带有自定义单元格的 UITableView 在 iOS 6 上画得很好,但在 iOS 7 上完全是白色的

如何在带有 ios 7.0.2 的 iphone 5 上运行 xcode 5 项目

我可以将带有 iOS 8 扩展的应用程序部署到运行 iOS 7 的设备上吗?

iOS 7 + Calabash:带有 NSLinkAttributeName 的 UITextView 和链接上的可访问性不起作用

在 iOS 7 上更改标签栏色调颜色