Objective C NSString* свойство сохранять количество странностей
-
03-07-2019 - |
Вопрос
У меня есть следующий пример класса:
Тест.h:
@interface Test : UIButton {
NSString *value;
}
- (id)initWithValue:(NSString *)newValue;
@property(copy) NSString *value;
Тест.м:
@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"];
Разве значение value не должно иметь значение retain, равное 1?Что я упускаю из виду?
Спасибо за вашу помощь.
Решение 5
У вас есть ссылка на неизменяемую строку.Присваиванию не нужно копировать значение (строковые данные), поскольку оно является неизменяемым.Если вы выполняете изменяемую операцию, например value = [newValue uppercaseString], то она должна скопировать биты в value, а количество сохраняемых значений увеличить.
Другие советы
Не смотрите на количество удержаний.Они бесполезны и только введут вас в заблуждение — вы не можете быть уверены, что ничто другое не сохраняет объект, что объект, который вы откуда-то получаете, не является общим.
Вместо этого сосредоточьтесь на право собственности на объект и следуйте инструкциям Правила управления памятью Cocoa до последней буквы.Таким образом, ваше управление памятью будет правильным независимо от того, какие оптимизации 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];
Вы передаете строковую константу, которая на самом деле не может быть освобождена.Я думаю, что 2147483647, вероятно, является UINT_MAX , что в основном означает, что объект не может быть освобожден.
Я думаю, ты хочешь это сделать:
self.value = newValue;
который вызовет установщик свойств и вызовет копирование."value = newValue" просто присваивает значение указателя переменной экземпляра.
Вам не следует обращать внимание на количество сохранений, просто следуйте правилам управления памятью Cocoa. http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html
хм..мы подбираемся все ближе.
похоже, что количество сохраняемых значений newValue также равно 2147483647.
Вместо этого я попытался динамически выделить строку с теми же результатами подсчета количества сохранений.
Я нашел здесь полезную статью: http://www.cocoadev.com/index.pl?NSString
Соглашение О свободной торговле:
Нужно ли освобождать NSString, возвращаемую с помощью @"", или она автоматически освобождается?Ни то, ни другое.@""-строки относятся к классу NSConstantString?, и, таким образом, действуют как атомы в lisp;они околачиваются поблизости.То есть, если вы используете @"cow" в двух разных местах вашего кода, они будут ссылаться на один и тот же объект.Я не думаю, что -release или -autorelease что-либо делают с любым из них.
Если у меня есть "копировать" в свойстве, разве оно не должно копировать содержимое целевой памяти в новую память с количеством сохранений, равным 1?Казалось бы, атрибут copy в этом случае ничего не делает?
#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
В Cocoa многие неизменяемые объекты просто сохранят себя, когда вы запросите копию в пределах той же зоны.Если объект гарантированно не изменится (т. е.его неизменность), то точный дубликат является избыточным.
В Objective-C класс constant string является отдельным от класса Cocoa NSString
класс, хотя это может быть подкласс NSString
(Я не слишком уверен).Этот класс constant string может переопределять NSObject
такие методы, как retain
, release
и dealloc
так что они ничего не делают, а также переопределяют retainCount
чтобы он всегда возвращал одно и то же число, UINT_MAX
или около того.Это происходит потому, что постоянная строка Objective-C создается в статической памяти.Он должен иметь общее поведение объекта Cocoa (при использовании Cocoa), чтобы его можно было добавлять в массивы, использовать в качестве ключей к словарю и т.д., за исключением управления его памятью, поскольку оно было выделено по-другому.
Отказ от ответственности:На самом деле я не знаю, о чем говорю.