Подтвердить что ты не робот

Злоупотребление Objective-C Сокращенное обозначение

Помимо того, что для начинающих школьников Objective-C существуют сердечные приступы, есть ли другие последствия для этого:

NSMutableArray *derp = @[].mutableCopy

В сравнении с этим:

NSMutableArray *derp = [[NSMutableArray alloc] init];
4b9b3361

Ответ 1

Кластеры кластеров не имеют дополнительного распределения, и это не имеет никакого отношения к магии компилятора. Итак, есть существенная разница между вашими примерами (btw, -1000 интернет-точек для злоупотребления точечной нотацией.) В первом примере есть два распределения, второй - только один. s >

Поскольку у нас нет доступа к фактическому исходному коду для NSArray, мы можем посмотреть GNUStep (реализация с открытым исходным кодом), чтобы увидеть, как они справляются с этим. В NSArray.m(упрощение и опускание нерелевантных вещей):

static GSPlaceholderArray   *defaultPlaceholderArray;
+ (void) initialize
{
    defaultPlaceholderArray = (GSPlaceholderArray*)
        NSAllocateObject(GSPlaceholderArrayClass, 0, NSDefaultMallocZone());
}

+ (id) alloc
{
    return defaultPlaceholderArray;
}

Что здесь происходит, так это то, что NSArray определяет объект singleton, placeholder, который он всегда возвращает в alloc. Когда init вызывается в этом одноэлементном, он создает собственный частный подкласс и возвращает его.

Итак, как мы можем сказать, делает ли Apple Foundation то же самое? Довольно легко, мы просто запускаем этот тест:

NSArray *a1 = [NSArray alloc];
NSArray *a2 = [NSArray alloc];
NSLog(@"%p, %p", a1, a2);

> "0x100102f30, 0x100102f30"

a1 и a2 имеют одинаковое расположение памяти, что означает, что Apple также использует одноэлементный подход. Если мы напечатаем имя класса __NSPlaceholderArray, чтобы это в значительной степени подтверждало это.

Итак, да, придерживайтесь [NSMutableArray new]:)

ОБНОВЛЕНИЕ: Грег Паркер указывает, что @[] также является синглом, поэтому @[].mutableCopy приводит к только одному распределению. Таким образом, два примера одинаковы.

Ответ 2

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

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

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

В этом отношении я бы предпочел второй фрагмент кода над первым. Это говорит о многом, что вы пытаетесь сделать. Первый фрагмент не только труднее читать; он также фиксирует ошибку стиля использования точечной нотации для вызова метода, а не получает значение свойства.

Плюс вызывает сердечные приступы просто не приятно.:)

Ответ 3

Трудно точно определить, сколько объектов создано, особенно в случае литерала массива.

Официальные документы clang говорят, что @[] расширяется до arrayWithObjects:count:, который, как я подозреваю, реализован как [[[self alloc] initWithObjects:objects count:count] autorelease],

Таким образом, в этой точке может быть выделен второй объект, поскольку NSArray является кластером классов , а реализация - [NSArray init] может выглядеть примерно так: это:

- (id)init
{
    [self release];
    self = [[__NSArrayI alloc] init];
    return self;
}

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

#import <Foundation/Foundation.h>


int main()
{
    NSArray *a = [NSArray alloc];
    NSLog(@"NSArray before init: %@", a.class);

    a = [a init];
    NSLog(@"NSArray after init: %@", a.class);

    NSArray *al = @[];
    NSLog(@"Array literal: %@", al.class);

    NSMutableArray *ma1 = [a mutableCopy];
    NSLog(@"NSMutableArray (copied): %@", ma1.class);

    NSMutableArray *ma2 = [NSMutableArray alloc];
    NSLog(@"NSMutableArray (manufactured) before init: %@", ma2.class);

    ma2 = [ma2 init];
    NSLog(@"NSMutableArray (manufactured) after init: %@", ma2.class);

    return 0;
}

И вот что он печатает (NSLog() беспорядок удален для ясности):

h2co3-macbook:~ h2co3$ ./quirk
NSArray before init: __NSPlaceholderArray
NSArray after init: __NSArrayI
Array literal: __NSArrayI
NSMutableArray (copied): __NSArrayM
NSMutableArray (manufactured) before init: __NSPlaceholderArray
NSMutableArray (manufactured) after init: __NSArrayM

Изменить: вот еще код с подключением. Результаты очень интересны, но это печатает много текста, поэтому вам рекомендуется компилировать и запускать его. В результате получается, что инициализаторы не не проходят через [NSArray init]:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>

void hook(Class cls, SEL sel, IMP newimp, IMP *old)
{
    Method m = class_getInstanceMethod(cls, sel);
    *old = method_setImplementation(m, newimp);
}

#define CLS(c) objc_getClass(#c)
#define META(c) objc_getMetaClass(#c)

IMP old_$_NSArray_$_alloc;
IMP old_$_NSMutableArray_$_alloc;
IMP old_$_NSPlaceholderArray_$_alloc;
IMP old_$_NSArrayI_$_alloc;
IMP old_$_NSArrayM_$_alloc;

IMP old_$_NSArray_$_init;
IMP old_$_NSMutableArray_$_init;
IMP old_$_NSPlaceholderArray_$_init;
IMP old_$_NSArrayI_$_init;
IMP old_$_NSArrayM_$_init;

id new_$_NSArray_$_alloc(id self, SEL _cmd)
{
    printf("+ [NSArray<%p> alloc]\n", self);
    return old_$_NSArray_$_alloc(self, _cmd);
}

id new_$_NSMutableArray_$_alloc(id self, SEL _cmd)
{
    printf("+ [NSMutableArray<%p> alloc]\n", self);
    return old_$_NSMutableArray_$_alloc(self, _cmd);
}

id new_$_NSPlaceholderArray_$_alloc(id self, SEL _cmd)
{
    printf("+ [NSPlaceholderArray<%p> alloc]\n", self);
    return old_$_NSPlaceholderArray_$_alloc(self, _cmd);
}

id new_$_NSArrayI_$_alloc(id self, SEL _cmd)
{
    printf("+ [NSArrayI<%p> alloc]\n", self);
    return old_$_NSArrayI_$_alloc(self, _cmd);
}

id new_$_NSArrayM_$_alloc(id self, SEL _cmd)
{
    printf("+ [NSArrayM<%p> alloc]\n", self);
    return old_$_NSArrayM_$_alloc(self, _cmd);
}

id new_$_NSArray_$_init(id self, SEL _cmd)
{
    printf("- [NSArray<%p> init]\n", self);
    return old_$_NSArray_$_init(self, _cmd);
}

id new_$_NSMutableArray_$_init(id self, SEL _cmd)
{
    printf("- [NSMutableArray<%p> init]\n", self);
    return old_$_NSMutableArray_$_init(self, _cmd);
}

id new_$_NSPlaceholderArray_$_init(id self, SEL _cmd)
{
    printf("- [NSPlaceholderArray<%p> init]\n", self);
    return old_$_NSPlaceholderArray_$_init(self, _cmd);
}

id new_$_NSArrayI_$_init(id self, SEL _cmd)
{
    printf("- [NSArrayI<%p> init]\n", self);
    return old_$_NSArrayI_$_init(self, _cmd);
}

id new_$_NSArrayM_$_init(id self, SEL _cmd)
{
    printf("- [NSArrayM<%p> init]\n", self);
    return old_$_NSArrayM_$_init(self, _cmd);
}

int main()
{
    hook(META(NSArray), @selector(alloc), (IMP)new_$_NSArray_$_alloc, &old_$_NSArray_$_alloc);
    hook(META(NSMutableArray), @selector(alloc), (IMP)new_$_NSMutableArray_$_alloc, &old_$_NSMutableArray_$_alloc);
    hook(META(__NSPlaceholderArray), @selector(alloc), (IMP)new_$_NSPlaceholderArray_$_alloc, &old_$_NSPlaceholderArray_$_alloc);
    hook(META(__NSArrayI), @selector(alloc), (IMP)new_$_NSArrayI_$_alloc, &old_$_NSArrayI_$_alloc);
    hook(META(__NSArrayM), @selector(alloc), (IMP)new_$_NSArrayM_$_alloc, &old_$_NSArrayM_$_alloc);

    hook(CLS(NSArray), @selector(init), (IMP)new_$_NSArray_$_init, &old_$_NSArray_$_init);
    hook(CLS(NSMutableArray), @selector(init), (IMP)new_$_NSMutableArray_$_init, &old_$_NSMutableArray_$_init);
    hook(CLS(NSPlaceholderArray), @selector(init), (IMP)new_$_NSPlaceholderArray_$_init, &old_$_NSPlaceholderArray_$_init);
    hook(CLS(NSArrayI), @selector(init), (IMP)new_$_NSArrayI_$_init, &old_$_NSArrayI_$_init);
    hook(CLS(NSArrayM), @selector(init), (IMP)new_$_NSArrayM_$_init, &old_$_NSArrayM_$_init);


    NSArray *a = [NSArray alloc];
    NSLog(@"NSArray before init: %@<%p>", a.class, a);

    a = [a init];
    NSLog(@"NSArray after init: %@<%p>", a.class, a);

    NSArray *al = @[];
    NSLog(@"Array literal: %@<%p>", al.class, al);

    NSMutableArray *ma1 = [a mutableCopy];
    NSLog(@"NSMutableArray (copied): %@<%p>", ma1.class, ma1);

    NSMutableArray *ma2 = [NSMutableArray alloc];
    NSLog(@"NSMutableArray (manufactured) before init: %@<%p>", ma2.class, ma2);

    ma2 = [ma2 init];
    NSLog(@"NSMutableArray (manufactured) after init: %@<%p>", ma2.class, ma2);

    return 0;
}

Ответ 4

Да, один выделяет 2 объекта, другой - нет. Я делаю [NSMutableArray new]

UPDATE: Грег Паркер прав, оба выделяют только один объект.