#iphone #objective-c #initialization #init #alloc
#iPhone #objective-c #инициализация #alloc
Вопрос:
Итак, вот мой сценарий — в заголовочном файле класса, который я делаю:
@interface MyClass : NSObject
{
NSString *string1;
NSString *string2;
}
- (void) methodOne: (NSString *) passedString;
- (void) methodTwo: (NSString *) passedString;
@end
В файле реализации я делаю это:
#import MyClass.h
@implementation MyClass
- (void) methodOne: (NSString *) passedString
{
NSLog(@"%@", passedString);
string1 = passedString;
}
- (void) methodTwo: (NSString *) passedString
{
NSLog(@"%@", passedString);
string2 = passedString;
}
Я обнаружил, что при выполнении этого есть какая-то несогласованность по сравнению с [NSString alloc] initWithString:] .
Как вы можете видеть, string1 и string2 обрабатываются точно так же, но происходит то, что string1 устанавливается, но string2 остается пустым. Я получаю плохой доступ, когда ссылаюсь на него позже.
Я подумал, что, возможно, я передаю пустую строку в methodTwo: поэтому я добавил этот NSLog, который доказывает, что он не пустой, но имеет ожидаемую строку.
Поскольку я заметил это несоответствие до того, как решил перейти на это:
- (void) methodOne: (NSString *) passedString
{
NSLog(@"%@", passedString);
string1 = passedString;
}
- (void) methodTwo: (NSString *) passedString
{
NSLog(@"%@", passedString);
string2 = [[NSString alloc] initWithString: passedString];
}
Теперь обе строки работают должным образом. Мой вопрос в том, почему существует это несоответствие?
Это не единственный раз, когда это случилось со мной. Это происходило со всеми видами объектов. Единственное, что, кажется, работает каждый раз, — это alloc init . Такие методы, как stringWithString: работают большую часть времени, но не всегда.
Комментарии:
1. Можете ли вы указать вызывающий код? Это тесно связано с тем, как создается passedString и, следовательно, его счетчик ссылок.
Ответ №1:
Это потому, что в первом примере вы не сохраняете и не копируете строки. string2 освобождается в какой-то момент, прежде чем вы его используете. На самом деле это чистая удача, что string1 в порядке. Вы должны изменить свой код, чтобы он был примерно таким:
- (void) methodOne: (NSString *) passedString
{
NSLog(@"%@", passedString);
NSString* oldString = string1;
string1 = [passedString copy];
[oldString release];
}
- (void) methodTwo: (NSString *) passedString
{
NSLog(@"%@", passedString);
NSString* oldString = string2;
string2 = [passedString copy];
[oldString release];
}
и освобождение в dealloc
-(void) dealloc
{
[string1 release];
[string2 release];
// other stuff
[super dealloc];
}
Я настоятельно рекомендую вам создать свойства для string1 и string2 для обработки всего этого подсчета ссылок:
@interface MyClass : NSObject
{
NSString *string1;
NSString *string2;
}
- (void) methodOne: (NSString *) passedString;
- (void) methodTwo: (NSString *) passedString;
@property (copy) NSString* string1;
@property (copy) NSString* string2;
@end
@imlementation MyClasss
@synthesize string1, string2;
- (void) methodOne: (NSString *) passedString
{
NSLog(@"%@", passedString);
[self setString1: passedString];
}
- (void) methodTwo: (NSString *) passedString
{
NSLog(@"%@", passedString);
[self setString2: passedString];
}
// dealloc as before
@end
Комментарии:
1. Имеет смысл! Однако один вопрос: мне не нужно освобождать их в dealloc при правильном использовании свойств? Или я должен, поскольку для этих свойств установлено значение копировать?
2. Все равно нужно освободить в dealloc, даже для свойств, которые сохраняются. Вместо этого вы могли бы установить для них значение nil, т.е.
[self setSetString1: nil]
Но это не рекомендуется в `dealloc.
Ответ №2:
Вы допускаете ошибки управления памятью. Вы должны сохранять или копировать строки, когда вы назначаете их своим ivars (и освобождаете их позже).
Возможно, вы все еще можете получить доступ к объекту, даже если он был освобожден, когда занимаемая им память еще не была перезаписана. Но вы не можете полагаться на это.
Ответ №3:
Если переданные строки автоматически освобождаются, при их назначении сохранение не выполняется. Постоянные строки (@str») по существу никогда не освобождаются, созданные строки, такие как stringWithFormat, должны быть сохранены.
Пожалуйста, покажите вызывающим.
Использование @properties с сохранением устранит многие проблемы с сохранением. Или рассмотрите возможность использования ARC, что устраняет необходимость сохранения / освобождения / автоматического выпуска.
Комментарии:
1. =] Не беспокойтесь. Просто бросилось в глаза.
Ответ №4:
Как уже говорилось в этой теме, у вас возникли некоторые проблемы с управлением памятью, возможно, вы не совсем понимаете, как выделяются и сохраняются NSObjects, вам следует ознакомиться с Objective-C управление памятью. В то же время есть два подхода, которые вы могли бы предпринять для решения вышеуказанной проблемы.
Вы могли бы сохранить свои переменные-члены NSString (string1 amp; string2) как свойства вашего класса, помимо некоторых других функций, объявление которых как свойств дало бы им средства доступа setter и getter, которые вы бы вызывали вместо method1 и method2. Таким образом, это изменит ваш код, чтобы он выглядел следующим образом в вашем заголовочном файле
@interface MyClass : NSObject
{
NSString *string1;
NSString *string2;
}
@property( nonatomic, retain)NSString* string1;
@property( nonatomic, retain)NSString* string1;
Затем не забудьте добавить следующее в исходный файл (обычно в верхней части файла после строки @implementation MyClass)
@implementation MyClass
@synthesize string1;
@synthesize string2;
Затем в классе, из которого вы вызывали method1 и method2, вы можете изменить код, чтобы он выглядел следующим образом
//Lets assume somewhere you've called an init Method for your MyClass Object, something like
MyClass* myClassObject = [[MyClass alloc] init];
//you can then call the setters to set the string like so
[myClassObject setString1:@"some string"]; //or myClassObject.string1 = @"some string";
[myClassObject setString2:@"some string"]; //or myClassObject.string2 = @some other string";
//Calling these member variables either of the above ways is valid, I prefer the former as it's a bit easier on the eye for me
//and to get the values back out of the strings you could call
NSString* output = [myClassObject string1];
//or
NSString* output2 = myClassObject.string2;
Теперь вы можете по какой-то причине не захотеть использовать свойство @ для переменных-членов NSString, поэтому вы можете изменить свой исходный исходный файл (.m), чтобы он выглядел как
@implementation MyClass
- (void) methodOne: (NSString *) passedString
{
NSLog(@"%@", passedString);
if( string1 != nil )
{
[string1 release];
}
string1 = [[NSString alloc] initWithString:passedString];
}
- (void) methodTwo: (NSString *) passedString
{
NSLog(@"%@", passedString);
if( string2 != nil )
{
[string2 release];
}
string2 = [[NSString alloc] initWithString:passedString];
}
Это должно решить проблему, почему ваши строки недействительны, поскольку вы не будете перезаписывать память и пытаться считывать мусор таким образом. Вам нужно будет не забыть освободить эти NSStrings в вашем dealloc, если они не равны нулю, иначе вы тоже получите утечку памяти.
Надеюсь, это поможет.