【问题标题】:UIAlertView fails to show and results in “EXC_BAD_ACCESS” errorUIAlertView 无法显示并导致“EXC_BAD_ACCESS”错误
【发布时间】:2009-07-06 18:37:32
【问题描述】:

当按下键盘上的返回按钮时调用一个方法。在调用另一个返回整数的方法后,会根据该整数创建一条消息。然后将消息传递到 UIAlterView 并显示给用户。警报没有任何选项(因此我不调用委托),只是简单地通知用户发生了什么。

编辑:下面是完整的方法(之前显示的部分)。当我注释掉 UIAlertView 之前的所有内容并替换字符串 @"test" 而不是传递消息时,警报会成功显示。我的结构没有正确处理内存吗?

- (IBAction)joinButton {
    struct userInfo localUser;

    [emailAddress resignFirstResponder];

    //convert textField text to char array in structure
    localUser.firstName = [self convertStringtoCharArray:firstName.text];
    localUser.lastName = [self convertStringtoCharArray:lastName.text];
    localUser.username = [self convertStringtoCharArray:username.text];
    localUser.email = [self convertStringtoCharArray:emailAddress.text];
    localUser.ipAddress = [self convertStringtoCharArray:localIPAddress.text];
    localUser.latitude = currentLocation.coordinate.latitude;
    localUser.longitude = currentLocation.coordinate.longitude;

    //pass structure to be sent over socket
    int result = [myNetworkConnection registerWithServer:&localUser];

    NSString *message = nil;

    //process result of sending attempt
    if (result == 0) {
        //registration succesful
        message = [NSString stringWithString:@"Registration successful"];
    } else if (result == 1) {
        //server unavailable
        message = [NSString stringWithString:@"Server unavailable. Please check your wi-fi settings and try again."];
    } else if (result == 2) {
        //unable to establish connection
        message = [NSString stringWithString:@"Unable to communicate with server. Please check your wi-fi settings and try again."];
    } else if (result == 3) {
        //username already in use
        message = [NSString stringWithString:@"Username in use. Try another username."];
    }

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Registration"
                                                    message:message
                                                   delegate:nil 
                                          cancelButtonTitle:@"Ok" 
                                          otherButtonTitles:nil];

    [alert show];
    [alert release];
}

当我执行代码时,iPhone 变灰,就像它即将显示警报但崩溃了。我在控制台中收到 EXC_BAD_ACCESS 错误。我是否没有正确发布警报或消息?这是控制台输出:

Program received signal:  “EXC_BAD_ACCESS”.
(gdb) backtrace
#0  0x30011944 in objc_msgSend ()
#1  0x3054803e in NSPopAutoreleasePool ()
#2  0x3054c808 in -[NSAutoreleasePool release] ()
#3  0x30936ac4 in _UIApplicationHandleEvent ()
#4  0x3204696c in PurpleEventCallback ()
#5  0x30254a76 in CFRunLoopRunSpecific ()
#6  0x3025416a in CFRunLoopRunInMode ()
#7  0x320452a4 in GSEventRunModal ()
#8  0x308f037c in -[UIApplication _run] ()
#9  0x308eea94 in UIApplicationMain ()
#10 0x000020bc in main (argc=1, argv=0x2ffff508) at /Users/reu2009/Documents/iPhone Development/Development/BuddyTracker/main.m:14
(gdb) frame 10
#10 0x000020bc in main (argc=1, argv=0x2ffff508) at /Users/reu2009/Documents/iPhone Development/Development/BuddyTracker/main.m:14 14       int retVal = UIApplicationMain(argc, argv, nil, nil);

编辑:删除了[message release];,并根据答案使用[NSString stringWithString];分配了字符串。

【问题讨论】:

  • 如果将 message:message 替换为 message:@"test" 是否有效?
  • 没有。同样的错误。我什至注释掉了条件消息创建块。
  • 很奇怪。您是否尝试过单步调试器以找出错误发生在哪一行?我只是好奇我们是不是找错地方了。
  • 它出现在方法的最后。你似乎是对的,Ken,这是该方法的早期内容(请参阅最新编辑)。
  • 尝试在方法的顶部添加断点。然后使用 step into 选项单步执行每一行。您已将其范围缩小到 UIAlertView 行以上,但仍然很难看出问题所在。当出现 EXC-BAD-ACCESS 消息时,无论调试器停留在哪一行,这都是您的问题行。有关调试基础知识的精彩视频,请参阅 Jeff LaMarche 关于调试的博客文章:iphonedevelopment.blogspot.com/2009/03/debugging.html

标签: iphone memory-management uialertview exc-bad-access


【解决方案1】:

我遇到了这样的问题...我从后台线程调用 uiAlertView ....从主线程调用它

【讨论】:

【解决方案2】:

从便捷构造函数返回的对象已经设置为自动释放。当你声明了一个指向“message”的指针时,“message”对象本身并不属于你,因为你使用了@"string" 便利构造函数来创建 NSString 对象。因此,您不需要释放它。

当您手动释放它时,它会被释放太多次(一次手动,一次在自动释放过程滚动时)并引发错误。

以下是来自 Apple 的一些附加信息:

http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html

良好的经验法则:除非您使用 alloc 或 init 或 copy 方法之一来创建对象(或者如果您自己保留该对象),您不需要释放它,但可以依赖实际的方法创建它是为了为您完成这项工作。

【讨论】:

  • 谢谢。但是,删除[消息发布]后;我犯了同样的错误。一定是消息字符串释放之外的东西。
  • 好吧,那我很困惑。 :) 我会尝试 Ken 的建议,并且可能会注释掉“int result...”这一行,看看其中是否有任何可能以某种方式影响问题。
  • 我相信规则是包含 alloc、retain 或 copy 的方法要求你释放对象。
  • 替换消息字符串或注释“int result”行都不会导致显示警报。在键盘上“返回”后调用它可能有什么关系吗?我已经调用了 [textfield resignFirstResponder];但是可见的键盘会产生警报吗?
  • 添加了关于保留对象的注释。谢谢,马克!
【解决方案3】:

尝试使用 NSZombieEnabled = YES。

  • 进入可执行文件的信息。
  • 单击“参数”选项卡。
  • 点击“要在环境中设置的变量”上的 +。
  • 键入 NSZombieEnable 和 YES。

当已经释放的内存被释放时,NSZombie会显示地址,然后你可以使用Instruments找到实际的对象。 Corbin 的 Treehouse 很好地概述了如何做到这一点: Instruments on Leopard: How to debug those random crashes in your Cocoa app

【讨论】:

    【解决方案4】:

    Sean 是对的 - 您无需在此处调用 [message release],因为您实际上从未保留消息对象。

    你需要说message = @"string",而不是只说message = [NSString stringWithString:@"string"];。老实说,我不知道为什么(也许有人可以发表评论,我可以改进这篇文章!)但这应该可以解决问题。

    【讨论】:

    • 我很确定它们会做同样的事情...@"string"[NSString stringWithString:@"string"] 都返回非保留的 NSStrings。
    【解决方案5】:

    我在这里遇到了与 UIAlertView 相同的问题,在我的情况下,我有另一个实现警报的类,并且从另一个类中调用了一个静态方法。像下面这样:

    ClassA
    
    ...
    
    doSomething {
     ... some stuff ...
    
     [MyAlertView showAlert];
    
     ... some other stuff...
    
    }
    

    我怀疑的是,当我单击按钮时,警报视图是异步显示的,对象已经被释放。

    为了验证这一点,我更改了代码以实例化警报而不是释放它。一切正常。

    我的最终解决方案是在父视图中声明一个变量,并在视图被释放时将其与其他变量一起释放。

    【讨论】:

      【解决方案6】:

      这可能是由于从后台线程更新 UIKit 造成的

      我是这样解决的

      UIAlertView *alertMSG = [[UIAlertView alloc] initWithTitle:nil
                              message:@"Your mnessage here"
                              delegate:self
                              cancelButtonTitle:@"Title here"
                              otherButtonTitles: nil];
      
          [[NSOperationQueue mainQueue] addOperationWithBlock:^{
               [alertMSG show];
          }];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-20
        • 2011-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        相关资源
        最近更新 更多