Использование методов доступа для установки iVars? - PullRequest
4 голосов
/ 11 февраля 2010

Изначально я смотрел на способ установки «pickerData» и думал, что удивляюсь, почему вы не можете просто назначить его напрямую (как в METHOD_002), но потом я сказал, что действительно должен использовать методы доступа, которые я определены и не устанавливаются переменные экземпляра напрямую. Я правильно понимаю, что METHOD_001 - лучший способ сделать это?

@property(nonatomic, retain) IBOutlet NSArray *pickerData;

METHOD_001

-(void)viewDidLoad {
    NSLog(@"VIEW: Single ... Loaded");
    NSArray *dataArray = [[NSArray alloc] initWithObjects:@"A", @"B", @"C",nil];
    [self setPickerData:dataArray];
    [dataArray release];
    [super viewDidLoad];
}

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

ИЛИ МЕТОД_002

-(void)viewDidLoad {
    NSLog(@"VIEW: Single ... Loaded");
    if(pickerData != nil) [pickerData release];
    pickerData = [[[NSArray alloc] initWithObjects:@"A", @"B", @"C", nil] retain];
    [super viewDidLoad];
}

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

EDIT_001:

Во-первых, я добавил значения «nil» для завершения NSArrays, исходящие из C, я всегда забываю это, мой плохой. Также вы правы, я не учел в METHOD_002 тот факт, что pickerData может быть уже установлен и в результате утечка старого объекта. Как только вы начинаете замечать эти проблемы и исправлять код, он начинает выглядеть так, как будто METHOD_001 - лучшая идея. Или просто использовать свойство напрямую, как отметили Владимир и eJames.

self.pickerData = [NSArray arrayWithObjects: @"A", @"B", @"C", nil];

EDIT_002:

Спасибо за все ссылки и комментарии, сейчас я собираюсь придерживаться METHOD_001, я мог бы так же легко использовать NSArrayWithObjects: но я пытаюсь сохранить низкое использование памяти, выпуская вещи самостоятельно, как только смогу (не это имеет значение здесь, но для будущих проектов) Также мне нравится ощущение self.pickerData, но я все еще не уверен, что я чувствую к точечной нотации, и сейчас пытаюсь придерживаться объектов старого стиля и сообщений, где это возможно. Еще раз большое спасибо за помощь.

1019 * Гэри *

Ответы [ 3 ]

3 голосов
/ 11 февраля 2010

Вы всегда должны использовать средства доступа к свойствам (что в Objective-C 2.0 означает использование обозначения self.property.)

Почему? Потому что он обеспечивает автоматический контроль доступа и управление жизненным циклом объекта. Сгенерированные средства доступа могут обеспечить большую защиту, такую ​​как чтение / запись, копирование, сохранение и т. Д., Которые в противном случае требуют большого количества ручного кода. Если вы пишете свои собственные методы доступа, вы можете добавить все необходимые валидации и побочные эффекты.

(Еще до того, как аксессоры Objective-C 2.0 считались высоким искусством. Это все еще возможно, если вы полностью используете потенциал.)

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

@property(nonatomic, retain)  NSMutableArray *myObjects;
@synthesize myObjects;

-(NSMutableArray *) myObjects{
    if (myObect!=nil) {
        return myObect;
    }
    NSMutableArray *anArray=[[NSMutableArray alloc] initWithCapacity:1];
    self.myObject=anArray;
    [anArray release]
    return myObject;
}
  1. Этот метод доступа гарантирует, что myObjects никогда не будет равен нулю, что устраняет большую часть стандартного тестирования нуля в остальной части вашего кода.
  2. Вы, очевидно, не можете вызвать self.myObjects (который на самом деле является [self myObjects]) внутри средства доступа без создания бесконечной рекурсии, поэтому вы должны получить доступ к необработанной переменной здесь, но ...
  3. ... Вы можете вызвать (автоматически сгенерированный) self.myObjects= (который на самом деле [self setMyObjects: anArray]), потому что это совершенно другой метод. Если вы посмотрите на внутренние элементы setMyObjects: вы увидите, что он также обращается к необработанной переменной.
  4. Если вы используете сгенерированные средства доступа, self.myObjects= обрабатывает сохранение, копирование, обнуление и т. Д. Каждый раз, когда вы вызываете его. Единственный раз, когда вам нужно позвонить релиз, находится в dealloc. Это само по себе стирает, вероятно, половину ошибок, которые делают люди в Objective-C.

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

Как показали предыдущие ответы, вы допустили несколько ошибок памяти, пытаясь управлять свойством напрямую. Если бы вы использовали аксессор каждый раз, вы бы их не сделали. Например:

pickerData = [[[NSArray alloc] initWithObjects:@"A", @"B", @"C", nil] retain];

... каждый раз нужно правильно управлять, тогда как ...

self.pickerData = [[NSArray alloc] initWithObjects:@"A", @"B", @"C", nil];

... автоматически корректно.

Помните, что конечная цель разработки для любого класса Objective-C состоит в том, что он должен быть идеально модульным и многоразовым. Это означает, что он должен управлять всей своей собственной памятью, собственной проверкой данных и собственными побочными эффектами. Средства доступа абсолютно необходимы для этого управления. Оборачивая логику вокруг каждого доступа к переменной, вы гарантируете, что (1) это ожидаемый вами тип, диапазон и т. Д. И (2) что он всегда рядом, когда вам это необходимо (3) что вы можете контролировать все стороны последствия записи или чтения переменной и (4) ее отсутствие.

Я не могу достаточно превозносить достоинства аксессоров. На самом деле, я мог бы написать небольшую песню. ; -)

3 голосов
/ 11 февраля 2010

Здесь есть много тем для обсуждения, но я начну с рекомендуемого подхода:

METHOD_003

-(void)viewDidLoad { 
    NSLog(@"VIEW: Single ... Loaded"); 
    self.pickerData = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; 
    [super viewDidLoad];
}

Примечание: спасибо Владимиру за напоминание для nil-terminate .

Теперь, для деталей:

METHOD_001 делает то же самое, что и METHOD_003, но требует еще несколько строк кода.

METHOD_002 имеет утечку памяти, потому что вы alloc массив, а затем retain его. В результате общее количество сохранений равно 2. Когда вы освобождаете массив в вашем методе dealloc, счет уменьшается до 1, поэтому массив не будет освобожден из памяти.

Даже если вы удалите лишний retain из METHOD_002, он не сделает две очень важные вещи:

  1. Он не будет отправлять соответствующие KVC / KVO уведомления . Какао делает много очень удобных вещей за кадром, когда вы используете средство доступа к свойству, поэтому, если у вас нет веских причин не делать этого, настоятельно рекомендуется использовать средства доступа.

  2. Он не будет автоматически освобождать любые старые данные, которые были сохранены в pickerData. Это не относится к viewDidLoad, но если бы вы использовали другой метод, изменит ситуацию, поэтому лучше всего привыкнуть использовать средства доступа, если у вас нет причина не.

0 голосов
/ 11 февраля 2010

Самые большие проблемы с вашим METHOD_002: а) вы сохраняете массив, которым вы уже владеете, что вам не нужно делать (и утечка массива), и б) вы не учитываете возможность что pickerData может уже иметь значение, отличное от nil (viewDidLoad может вызываться много раз в течение срока службы контроллера).

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

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