Objective C NSString выпущен в синглтоне - PullRequest
0 голосов
/ 07 февраля 2010

Я создаю небольшое приложение для iphone и использую одиночный файл для хранения и обновления строки, которая обновляется, когда пользователь нажимает буквы или цифры на экране, чтобы сформировать код.

т.е. они нажимают 3, затем S, затем 4, и мне нужно отследить и объединить этот ввод, чтобы сказать «3S4». Когда синглтон инициализируется, он создает пустую строку NSString, а затем я использую метод stringByAppendString, чтобы добавить следующую нажатую букву / цифру. Когда я впервые попробовал это, у меня не было строки [enterCode retain], и приложение зависало с EXC_BAD_ACCESS, всегда после 2 входов. Я установил свойство NSZombie, которое сообщало мне о том, что enterCode был распределен, но я не знаю, где и как это произошло. Все, что я знаю, это то, что в конце метода addInput он сообщит, что значение retainCount будет равно 2, а затем сразу же после того, как я смогу увидеть (вызывая синглтон из другого места), оно упадет до 1 (когда строка удержания будет там ).

Мой вопрос: хотя то, что я сделал, добавив [enterCode retain], работает для меня, нарушаю ли я некоторые правила здесь или поступаю неправильно или неправильно? Я просто не понимаю, почему освобождается строка.

Я новичок в Objective-C, кстати

в MySingleton.h

@interface MySingleton : NSObject {
   NSString *enteredCode;
}   

в MySingleton.m

-(void) addInput:(NSString *) input
{ 
  NSLog(@"enteredCode retain count is : %d \n ",[enteredCode retainCount]);

  enteredCode = [enteredCode stringByAppendingString:input];

 NSLog(@"enteredCode retain count is : %d \n ",[enteredCode retainCount]);

 [enteredCode retain]; // without this the app crashes

 NSLog(@"enteredCode retain count is : %d \n ",[enteredCode retainCount]);

}

-(id) init
{
    self = [super init];

    if (self)
    {
        enteredCode = @"";


    }

    return self;
}

Ответы [ 3 ]

3 голосов
/ 07 февраля 2010

Во-первых, никогда не используйте метод -retainCount. Абсолютное количество сохранений в объекте - это деталь реализации фреймворков, которая часто дает неверные результаты.

Сохранять счет - это то, что вы должны поддерживать как сбалансированный набор дельт. Если вы заставляете счет сохранения быть добавленным к чему-либо, вы должны release или autorelease этот объект где-нибудь. Конец истории.

Этот документ объясняет все это .

С этими знаниями источник вашей аварии - довольно распространенная ошибка управления памятью.

  enteredCode = [enteredCode stringByAppendingString:input];

Каждый раз, когда выполняется эта строка кода, вы заменяете enteredCode на автоматически выпущенный экземпляр NSString. Пул автоматического выпуска очищается, и ваша программа аварийно завершает работу при следующем использовании enteredCode.

Ваше решение о сохранении enteredCode - это только половина решения. Вам также необходимо убедиться, что исходное значение enteredCode также сброшено. См. Документы по управлению памятью.

Если бы это было мое приложение, я бы превратил enteredCode в @property, который копирует строку и всегда устанавливает и обращается к enteredCode через это свойство, никогда не сохраняя или не выпуская его вручную в моем коде (за пределами -dealloc конечно).

1 голос
/ 07 февраля 2010

Вот как должен выглядеть ваш код:

@interface MySingleton : NSObject {
    NSString *enteredCode; 
}

@property (nonatomic, retain) NSString *enteredCode;

@end


@synthesize enteredCode;

-(void) addInput:(NSString *) input
{ 
    self.enteredCode = [self.enteredCode stringByAppendingString:input];
}

- (void)dealloc {
    [enteredCode release];
}

@end
1 голос
/ 07 февраля 2010

NSString stringByAppendingString: возвращает новую NSString, созданную путем добавления одной строки к другой, а для новой NSString задано значение autorelease, что очищает пул авто-выпуска, и при следующем запуске происходит сбой приложения. Вы переопределяете существующую строку с помощью stringByAppendingString:, и это вызывает проблемы с сохранением. (В качестве альтернативы используйте NSMutableString, и вы можете избежать этого.)

Кстати, вы можете сделать if (self = [super init]) в вашем init переопределении. Объявление возвращает true, если оно происходит или может произойти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...