Что на самом деле делает Objective-C, когда вы объявляете объект? - PullRequest
8 голосов
/ 10 июня 2011

Я прочитал руководство по управлению памятью от Apple и не вижу, где объясняется этот случай ...

Много раз, особенно при написании метода класса, возвращающего экземпляр класса, яЯ начну так, потому что я так и видел, и это работает.

[ПРИМЕЧАНИЕ] Этот код из памяти - я обновлю его, когда вернусь домой, чтобы показать примерэто действительно работает (я придумал это, чтобы проиллюстрировать это, но, очевидно, я недостаточно хорошо помню это, чтобы создать что-то, что имеет смысл ...

[ПРАВИТЬ] Вот мой фактический метод - конечно, все были правычто я должен звонить alloc, что я есть.

+ (id)player
{
    Player *player = nil;
    if ((player = [[[super alloc] initWithFile:@"rocket.png"] autorelease])) {
    [player setProjectileType:kProjectileBullet];
        [player setProjectileLevel:1];
        [player setInvincible:YES];
        [player setEmitter:[CCParticleSystemQuad particleWithFile:@"exhaust.plist"]];
        [[player emitter] setPosition:ccp(0.0, player.contentSize.height/2)];
        [player addChild:player.emitter];
    }
    return player;
}

Итак, что я получил из ответов: * Объявление экземпляра просто возвращает мне указатель на ячейку памяти и сообщает Xcode, какой класс у объектабудет. * Установка указателя на nil в значительной степени просто устанавливает его на ноль - удерживая его от мусора (правильно?) * Так как я автоматически освобождаю экземпляр, возвращаемый объект также автоматически высвобождается.

Спасибо, что помогли мне понять это!

Ответы [ 3 ]

11 голосов
/ 10 июня 2011

Может кто-нибудь объяснить, что делает компилятор, когда видит это?

    DooDad* aDooDad = nil;

Если вы действительно заинтересованы в том, что делает компилятор, ответ таков: компилятор зарезервирует некоторую память в стеке для локальной переменной aDooDad, которая является типом указателя (обычно она имеет размер 64 или 32 бита). в зависимости от процессора). Этот указатель затем инициализируется, чтобы содержать nil (обычно 0x00..00).

Заявление, подобное этому:

         DooDad* aDooDad = [[DooDad alloc] init...];

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

Итак, в конце концов,

    DooDad* aDooDad = nil;

не объявляет объект, это просто переменная, содержимое которой интерпретируется как адрес объекта типа DooDad. Таким образом, такая декларация аналогична любой другой декларации, которую вы знаете, например, при инициализации int равным 0, чтобы позже вы могли присвоить ему некоторое значение в операторе if.

утверждение типа:

 [aDooDad doSomething];

интерпретируется системой времени выполнения Objective C следующим образом: отправьте сообщение doSomething объекту, адрес которого хранится в aDooDad. Если этот адрес nil, сообщение не отправляется. С другой стороны, если вы разыменуете нулевой указатель: *aDooDad вы получите неопределенное поведение.

Указатели - вещи довольно низкого уровня. Надеюсь, это поможет.

4 голосов
/ 10 июня 2011

Если вы знакомы с C или C ++, переменные можно создавать одним из двух способов: статически в стеке вызовов или динамически в куче.Переменная память, созданная в стеке, восстанавливается, когда текущий кадр стека выходит из области видимости, поэтому вам не нужно беспокоиться о ее создании или уничтожении.В Objective-C объекты всегда создаются динамически.Примитивы (например, int, float, указатели и т. Д.) Могут создаваться статически или динамически.Для иллюстрации:

- (id)something {

    NSObject myObject; // Illegal static object allocation
    NSObject* myObject; // Legal primitive (pointer) static allocation
    int myInt; // Legal primitive static allocation
    int* myIntPtr; // Legal primitive (pointer) static allocation
}

Итак, когда вы говорите DooDad* dodad = nil;, вы создаете примитив (указатель на DooDad) в стеке.Будучи переменной стека, вы не выделяете и не освобождаете ее, как если бы вы не беспокоились о выделении или освобождении какой-либо памяти в следующем методе:

- (id)allStackVariables {
    int myInt = 0;
    float myFloat = 0.0f;
    float* myFloatPtr = NULL;
    NSObject* myObject = nil;
}

Установка вnil просто устанавливает содержимое переменной равным тому, что компилятор определяет как nil, что-то вроде 0x000000 в шестнадцатеричном виде.Сказать DooDad* dooDad = nil; концептуально идентично тому, чтобы сказать что-то вроде int myInt = 0;

2 голосов
/ 10 июня 2011

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

Не уверен, какова цель метода, который вы опубликовали, но на многих уровнях он кажется неправильнымОн вернет ноль, всегда.Если это не метод инициализатора, он не должен вызывать [self init].Если это метод инициализатора, он должен возвращать себя и иметь имя, похожее на «init ...»

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