Цель C NSString* свойство сохранить количество странности
У меня есть следующий пример класса:
test.h:
@interface Test : UIButton {
NSString *value;
}
- (id)initWithValue:(NSString *)newValue;
@property(copy) NSString *value;
Test.m:
@implementation Test
@synthesize value;
- (id)initWithValue:(NSString *)newValue {
[super init];
NSLog(@"before nil value has retain count of %d", [value retainCount]);
value = nil;
NSLog(@"on nil value has retain count of %d", [value retainCount]);
value = newValue;
NSLog(@"after init value has retain count of %d", [value retainCount]);
return self;
}
Который производит следующий вывод:
2008-12-31 09:31:41.755 Concentration[18604:20b] before nil value has retain count of 0
2008-12-31 09:31:41.756 Concentration[18604:20b] on nil value has retain count of 0
2008-12-31 09:31:41.757 Concentration[18604:20b] after init value has retain count of 2147483647
Я называю это так:
Test *test = [[Test alloc] initWithValue:@"some text"];
Не должно ли значение иметь счет сохранения 1? Что мне не хватает?
Спасибо за вашу помощь.
9 ответов
У вас есть ссылка на неизменяемую строку. Присвоение не должно копировать значение (строковые данные), поскольку оно является неизменным. Если вы выполняете изменяемую операцию, например, value = [newValue uppercaseString], то она должна копировать биты в значение, а счет сохранения значения увеличивается.
Не смотрите на удержание счета. Они бесполезны и могут ввести вас в заблуждение - вы не можете быть уверены, что ничто иное не удерживает объект, что объект, который вы откуда-то получаете, не является общим.
Вместо этого сосредоточьтесь на владении объектом и следуйте правилам управления памятью Какао до буквы. Таким образом, ваше управление памятью будет правильным, независимо от того, какие оптимизации может сделать Cocoa за кулисами для вас. (Например, реализация -copy
как раз -retain
для неизменяемых предметов.)
Кроме того, важно понимать разницу между свойствами ваших объектов и переменными экземпляра в ваших объектах. В коде вашего вопроса вы присваиваете значение переменной экземпляра. Эта переменная экземпляра - это просто переменная. Присвоение ему будет вести себя как любое другое присвоение переменной. Чтобы использовать свойство, вы должны использовать либо синтаксис точки, либо синтаксис скобок, чтобы фактически вызвать метод установки свойства:
self.value = newValue; // this is exactly equivalent to the next line
[self setValue:newValue]; // this is exactly equivalent to the previous line
Код, сгенерированный для точечного синтаксиса и синтаксиса скобок, идентичен, и ни один из них не получит прямой доступ к переменной экземпляра.
Вы передаете буквальную строку. Компилятор, вероятно, размещает его в статической памяти и устанавливает максимальное количество сохраняемых данных.
Попробуйте вместо этого динамически распределенную строку и посмотрите, что произойдет.
NSString* string = [[NSString alloc] initWithString: @"some text"];
Test* test = [[Test alloc] initWithValue: string];
Я думаю, что вы хотите сделать это:
self.value = newValue;
который вызовет установщик свойства и вызовет копию. "value = newValue" просто присваивает значение указателя переменной экземпляра.
Вы передаете строковую константу, которая не может быть освобождена. Я думаю, что 2147483647, вероятно, UINT_MAX, что означает, что объект не может быть освобожден.
Вы не должны обращать внимание на количество сохраняемых данных, просто следуйте правилам управления памятью Какао. http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html
Хм.. мы приближаемся
Похоже, что счетчик сохранения newValue также равен 2147483647.
Вместо этого я попытался динамически распределить строку с теми же результатами сохранения количества.
Я нашел полезную статью здесь: http://www.cocoadev.com/index.pl?NSString
FTA:
Нужно ли освобождать строку NSString, возвращаемую символом @", или она автоматически высвобождается? Ни. @""- строки имеют класс NSConstantString? и, таким образом, действуют как атомы в lisp; они торчат. То есть, если вы используете @"cow" в двух разных местах в вашем коде, они будут ссылаться на один и тот же объект. Я не думаю, что -релиз или -авто-релиз делает что-либо с одним из них.
Если у меня есть "copy" для свойства, не должно ли оно скопировать содержимое целевой памяти в новую память с счетом сохранения 1? Казалось бы, атрибут копирования ничего не делает в этом случае?
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char *cstr = "this is a c string";
NSString *str = [[NSString alloc] initWithUTF8String:cstr];
NSLog(@"rc1: %d", [str retainCount]);
[pool drain];
return 0;
}
Если вы запустите приведенный выше код, он будет отображать счет сохранения 1
В Какао многие неизменяемые объекты просто сохраняются, когда вы запрашиваете копию в той же зоне. Если объект гарантированно не изменяется (то есть его неизменность), то точный дубликат является избыточным.
В Objective-C константный класс строки отделен от какао NSString
класс, хотя это может быть подкласс NSString
(Я не слишком уверен). Этот константный класс строки может переопределить NSObject
методы как retain
, release
а также dealloc
так что они ничего не делают, а также переопределяют retainCount
так что он всегда возвращает одно и то же число, UINT_MAX
или так. Это связано с тем, что в статической памяти создается постоянная строка Objective-C. Он должен иметь общее общее поведение объекта Какао (при использовании Какао), чтобы его можно было добавлять в массивы, использовать в качестве ключей к словарю и т. Д., Кроме как в отношении управления памятью, поскольку он был распределен по-другому.
Отказ от ответственности: я на самом деле не знаю, о чем говорю.