iphone назначает переменные экземпляра - PullRequest
1 голос
/ 14 июня 2009

Я только что провел последние 3 часа, пытаясь выяснить эту ошибку. Я хотел бы, чтобы кто-то объяснил мне это, чтобы я не делал это снова.

Я назначил переменную экземпляра NSString без использования "self". Когда класс («я») вышел, я получил ошибку «плохой доступ». Я сделал то же самое в другом классе с теми же объявлениями переменных, и у меня нет этой ошибки. Ниже мой код. Я закомментировал строку, которая сломалась, и строка ниже исправляет это. Но я не понимаю почему ... Обратите внимание, что есть другие переменные экземпляра, которые не вызывают эту проблему. Должен ли я всегда использовать зарезервированное слово «self» при назначении переменных экземпляра? Пожалуйста, дайте мне знать.

декларации

@property (nonatomic, readonly, assign) int IID;
@property (nonatomic, assign) int ProfileIID;
@property (nonatomic, retain) NSDate *NoteDate;
@property (nonatomic, copy) NSString *NoteText;

фрагмент кода

    // the default date format is Year-Month-Day 
NSDateFormatter *df = [[[NSDateFormatter alloc] init] autorelease];
[df setDateFormat:kDateFormat];

IID = sqlite3_column_int(selectstmt, 0);
ProfileIID = sqlite3_column_int(selectstmt, 1);

// notice this does not cause a memory error
NoteDate = [[df dateFromString: [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)]] retain];    

// the following may be NULL.  Checking using the sqlite3_column_text method
const char *columnText = (const char *)sqlite3_column_text(selectstmt, 3);
if(columnText != NULL)
{
    // this causes a memory error
    //NoteText = [NSString stringWithUTF8String: columnText ];
    // this does not cause memory error
    self.NoteText = [NSString stringWithUTF8String: columnText ];
}

Ответы [ 3 ]

5 голосов
/ 14 июня 2009

Причина, по которой

NoteDate = [[df dateFromString: [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)]] retain]; 

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

Если переменные возвращаются автоматически освобожденными, то они освобождаются при сливе пула автоматического выпуска, который происходит в конце каждого события (подробнее см. пули автоматического выпуска ). Это не хорошо с переменной экземпляра, потому что она должна остаться после текущего события.

Когда вы назначаете переменную с помощью:

NoteText = [NSString stringWithUTF8String: columnText];

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

Называя его так:

self.NoteText = [NSString stringWithUTF8String: columnText];

действительно сохраняет строку, так как строка является другим способом записи:

[self setNoteText:[NSString stringWithUTF8String: columnText]];

, который вызывает ваш метод установки и сохраняет переменную, предотвращая ее освобождение в конце текущего события.

4 голосов
/ 14 июня 2009

Назначение NoteText из метода класса не вызывает метод синтезированного сеттера, он непосредственно устанавливает переменную экземпляра. Это означает, что ваша строка не сохраняется (или копируется, в случае вашего установщика), и сбой происходит при попытке освободить объект, который уже был освобожден. Сделайте это:

self.NoteText = [NSString stringWithUTF8String: columnText ];

Это вызовет ваш сеттер, и все будет хорошо.

Редактировать : Просто чтобы быть ясно, это верно для всех иваров.

myVariable = someValue;  // Sets the ivar directly.
self.myVariable = someValue;  // calls [self setMyVariable].
0 голосов
/ 15 июня 2009

Эта путаница между методами ивара и сеттера - вот почему я никогда не называю мои сеттеры и мои ивары одинаковыми.

Apple обычно называет свои ивары, начиная с подчеркивания (_), например NoteText. В моем случае я использовал префикс i для иваров. Например:

NSString* i_name;

@property (nonatomic, copy) NSString* name;

@synthesize name = i_name;

Таким образом, вы можете легко определить разницу между назначением ивара:

i_name = [[whatever title] retain];

и вызов метода установки

self.name = [whatever title]; // Equivalent to [self setName:[whatever title]

Сеттер, так как он определен с помощью copy (или аналогично для retain), получит владение переданной переменной и освободит владение старым значением. Назначение ivar ничего не делает.

Также обратите внимание, что ваши собственные имена должны начинаться со строчной буквы, иначе они не будут KVO-совместимыми .

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