Почему неявная инициализация переменной не работает согласованно на iPhone? - PullRequest
1 голос
/ 05 октября 2011

Так вот мой сценарий - В заголовочном файле класса я делаю:

@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:].

Как видите, строки1 и строка2 обрабатываются одинаково, но происходит то, что строка1 устанавливается, а строка2 остается пустой. Я получаю плохой доступ, когда ссылаюсь на него позже.

Я подумал, что, может быть, я передаю пустую строку в methodTwo: поэтому я добавил этот NSLog, который доказывает, что он не пустой, но имеет ожидаемую строку.

Поскольку я заметил это несоответствие, прежде чем я решил изменить на это:

        - (void) methodOne: (NSString *) passedString
        {
           NSLog(@"%@", passedString);
           string1 = passedString;
        }

        - (void) methodTwo: (NSString *) passedString
        {
           NSLog(@"%@", passedString);
           string2 = [[NSString alloc] initWithString: passedString];
        }

Теперь обе строки работают как положено. Мой вопрос: почему это несоответствие?

Это не единственный раз, когда это случилось со мной. Это случилось со всеми видами объектов. Единственная вещь, которая, кажется, работает каждый раз, это alloc init. Такие методы, как stringWithString: работают большую часть времени, но не всегда.

Ответы [ 4 ]

2 голосов
/ 05 октября 2011

Это потому, что в первом примере вы не сохраняете и не копируете строки. 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 голос
/ 05 октября 2011

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

Возможно, что вы все еще можете получить доступ к объекту, даже если он был освобожден, когда память, которую он занимал, имеетеще не был перезаписан.Но на это нельзя полагаться.

0 голосов
/ 05 октября 2011

Как уже отмечалось в этой теме, у вас есть некоторые проблемы с управлением памятью, возможно, вы не совсем понимаете, каким образом объекты NSO выделяются и сохраняются, вам следует ознакомиться с управлением памятью Objective-C. В то же время есть два подхода, которые вы можете использовать для решения вышеуказанной проблемы.

Вы могли бы хранить свои переменные-члены NSString (string1 & 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;

Теперь вы можете по какой-то причине не использовать @property для переменных-членов 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];
}

Это должно решить проблему того, почему ваши строки недопустимы, так как вы не будете перезаписывать память и пытаться таким образом считывать обратно мусор. Вы должны будете не забыть выпустить эти строки NSS в свой пакет, если они не равны нулю, иначе вы также получите утечку памяти.

Надеюсь, это поможет.

0 голосов
/ 05 октября 2011

Если переданные строки автоматически освобождены, при их назначении сохранение не сохраняется. Постоянные строки (@str ") по существу никогда не освобождаются, созданные строки, такие как stringWithFormat, должны быть сохранены.

Пожалуйста, покажите звонящим.

Использование @properties с retain устранит многие проблемы с сохранением. Или рассмотрите возможность использования ARC, что устраняет необходимость сохранения / освобождения / автоматического выпуска.

...