Некоторые вопросы начинающих Objective-C / iPhone - PullRequest
7 голосов
/ 02 апреля 2009

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

1. (self! = Nil) проверка в коде инициализатора. Зачем это делать? Чтобы предотвратить случайный доступ к некоторому коду «только один раз», который там находится? Откуда взялся этот случайный доступ? Такие проверки показывают, что я не контролирую происходящее.

- (id)init { self = [super init] if (self != nil) { // Code.. } return self; }

2. Почему вам не нужно освобождать ничего, что возвращают статические методы? (или это идея у меня есть)

3. Как дела = @ "Привет!" отличается от

str = [[NSString alloc] initWithString:@"Hi there!"];

Как я понимаю, вы должны выпускать str в aquired вторым способом, а не первым? Если да, когда выйдет первый? Какой из них предпочтительнее (без учета длины набора)?

4. Что такое авто-выпуск, если в iphone нет сборки мусора? Я заметил нечто, называемое пулом авто-релизов, созданное в main.m. Является ли [myObject autorelease]; способ добавить myObject в ближайший пул "autorelease pool", который его выпустит? В основном, какая-то магия, чтобы не выпустить ее самостоятельно? Зачем его использовать?

Ну, вот и все. Спасибо за любые ответы!

Ответы [ 5 ]

11 голосов
/ 02 апреля 2009
  1. В Objective-C можно вернуть экземпляр, отличный от self, из -init. Классы делают это, например, для принудительного применения одноэлементного экземпляра или в случае кластеров классов. NSNumber, например, возвращает подкласс в зависимости от типа значения, переданного его инициализатору. Поэтому, когда вы вызываете [[NSNumber alloc] initWithLong:long_value], NSNumber инициализатор -initWithLong: вызывается после NSNumber +alloc, но подкласс NSNumber может быть возвращен вызывающему абоненту. Таким образом, шаблон

    self = [super init];

    , который переназначает self на значение [super init], так что self указывает на фактический экземпляр, который вернул [super init]. Если +alloc или метод супер init не удался, результат [super init] может быть nil. Чтобы избежать побочных эффектов в случае неудачной инициализации, шаблон становится

    - (id) init {
      if(self = [super init]) {
        // do initialization of instance variables etc.
      }
    
      return self;
    }
    

    Обратите внимание, что вы должны вернуть self (или nil или другой экземпляр) из метода init. Вы должны назначить себя для [super init], и вы можете проверить nil, прежде чем делать больше работы.

  2. Возможно, вам придется освободить возвращаемое значение метода Staic. Вы должны прочитать руководство по управлению памятью Какао . Как правило, правило довольно простое: если вызываемый вами метод имеет в своей подписи «new», «alloc» или «copy», результат принадлежит вызывающей стороне, и вызывающая сторона должна вызвать -release в этом экземпляре, иначе утечка памяти. Конечно, вы должны вызывать -retain для всего остального (т.е. не для метода alloc, new или copy), на который вы хотите сохранить ссылку, а затем вызывать -release или -autorelease, когда вы закончите. с этим экземпляром.

  3. str = @"Hi there!", предполагая, что str был объявлен как NSString *str; назначает адрес строковой константы @"Hi there!" to the value of the str variable. You do not need to retain or release string constants. str = [[NSString alloc] initWithString: @ "Привет!" ; allocates a new string instance. The value of str will be the address of this instance. Each call of str = [[NSString alloc] initWithString: @ "Hi there!"]; again will allocate a new instance. So after str2 = [[NSString alloc] initWithString: @ "Hi there!"]; , str! = str2 , while after str2 = @ "Привет!", str==str2. См. Также этот ответ.

  4. -autorelease добавляет получателя к текущему NSAutoreleasPool. Когда пул очищается (обычно в конце текущей итерации цикла выполнения или когда пул очищается вручную), пул вызывает -release для всех экземпляров в пуле. Если это -release уменьшает количество сохраненных до 0, объект освобождается (и вызывается -dealloc), как и любой другой -release. Использование пула автоматического выпуска обычно недовольно на iPhone, так как это может привести к накоплению множества неиспользуемых экземпляров в пуле до его опустошения в конце итерации цикла выполнения. Если вы можете использовать -release вместо -autorelease, вам, как правило, следует. Снова, см. Руководство по управлению памятью Какао для получения дополнительной информации.

2 голосов
/ 02 апреля 2009
  1. Существует точка зрения, что в большинстве случаев выделение указателя self должно выполняться системой, а не программистом.

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

- (id)init {
    if (![super init]) {
        return nil; // There is a problem so bail early.
    }
    // Initialisation code here.
    return self
}

Уилл Шипли объясняет это гораздо лучше, чем я.

1 голос
/ 02 апреля 2009

вызывающий

self = [super init];

Может возвращать ноль, если суперкласс не может инициализировать себя по тем или иным причинам, в том числе из-за недоступности памяти или если определенные условия не были выполнены. Если это так, вы не хотите пытаться устанавливать переменные self, устанавливать self в качестве делегата или добавлять self в массив, если self равно nil.

Пул авто-релизов создается при каждом событии, которое iPhone отправляет вашему приложению. Он создается перед выполнением любого кода и выпускается после выполнения всего вашего кода для каждого события. Любые объекты, которые вы называете autorelease, будут включены в текущий пул автоматического выпуска. Любые объекты в пуле автоматического выпуска будут освобождены столько раз, сколько они были добавлены, после завершения вашего кода. Таким образом, вам не нужно беспокоиться о том, кто отвечает за освобождение объекта, созданного одним методом и возвращенного другому методу.

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

str = [[NSString alloc] initWithString:@"Hi there!"];

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

@"Hi there!";

возвращает строку, о которой вам не нужно беспокоиться об освобождении. Расширяем ваш предыдущий пример:

str = [[[NSString alloc] initWithString:@"Hi there!"] autorelease];

будет другим методом создания строки, о которой вам не нужно беспокоиться об освобождении.

Одно из различий между пулами сборки мусора и автоматического выпуска состоит в том, что сборка мусора работает с циклическими ссылками. Используя пулы авто-релиза, вы не хотите иметь два объекта, которые сохраняют друг друга, и надеетесь, что, если на них ничего не ссылается, они исчезнут; они не будут.

1 голос
/ 02 апреля 2009
  1. Если self равно nil после суперинициализации, значит, вам не хватает памяти. Единственный разумный способ - вернуть ноль и надеяться, что все будет корректно обработано в стеке.

  2. Статические методы не могут размещаться в куче, поэтому освобождать нечего.

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

  4. Это простая сборка мусора. Что касается того, почему его использовать, простой ответ - нет. Не рекомендуется использовать авто-релиз на iPhone из-за ограниченных ресурсов.

1 голос
/ 02 апреля 2009

1: эта проверка должна гарантировать, что супер-конструктор вернул новый объект.

2: Статические методы не ссылаются на экземпляр

3

str = @"Hi there!"

Это присваивает адрес постоянной строки "Привет!" до указателя ул

str = [[NSString alloc] initWithString:@"Hi there!"];

Это выделяет строку и копирует "Привет!" к этому. Это означает, что a) str является изменяемым и b) должен быть освобожден, когда вы закончите с ним.

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