Переменная проблема экземпляра iPhone - PullRequest
2 голосов
/ 19 марта 2012

Я пытаюсь выяснить, какова цель синтеза myString в переменной экземпляра _myString.

Какова цель сделать это?Я склонен замечать, что многие люди делают это.

Также я должен освободить переменную экземпляра и установить для переменной экземпляра значение nil, это правильно.

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    NSString *_myString;
}

@property (nonatomic, retain) NSString *myString;

@end

ViewController.m

#import "ViewController.h"

@implementation ViewController

@synthesize myString = _myString;

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.myString = [[NSString alloc] initWithFormat:@"Hello"];

    _myString = [[NSString alloc] initWithFormat:@"Goodbye"];

    NSLog(@"%@\t%@", self.myString, _myString);
}

- (void)viewDidUnload
{
    _myString = nil;
    [super viewDidUnload];
}

- (void)dealloc
{
    [_myString release];
    [super dealloc];
}

@end

Ответы [ 4 ]

3 голосов
/ 19 марта 2012

Когда вы @synthesize свойство типа объекта в цели c, компилятор сгенерирует два скрытых метода для этой переменной экземпляра. Таким образом, когда вы ссылаетесь на myObject.myString, будет возвращен не только указатель _myString, но и будет вызван сгенерированный метод - (NSString*) myString. Аналогично, если вы назначите что-то свойству: myObject.myString = @"foo";, оно будет скомпилировано в [myObject setMyString:@"foo"];.

Значения - (NSString*) myString и - (void) setMyString:(NSString*) theString зависят от ключевых слов, которые вы указали при объявлении свойства. Наиболее распространенным является assign, который просто назначает указатель, который вы даете:

- (void) setMyString:(NSString*) theString 
{
     _myString = theString;
}

- (NSString*) myString
{
    return _myString;
}

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

В свою очередь, retain генерирует аналогичный метод установки (метод получения будет таким же):

- (void) setMyString:(NSString*) theString 
{
     [theString retain];
     [_myString release];
     _myString = theString;
}

Вы можете видеть, что это заботится об управлении памятью объекта, который вы передали в свойство. Другими словами, вы можете быть уверены, что объект не будет освобожден до тех пор, пока он не будет у вас в собственности, поэтому вам не придется retain вручную, когда вы переходите в собственность. Это делает гораздо удобнее написание кода, который управляет памятью без утечек. Обратите внимание, что в dealloc вам все еще нужно применить nil к вашему имуществу, чтобы освободить последний сохраненный объект.

Другая категория свойств, когда их данные поступают не из переменных экземпляра, а из какого-либо другого источника данных, например базы данных. Автоматически сгенерированные свойства управляемых объектов базовых данных, например, работают так.

Наконец, вы также можете определить свои собственные методы получения и установки. Хорошая идея, например, написать оболочку свойства вокруг некоторых часто используемых NSUserDefaults настроек, которые облегчат его доступ:

@interface Bar 

@property (nonatomic, assign) NSString* foo;

@end

@implementation Bar

- (void) setFoo:(NSString *)theFoo
{
    [[NSUserDefaults standardUserDefaults] setObject:theFoo 
                                              forKey:@"settings.foo"];
}

- (NSString*) foo
{
    return [[NSUserDefaults standardUserDefaults] 
        stringForKey:@"settings.foo"];
}

@end

myBar.foo = @"foobar"; // automatically persisted between application runs

Прочтите также: Расширенное управление памятью и Объявленные свойства в задаче C

1 голос
/ 19 марта 2012

self.myString (технически [self myString]) фактически получает доступ к параметру ivar _myString и устанавливает его с помощью функции в этом объекте, записанной так:

-(NSString *)myString {
    // code that is automatically generated by the @synthesize statement OR
    // code that you write which over-rides the generated accessor.
    // both of which generally return the value stored in _myString
}

-(void)setMyString:(NSString *)newString{
    // code that generally changes the value of _myString
}

Использование _myString напрямую обходит эти функции и напрямую обращается к ивару.

0 голосов
/ 19 марта 2012

Объявлено, что нужно различать частные переменные и открытые переменные в объекте. Это совершенно необязательно.

См. Это: Когда вызывается UIViewController viewDidUnload? и Что именно я должен делать в viewDidUnload? .

Это может помочь вам.

0 голосов
/ 19 марта 2012

Люди склонны синтезировать свойства, чтобы подчеркнуть префиксные переменные, чтобы не перепутать их при написании другого кода. Например:

// ... do sth
myString = @"Foo";
// ... do sth else ...
self.myString = @"Bar";

Первая инструкция обращается к переменной напрямую, вторая использует синтезированный установщик. Когда вы синтезируете без указания конкретной переменной, для вас будет создана переменная с тем же именем, что и у свойства:

@synghesize myString; // this creates myString variable for you

Вместо этого люди создают префиксные переменные с подчеркиванием, чтобы избежать прямого доступа к нему по ошибке. Когда они это делают, первая инструкция myString = @"Foo" больше не компилируется, что позволяет очень легко предотвратить неприятные ошибки, подобные тем, которые возникают при обходе метода получения или установки по ошибке.

Что касается вашего второго вопроса, используйте ARC, если это возможно. Если нет, вы должны сначала освободить переменную, а затем сбросить указатель. В представленном вами коде viewDidUnload будет вызываться раньше, чем dealloc, поэтому у вас будет утечка памяти, потому что _myString будет указывать на nil перед вызовом release для него.

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