Сохраните, выделение, свойства … Тема для создания жизни Obj-c легче!

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

Хорошо ниже некоторые примеры:

// myArray is property (retain)
myArray = otherArray;

//myArray isn't a property
myArray = otherArray;

//myArray is a property (retain)
myArray = [[NSArray alloc] init];

//myArray isn't a property
myArray = [[NSArray alloc] init];

---Так, если я понимаю..., когда Вы помещаете self.myArray, Вы говорите XCode использовать метод считывания или метод set, но когда Вы просто делаете myArray, Вы ответственны за все, правильно?

[РЕШЕННЫЙ] UPDATE1: Есть ли различие между:

//myArray is a property
myArray = otherArray; // it is only a reference, releasing otherArray will imply releasing myArray
self.myArray = otherArray; // otherArray is sent a retain message so releasing otherArray will still keep myArray in memory

---Да, существует различие (см. комментарии выше),

[РЕШЕННЫЙ] UPDATE2: myArray ниже равного нолю?

NSArray *myArray;

---Kubi: Да, это равно нолю.

[РЕШЕННЫЙ] UPDATE3: это значит 2, сохраняет? Каждый сохраняет от сам, и каждый сохраняет от выделения? Действительно ли это - утечка памяти?

self.myArray = [[NSArray alloc] init];

---Kubi: Да, это - утечка памяти!

[РЕШЕННЫЙ] UPDATE4: свойство заботится обо всем? никакая потребность к выделению или выпуску?

self.myArray = [NSArray array];

---Мы здесь используем метод set так, чтобы массив был сохранен правильно

[РЕШЕННЫЙ] UPDATE5: действительно ли эти два блока являются тем же?

//myArray is a retained property

self.myArray = [NSArray array]; //retain
self.myArray = nil; //release and set to nil

myArray = [[NSArray alloc] initWithArray]; //retain
self.myArray = nil; //release and set to nil

---Kubi: Да, они идентичны

Спасибо за время.

Gotye.

5
задан gotye 24 March 2010 в 09:37
поделиться

3 ответа

Во-первых, я предполагаю, что у вас есть свойство с именем myArray и iVar с именем myArray ? Если это так, то варианты 1, 2 и 3, 4 идентичны. Если вам нужно установить свойство вашего текущего класса, вы должны сделать это одним из следующих методов:

self.myArray = otherArray;
[self setMyArray:otherArray];

строка myArray = otherArray установит только iVar, но не свойство.

Во второй части вы спрашиваете об управлении памятью. Шаг первый: прочтите Руководство Apple . Это действительно обязательное чтение. Не волнуйтесь, если вы не до конца понимаете, продолжайте читать его раз в месяц, и в конце концов он кристаллизуется.

Шаг второй: запомните это практическое правило: если вы alloc , скопируете , новый или сохраните объект, вы несут ответственность за освобождение этого объекта, если вы этого не сделаете, он будет утек.

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

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


Обновление 1 Очень большая разница.Две строки полностью разные. Что касается точечного синтаксиса, важно понимать, что эти две строки в точности эквивалентны:

self.myArray = otherArray;
[self setMyArray:otherArray];

Обратите внимание, что вторая строка - это вызов метода. Теоретически в этот метод можно было вложить все, что угодно. Вы можете установить для myArray значение nil или установить для него значение someOtherArray , или обновить twitter или что-то еще.


Обновление 2 Ага, указатели в Obj-C инициализируются нулем.


Обновление 3 Совершенно верно. Если свойство myArray объявлено как keep и вы используете синтезаторы по умолчанию, это вызовет утечку памяти.

Обновление 5 Тоже совершенно верно.

6
ответ дан 13 December 2019 в 19:24
поделиться

Лучшее место, чтобы найти ответ на этот вопрос, - это в соответствующей документации Apple, которая объясняет все об управлении памятью . Сказав это, вы используете здесь только ivars, вы не устанавливаете свой ivar с помощью сгенерированных ObjC сеттеров. Как говорит куби, вы должны сказать

self.myArray = otherArray;

, чтобы использовать свойство myArray.

0
ответ дан 13 December 2019 в 19:24
поделиться

Куби ответил хорошо. Перечитывать Руководство Apple, пока вы не разобрались, действительно обязательно.

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

  1. Объявите свойство для каждой создаваемой вами переменной экземпляра объекта. Объявите его как (неатомарный, сохранить), если только это не объект, которым ваш класс не владеет, например делегат, который создаст циклическую ссылку. В этом случае объявите его как (nonatomic, assign), чтобы избежать утечки всех объектов в этом цикле.

     @property (неатомарный, сохранить) NSString * title; 
     @ property (неатомарный, назначить) id  делегат; 
     
  2. Даже если переменная экземпляра объекта предназначена только для частное использование классом, объявите свойство для него в расширении класса в верхней части вашего .m файла, чтобы синтезированный метод установки мог позаботиться об управлении памятью за вас.

     // Widget.m
    @interface Widget () 
     @ property (неатомарный, сохранить) NSString * privateState; 
     @ end 
     {{1} } @implementation Widget 
     @ синтезировать заголовок, делегат, частное состояние; 
     // ...
     @ end 
     
  3. Каждый раз, когда вы назначаете объект переменной экземпляра, всегда устанавливайте его через свойство, используя self.

     self.title = @ "Title"; 
  4. В вашем dealloc установите для каждого свойства объекта значение nil. Если вы следовали описанным выше методикам, это одновременно правильно освободит переменные вашего экземпляра и установит их в ноль для защиты от EXC_BAD_ACCESS. Сделайте dealloc первым методом в своем классе, чтобы не забыть ни о каких свойствах.

     - (void) dealloc {
    self.title = nil; 
    self.delegate = nil; 
    self.privateState = nil; 
     [super dealloc ]; 
    } 
     
  5. Для каждого написанного вами настраиваемого класса убедитесь, что у него есть хотя бы один метод фабрики классов, который делегирует методу инициализации с теми же параметрами и автоматически освобождает возвращаемый объект. Это ограничивает почти все вызовы alloc и init этими фабричными методами, а не разбрасывает их по вашему коду.

     - (id) initWithTitle: (NSString *) делегат theTitle: (id) theDelegate {
    if (self = [super init]) {
    self.title = theTitle; {{1 }} self.delegate = theDelegate; 
    self.privateState = @ "start"; 
    } 
    return self; 
    } 
     + (id ) widgetWithTitle: (NSString *) делегат theTitle: (id) theDelegate {
    return [[[self alloc] initWithTitle: theTitle delegate: theDelegate] автозапуск]; 
    } 
     
  6. Всякий раз, когда вы создаете экземпляр объекта, всегда делайте это с помощью метода фабричного класса, если это возможно. Это дает вам автоматически выпущенный объект, поэтому вам не нужно освобождать его, если вы не сохраните его.

     сам.widget = [Widget widgetWithTitle: @ "My Widget" delegate: self]; 
     
  7. Когда вам нужно создать экземпляр объекта, у которого нет подходящего метода фабричного класса, автоматически выпустите его в той же строке, чтобы вы не Не забудьте сделать это позже. (Исключение: отпустите вручную, если вы делаете это тысячи раз в тесном цикле.)

     self.containerView = [[[UIView alloc] initWithFrame: self.bounds] autorelease]; 
     
  8. Если вы освобождаете объект, у которого есть делегат или подобное свойство, которое указывает обратно в циклической ссылке, сначала установите для этого свойства значение nil. Это предотвращает EXC_BAD_ACCESS в случае, если объект переживет свой делегат и попытается вызвать метод делегата после того, как он был освобожден.

     - (void) dealloc {
    self.widget.delegate = nil; 
    self.widget = nil; 
    self.containerView = nil; 
     [ super dealloc]; 
    } 
     

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

5
ответ дан 13 December 2019 в 19:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: