IBOutlets, переменные экземпляра и свойства: лучшие практики - PullRequest
7 голосов
/ 24 мая 2011

Сегодня я провёл всевозможные исследования лучших практик в отношении объявления IBOutlets и переменных экземпляра, управления ими, использования правильных методов доступа и их правильного освобождения. Я в значительной степени там, но у меня есть некоторые нишевые вопросы, которые, я надеюсь, кто-то сможет посоветовать лучшую практику. Я отформатирую их как код и прокомментирую вопросы, чтобы их было легче понять. Я исключил некоторые очевидные части, которые я не считал релевантными и которые можно смело предположить для работы (например, препроцессор, @end, необходимые методы реализации и т. Д.).

MyViewController.h

@class OtherViewController;

@interface MyViewController : UIViewController {

     NSString *_myString;
     BOOL _myBOOL;

}

// The first two properties aren't declared in the interface
// above as per best practices when compiling with LLVM 2.0

@property (nonatomic, retain) OtherViewController *otherViewController;
@property (nonatomic, retain) UIButton *myButton;
@property (nonatomic, copy) NSString *myString;
@property (readwrite) BOOL myBOOL;

MyViewController.m

@implementation MyViewController

// Synthesizing IBOutlets on iOS will cause them to be
// retained when they are created by the nib

@synthesize otherViewController;
@synthesize myButton;

// Assign instance variables so as to force compiler
// warnings when not using self.variable

@synthesize myString = _myString;
@synthesize myBOOL = _myBOOL;

- (void)viewDidLoad {

     // QUESTIONS:

     // 1. Ignoring convenience methods, can you still alloc and init in dot notation
     //    even when it's being properly synthesized?

     self.myString = [[NSString alloc] initWithString:@"myString"];
     self.myString = existingNSStringObject;

     // 2. Should you always call methods for IBOutlets and instance variables using dot notation?
     //    Is there any difference seeing as these aren't directly invoking setters/getters?

     [self.myButton setText:self.myString];
     [myButton setText:self.myString];

     [self.otherViewController.view addSubview:mySubview];
     [otherViewController.view addSubview:mySubview];

     [self.myButton setAlpha:0.1f];
     [myButton setAlpha:0.1f];
     self.myButton.alpha = 0.1f;
     myButton.alpha = 0.1f;

     // 3. How fussy are scalar variables in terms of getters and setters,
     //    given that there is a @synthesize declaration for them?

     self.myBOOL = YES;
     myBOOL = NO;

     if(self.myBOOL) { ... }
     if(myBOOL) { ... }

     // 4. On instantiation of new view controllers from NIBs, should you use
     //    dot notation? (I haven't been doing this previously).

     otherViewController = [[OtherViewController alloc] initWithNibName:@"OtherView" bundle:nil];
     self.otherViewController = [[OtherViewController alloc] ... ]

}

- (void)viewDidUnload {

     // 5. Best practice states that you nil-value retained IBOutlets in viewDidUnload
     //    Should you also nil-value the other instance variables in here?

     self.otherViewController = nil;
     self.myButton = nil;

     self.myString = nil;

}

- (void)dealloc {

     [otherViewController release];
     [myButton release];
     [_myString release];   

}

Ответы [ 3 ]

3 голосов
/ 24 мая 2011

1) Вы немного неправильно поняли @synthesize.@synthesize ничего не делает с объектом.Он только указывает компилятору генерировать методы getter и setter в соответствии с параметрами, используемыми в объявлении @property

// Синтезирование IBOutlets в iOS приведет к тому, что они будут

//сохраняется, когда они создаются пером

розетки не сохраняются (розетки являются просто уведомлениями для конструктора интерфейса и не влияют на код), * ​​1011 *объекты сохраняются, когда используется сеттер, сгенерированный @synthesize.Когда перо загружено, система загрузки вызывает ваш сгенерированный установщик.

2) Решение о том, использовать ли средства доступа в задаче C, ничем не отличается от решения использовать средства доступа в любом другом объектно-ориентированном языке.Это выбор стиля, потребности и надежности.То, что метод доступа служит в качестве IBOutlet, не имеет значения.

Но в объективном CI следует предложить НЕ использовать методы доступа в двух местах: dealloc и в самом методе доступа var.

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

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

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

3) Не уверен, что вы подразумеваете под суетой.Возможно см. Ответ на 2)

4) См. 2) и будьте осторожны с управлением памятью.Если вы вызываете alloc / init, теперь вы отвечаете за освобождение объекта - это полностью независимо от удержаний / выпусков, используемых аксессорами и dealloc.

5) Нет, вы не должны обнулять другие переменные экземпляра в viewDidUnload.Ожидается, что ваш контроллер будет поддерживать свое состояние, даже если представление исчезнет.viewDidUnload предназначен только для очистки потенциально опасных объектов просмотра, когда представление контроллера в данный момент не отображается на экране.

Рассмотрим контроллер навигации.Контроллер вида 1 находится в стеке, а затем контроллер вида 2 толкается и становится видимым.Если условия памяти становятся низкими, система может попытаться выгрузить представление контроллера представления 1 и затем вызовет viewDidUnload.

Тогда контроллер представления 2 с выталкиванием больше не будет создавать объект контроллера представления 1, но будет загружать контроллер представления 1view и вызов viewDidLoad.

Re comments

2) Совершенно верно - вы можете использовать вспомогательный конструктор или освобождение сразу после выделения, инициализации и назначения или выпускадо выхода из блока или автоматического выпуска.То, что вы выбираете, в основном зависит от стиля (хотя некоторые будут спорить с авто-выпуском, но не со мной!)

3) Есть средства доступа для скаляров - вы создали их в своем коде

@property (readwrite) BOOL myBOOL;

Это создает методы myBOOL и setMyBOOL для вашего класса.

Помните, что нет ничего особенного в точечной нотации.Это только для удобства, и когда код скомпилирован, myObject.property в точности эквивалентен [свойству myObject], а myObject.property = x в точности эквивалентен [myObject setProperty: x].Использование точечной нотации - это выбор стиля.

3 голосов
/ 24 мая 2011

Я всегда объявляю и явно устанавливаю базовую переменную экземпляра свойства. Немного больше впереди, но, на мой взгляд, стоит явно дифференцировать переменные и свойства и сразу увидеть, какие переменные экземпляра имеет класс. Я также добавляю имена переменных экземпляра, поэтому компилятор жалуется, если я случайно набрал property вместо object.property.

  1. При вызове alloc / init создается объект с счетом сохранения 1. Ваше синтезированное свойство также сохранит объект, вызывая утечку памяти при его освобождении (если только вы не освободите свое свойство сразу после этого, но это плохая форма) , Лучше выделить / и освободить объект в отдельной строке.

  2. Точечная запись фактически совпадает с вызовом [self setObject:obj]. Не использование точечной нотации напрямую обращается к базовой переменной экземпляра. В init и dealloc всегда обращайтесь к переменной экземпляра напрямую, поскольку методы доступа могут включать дополнительные операции (такие как уведомления о значении ключа), которые недопустимы при создании или уничтожении объекта. Все остальное время используют синтезированные методы доступа. Даже если вы сейчас не делаете ничего особенного, вы можете позже переопределить эти методы, чтобы изменить то, что происходит при установке переменной.

  3. Скаляры работают так же, только вам не нужно слишком беспокоиться о памяти.

  4. Один обращается к синтезированным методам доступа, другой - к переменной экземпляра напрямую. Смотрите вопросы один и два снова и будьте осторожны с утечками памяти!

  5. Контроллер вида может быть снова выведен на экран, в этом случае ваш метод viewDidLoad будет вызван во второй раз. Если вы устанавливаете начальные значения в viewDidLoad, продолжайте и установите ваши свойства равными nil здесь. Это имеет смысл для свойств, которые используют много памяти и не будут влиять на состояние представления. С другой стороны, если вы хотите, чтобы свойство сохранялось до тех пор, пока вы не убедились, что оно больше не нужно, создайте его в своем методе init и не выпускайте его до dealloc.

1 голос
/ 24 мая 2011
  1. Обозначения точек и скобок практически одинаковы.
  2. С помощью self.myVariable вы получаете доступ к получателю свойства переменной экземпляра myVariable, а с помощью myVariable вы получаете доступ к локальной переменной.Это не одно и то же.
  3. Вы можете настроить сеттеры и геттеры, переопределив методы и задав для них некоторые определенные условия.
  4. См. Первый ответ (предпочтительны скобки - лучшее пониманиекода)
  5. Лучше сделай отдельный метод.

Как:

- (void) releaseOutlets {
 self.firstOutlet = nil;
 self.mySecondOutlet = nil;
 ……………………
 self.myLastOutlet = nil;
}

, а затем вызвать этот метод как в viewDidUnload, так и в dealloc методах.

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

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