【问题标题】:Universal iOS app crashing on iPhone/iTouch 3.1.3 due to UIPopoverController由于 UIPopoverController,通用 iOS 应用程序在 iPhone/iTouch 3.1.3 上崩溃
【发布时间】:2011-04-28 08:45:50
【问题描述】:

我刚刚更新了我的应用程序,使其成为通用应用程序。为此,我在某个地方添加了对UIPopoverController 的支持。现在该应用似乎在 3.1.3 iPhone/iTouch 设备上崩溃了:

OS Version:      iPhone OS 3.1.3 (7E18)
Report Version:  104

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x00000001, 0xe7ffdefe
Crashed Thread:  0

Dyld Error Message:
  Symbol not found: _OBJC_CLASS_$_UIPopoverController

我不明白的是,如果硬件是 iPad,我只会尝试调用 UIPopoverController:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:btc];
    CGSize popoverSize = { 300.0, 500.0 };
    popover.delegate = self;
    popover.popoverContentSize = popoverSize;
    self.bmPopover = popover;
    [popover release];

    [self.bmPopover presentPopoverFromBarButtonItem:self.bmBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
    [self presentModalViewController:nav animated:YES];
}

我确实声明了一个 iVar 和一个 UIPopoverController 类型的属性,但如果我实际上没有尝试调用类中的方法,我不会想到这会在运行时引起问题。

如果不支持,我应该怎么做才能确保系统在运行时不会尝试与 UIPopoverController 链接?

【问题讨论】:

  • 崩溃日志的其余部分(您省略了)包含调用堆栈。它会准确地告诉您UIPopoverController 的使用位置。检查调用堆栈或发布它,我们可以提供帮助。
  • 没有堆栈跟踪,因为应用程序在尝试链接时死了,所以它甚至永远不会运行。弱链接似乎可以解决问题。

标签: iphone cocoa-touch xcode ipad ios


【解决方案1】:

对于通用应用程序,您不仅应检查这是否是 ipad 或此类是否存在,还应将 UIKit 链接为弱引用而非默认值(强),以执行此操作:

  1. 获取目标信息
  2. 选择常规
  3. 在链接库中将所需的 UIKit 更改为 UIKit 弱

享受制作通用应用程序的乐趣:]

【讨论】:

  • 如果他是“强”链接,他的应用程序将无法在 3.1 设备上编译和运行。对吗?
  • 看起来将框架从“必需”切换到“弱”解决了这个问题。谢谢!
【解决方案2】:

即使这段代码很可能永远不会在 iPhone 上运行,它仍然会被链接,因此您会收到错误消息。在实例化之前,您需要检查该类是否存在。您可以将上面的代码修改为以下内容。

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    Class UIPopoverControllerClass = NSClassFromString(@"UIPopoverController");
    if (UIPopoverControllerClass != nil) {
        UIPopoverController *popover = [[UIPopoverControllerClass alloc] initWithContentViewController:btc];
        CGSize popoverSize = { 300.0, 500.0 };
        popover.delegate = self;
        popover.popoverContentSize = popoverSize;
        self.bmPopover = popover;
        [popover release];

        [self.bmPopover presentPopoverFromBarButtonItem:self.bmBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    }
} else {
    [self presentModalViewController:nav animated:YES];
}

此外,您可以对 UIKit 框架进行弱链接,这也可以解决问题。我更喜欢代码解决方案,因为它更安全。

【讨论】:

  • 我现在正在尝试这个。不幸的是,我必须将应用程序发送给使用 3.1 设备的人进行测试,因为我无法下载旧版本的 iOS...:(
  • 他必须已经正确地进行了弱链接,否则他的应用程序将无法编译和运行。
  • 如果他的基础 sdk 是 3.2 或更高版本,它将编译并运行。它只是不会在 3.0 设备上启动。
【解决方案3】:

您需要通过引用字符串中的类来停止编译器错误。这应该与 UI_USER_INTERFACE_IDIOM() 一起使用,并将在不了解 UIPopoverController 的 SDK 上编译。这是一个例子:

Class popClass = NSClassFromString(@"UIPopoverController");
if(popClass) {
    id infoPop = [[popClass alloc] initWithContentViewController:popViewController];
    [infoPop presentPopoverFromRect:CGRectMake(20, 70, 10, 10) inView:self.view permittedArrowDirections:4 animated:YES];
}

【讨论】:

  • Nimrod 并未表示他遇到任何编译器错误。
  • 我这样做并使用了弱链接。
【解决方案4】:

简单的答案:

在您的 Xcode 项目中,选择顶级项目图标。执行 Get Info,转到 BUILD 面板。将 Configurations 设置为 All Configurations,将 Show: 设置为 ** All Settings**

iOS 部署目标 设置为 iOS 3.1。

重新编译。您的程序失败,因为最低操作系统设置得太高,因此加载程序无法解析符号 UIPopoverController。我刚刚向您介绍的更改使该符号变弱:它将解析为 NULL,但至少您的程序会加载。


您是否正在加载隐式创建 UIPopoverController 的 NIB 文件?这是另一种崩溃方式。

【讨论】:

  • 这不是真的。如果你实例化一个 UIPopoverController 并将你的基本 SDK 设置为 4.0 并且你的部署目标设置为 3.0,应用程序将在 3.0 - 3.1.3 上崩溃
  • rickharrison 是正确的。但是,它会在您创建/使用UIPopoverController 时崩溃。所以有可能避免崩溃。
  • 在NIB 中可能使用UIPopoverController 是一个很好的观点。
  • 有 3 种可能的崩溃:(1)您引用了 UIPopoverController,即使您从未实例化它,并且您的部署目标设置为 3.2。在这种情况下,您将在加载时失败。 (2) 你尝试在 Obj-C 代码中实例化它 (3) 你加载一个实例化它的 nib 文件。原始海报遭受(1)型崩溃。因此我的回答是正确的,其他人处理的是(2)型崩溃。
【解决方案5】:

我发现添加它很有用,这样我就可以在 3.2 之前的系统上使用 UI_USER_INTERFACE_IDIOM()。

#ifndef __IPHONE_3_2    // if iPhoneOS is 3.2 or greater then __IPHONE_3_2 will be defined

typedef enum {
    UIUserInterfaceIdiomPhone,           // iPhone and iPod touch style UI
    UIUserInterfaceIdiomPad,             // iPad style UI
} UIUserInterfaceIdiom;

#define UI_USER_INTERFACE_IDIOM() UIUserInterfaceIdiomPhone

#endif // ifndef __IPHONE_3_2

【讨论】:

  • 这是不必要的。 UI_USER_INTERFACE_IDIOM() 是 3.2 SDK 中定义的编译时宏。该宏的设计使其在 3.2 之前的操作系统上运行时可以正常工作。只要您将 Base SDK 设置为 3.2 并将部署目标设置为 pre-3.2,您就可以在 pre-3.2 操作系统上使用它。
  • 这很有趣。我使用这种解决方法的原因正是因为 UI_USER_INTERFACE_IDIOM 是未定义的——即使我正在开发一个通用应用程序......
猜你喜欢
  • 2011-04-20
  • 2019-06-25
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-31
  • 2013-11-13
相关资源
最近更新 更多