UIAlertView не отображается и приводит к ошибке «EXC_BAD_ACCESS»

Метод вызывается при нажатии кнопки возврата на клавиатуре. После вызова другого метода, который возвращает целое число, создается сообщение на основе этого целого числа. Затем сообщение передается в 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]; на основе ответов.


person Eric de Araujo    schedule 06.07.2009    source источник
comment
это сработает, если вы замените сообщение: сообщение сообщением: @test?   -  person Ken Pespisa    schedule 06.07.2009
comment
Та же ошибка. Я даже закомментировал блок создания условного сообщения.   -  person Eric de Araujo    schedule 06.07.2009
comment
Очень странно. Вы пытались пройти через отладчик, чтобы выяснить, в какой строке возникает ошибка? Мне просто любопытно, если мы ищем не в том месте.   -  person Ken Pespisa    schedule 07.07.2009
comment
Это происходит в самом конце метода. Кажется, ты прав, Кен, это что-то более раннее в методе (см. Последнее редактирование).   -  person Eric de Araujo    schedule 07.07.2009
comment
Попробуйте добавить точку останова в начале вашего метода. Затем используйте опцию step into, чтобы пройти через каждую строку. Вы сузили его до чего-то выше строки UIAlertView, но все еще слишком сложно понять, в чем проблема. На какой бы строке ни застрял отладчик при появлении сообщения EXC-BAD-ACCESS, это будет ваша проблемная строка. Хорошее видео об основах отладки см. в записи блога Джеффа Ламарша об отладке: iphonedevelopment. blogspot.com/2009/03/debugging.html   -  person Ken Pespisa    schedule 07.07.2009


Ответы (6)


у меня была такая проблема... я вызывал uiAlertView из фонового потока.... вызывал его из основного потока

person j2emanue    schedule 13.11.2012
comment
Это была именно моя проблема. Спасибо. - person a1phanumeric; 15.11.2012
comment
Пример того, что означает j2emanue, см. в разделе stackoverflow.com/questions/12468677/ - person Ben Wheeler; 13.06.2013

Объекты, возвращаемые из удобных конструкторов, уже настроены на автоматическое освобождение. Хотя вы объявили указатель на «сообщение», сам объект «сообщение» вам не принадлежит, поскольку вы использовали удобный конструктор @"string" для создания объекта NSString. Таким образом, вам не нужно его выпускать.

Когда вы выпускаете его вручную, он затем освобождается слишком много раз (один раз вручную и один раз, когда процесс автоматического выпуска повторяется) и выдает ошибку.

Вот дополнительная информация от Apple:

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

Хорошее эмпирическое правило: если вы не используете один из методов alloc, init или copy для создания объекта (или если вы сохраняете объект самостоятельно), вам не нужно освобождать его, но вы можете положиться на метод, который фактически создал его для сделать эту работу для вас.

person Sean McMains    schedule 06.07.2009
comment
Спасибо за это. Однако после удаления [выпуска сообщения]; Я получаю ту же ошибку. Это должно быть нечто большее, чем выпуск строки сообщения. - person Eric de Araujo; 06.07.2009
comment
Ну тогда я в недоумении. :) Я бы попробовал предложение Кена и, возможно, прокомментировал строку int result..., чтобы увидеть, может ли какой-либо из них так или иначе повлиять на проблему. - person Sean McMains; 06.07.2009
comment
Я считаю, что правило заключается в том, что методы, содержащие выделение, сохранение или копирование, требуют освобождения объекта. - person Mark; 06.07.2009
comment
Ни замена строки сообщения, ни комментирование строки результата int не приводят к отображению предупреждения. Может ли это быть связано с тем, что это вызывается после возврата на клавиатуре? Я вызвал [текстовое поле resignFirstResponder]; но будет ли видимая клавиатура вызывать предупреждение? - person Eric de Araujo; 06.07.2009
comment
Добавлено примечание о сохранении объекта. Спасибо, Марк! - person Sean McMains; 06.07.2009

Попробуйте с NSZombieEnabled = YES.

  • Зайдите в информацию о вашем исполняемом файле.
  • Нажмите на вкладку Аргументы.
  • Нажмите + на «Переменные, которые нужно установить в среде».
  • Введите NSZombieEnable и YES.

Когда освободится память, которая уже была освобождена, NSZombie отобразит адрес, после чего вы сможете использовать Инструменты для поиска фактического объекта. В Treehouse Корбина есть хороший обзор того, как это сделать: Инструменты для Leopard: как отлаживать эти случайные сбои в вашем приложении Cocoa

person hanleyp    schedule 06.07.2009

Шон прав - вам не нужно вызывать здесь [выпуск сообщения], потому что вы фактически никогда не сохраняете объект сообщения.

Вместо того, чтобы просто сказать message = @"string", вам нужно сказать message = [NSString stringWithString:@"string"]; Честно говоря, я не знаю, почему (может быть, кто-то может прокомментировать, и я смогу улучшить этот пост!), но это должно сработать.

person Ben Gotow    schedule 06.07.2009
comment
Я почти уверен, что они делают то же самое... @"string" и [NSString stringWithString:@"string"] оба возвращают несохраненные NSStrings. - person davidcann; 10.02.2010

У меня была та же проблема с UIAlertView, в моем случае у меня был другой класс, реализующий предупреждение, и из другого я вызывал статический метод. Как следующее:

ClassA

...

doSomething {
 ... some stuff ...

 [MyAlertView showAlert];

 ... some other stuff...

}

Я подозреваю, что, поскольку окно оповещения отображается асинхронно, когда я нажимал кнопку, объект уже был выпущен.

Чтобы убедиться в этом, я изменил код, чтобы создать экземпляр предупреждения, а не выпускать его. И все работало.

Мое окончательное решение состояло в том, чтобы объявить переменную в родительском представлении и освободить ее вместе с другими переменными при освобождении представления.

person Jose Muanis    schedule 29.03.2010

Это может быть связано с обновлением UIKit из фонового потока.

Я решил это так

UIAlertView *alertMSG = [[UIAlertView alloc] initWithTitle:nil
                        message:@"Your mnessage here"
                        delegate:self
                        cancelButtonTitle:@"Title here"
                        otherButtonTitles: nil];

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
         [alertMSG show];
    }];
person Azhar    schedule 08.03.2014