в iOS 5 метод, возвращающий NSString, иногда возвращает мусор

У меня есть приложение, которое отлично работает в iOS 4, но происходит сбой при прокрутке UITableView, когда тот же точный код компилируется с использованием iOS5 и XCode 4.2. Код нарушения приведен ниже:

    - (NSString *)getDefaultIconName {
        NSInteger value = [self.iconId characterAtIndex:0] % 4;
        NSString *returnValue = nil;

        switch (value) {
            case 0:
                returnValue = @"default_icon_1";
                break;
            case 1:          
                returnValue = @"default_icon_2";
                break;
            case 2:
                returnValue = @"default_icon_3";
                break;
            case 3:
            default:
                returnValue = @"default_icon_4";
                break;
        }

        return returnValue;
    }

Этот метод вызывается из подкласса UITableViewCell, который создается или повторно используется при вызове cellForRowAtIndexPath. Когда таблица создана и отображаются ячейки, этот вызов возвращает правильную строку. Когда я прокручиваю таблицу вниз, этот вызов возвращает недопустимую ссылку, что приводит к сбою моей попытки сохранить строку в другом классе с EXEC_BAD_ACCESS. В отладчике я вижу, что UITableViewCell существует правильно, и все значения установлены правильно, за исключением возвращаемого значения для этого вызова, которое говорит Invalid CFStringRef.

Как ни странно, если я размещаю оператор NSLog, распечатывающий returnValue перед возвратом, он не падает. То же самое верно, если я проверяю, является ли returnValue isKindOfClass:[NSString class] перед его возвратом.

Третье, что я заметил, это то, что если я компилирую с отключенной оптимизацией кода, он также не падает.

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

edit: Извините, returnValue, в котором отсутствует *, был опечаткой.


person DrewJ    schedule 07.11.2011    source источник
comment
Методы не должны иметь префикс get; это должно быть просто defaultIconName.   -  person bbum    schedule 07.11.2011


Ответы (4)


В коде, который вы вставили, нет ничего явно неправильного, поэтому ищите проблемы (повреждение памяти, чрезмерное количество объектов) в другом месте.

Кроме того, вместо оператора switch() вы можете индексировать массив возвращаемых значений:

NSInteger value = [self.iconId characterAtIndex:0] % 4;
NSString *icons[4] = {@"default_icon_1",
   @"default_icon_2",
   @"default_icon_3",
   @"default_icon_4"};

return icons[value];
person David Gelhar    schedule 07.11.2011
comment
Дэвид, код, который вы предоставили, действительно предотвращает сбой. Однако использование if-else для замены переключателя не работает. Кроме того, просто добавив NSLog(returnValue); перед возвратом также предотвращает сбой. У вас есть идеи, почему это может быть или почему ваше исправление работает? - person DrewJ; 07.11.2011
comment
Это всего лишь случайное решение проблемы — на самом деле в том, что вы делали изначально, нет ничего плохого. Все, что вы видите — проблема исчезает, когда вы отключаете оптимизацию или добавляете операторы NSLog — указывает на какую-то проблему с повреждением памяти (например, продолжение использования объекта после того, как вы выполните release() д это). - person David Gelhar; 07.11.2011
comment
Я посмотрю, смогу ли я воспроизвести этот сценарий в небольшой тестовой среде, и открою отчет об ошибке с помощью Apple. Спасибо. - person DrewJ; 08.11.2011

Добавьте * к returnValue при объявлении. Сейчас это не указатель.

person larsacus    schedule 07.11.2011
comment
Ах, да, вы должны объявить returnValue вот так NSString *returnValue = nil; (если только это не опечатка). - person shookster; 07.11.2011
comment
О, похоже, кто-то уже сказал это в комментарии к исходному вопросу. - person larsacus; 07.11.2011
comment
Извините, * была опечатка при публикации вопроса. - person DrewJ; 07.11.2011
comment
Тогда похоже, что это определенно ваши настройки оптимизации. Попробуйте запустить компилятор с включенным флагом -mno-thumbs, хотя я не совсем уверен, что конкретно он делает. Это решение для сбоев, связанных с оптимизацией, которые я видел в твиттере. - person larsacus; 07.11.2011

Это может быть потому, что в случае 3 вы возвращаете returnValue, когда оно равно нулю? Если это так, установите для returnValue значение по умолчанию.

Также убедитесь, что вы не делите на ноль.

person ader    schedule 07.11.2011
comment
case 3 попадает в дело default. - person Jonathan Grynspan; 07.11.2011
comment
Код определенно не делится на 0, это операция по модулю 4. 0 % 4 вернет 0. Кроме того, в случае 3 нет разрыва, поэтому возвращается значение по умолчанию, а не nil. - person DrewJ; 07.11.2011
comment
дох! конечно, я пропустил отсутствующий перерыв. упомянул только о том, что делится на ноль, поскольку я помню, как обновлял проект до ios5, у меня были предупреждения об этом (когда я запускал анализ), которые мне пришлось исправить. - person ader; 08.11.2011