ARC и автореферат

autorelease используется для возвращаемого функционального объекта, поэтому вызывающий абонент не принимает права собственности, а вызываемый освободит объект в будущем.

Тем не менее, ARC может рассчитывать право собственности на вызывающего абонента и выпускать его после использования, то есть он может вести себя так же, как Smart Pointer на С++. С ARC он может избавиться от автореферата, потому что автореферат не является детерминированным.

Причина, по которой я задаю этот вопрос, заключается в том, что я вижу возвращаемые объекты, вызывающие dealloc ранее в ARC, чем код, не относящийся к ARC. Это заставляет меня думать, что ARC может выглядеть как Smart Pointer и может сделать авторекламу бесполезной. Это правда или возможно? Единственное, что я могу сказать о полезности автореферата, - это многопоточный или сетевой код, потому что, возможно, не так просто подсчитать право собственности, когда объект проходит.

Спасибо за ваши мысли.

Вот новое редактирование, чтобы все было ясно:

с авторекламой

+ (MyClass*) myClass
{
    return [[[MyCClass alloc] init] autorelease];
}

- doSomething
{
   MyClass *obj = [MyClass myClass];
}

С ARC:

+ (MyClass*) myClass
{
    return [[MyCClass alloc] init]; // no autorelease
}

- doSomething
{
   MyClass *obj = [MyClass myClass];
   // insert [obj release]
}

Итак, нам действительно не нужна автореферат.

Ответ 1

Автореферат как механизм по-прежнему используется ARC, кроме того, компилятивный код ARC предназначен для беспрепятственного взаимодействия с компилированным кодом MRC, так что авторефератное оборудование находится вокруг.

Во-первых, не думайте в терминах ссылок, но с точки зрения доли владения - пока существует заявленная доля собственности в объекте, тогда объект живет, когда нет доли собственности, он уничтожается. В MRC вы объявляете права собственности, используя retain, или создавая новый объект; и вы отказываетесь от доли участия, используя release.

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

Для решения этой проблемы используются два решения:

1) Объявлен способ передачи доли владения в возвращаемое значение от вызываемого абонента - это модель, используемая для методов init, copy и т.д. Обвиняемый никогда не уведомляет, что он отказывается от своей доли владения, а вызывающий не объявляет права собственности - по соглашению абонент просто берет на себя долю собственности и несет ответственность за отказ от нее позже.

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

Вопрос в том, кто может "кто-то" быть тем, кто поддерживает права собственности? Это не может быть метод вызова, поскольку он собирается уйти. Введите "пул авторесурсов" - это просто объект, на который кто-либо может передать долю владения, чтобы объект оставался на некоторое время. Пул авторекламы будет отчуждать свою долю владения во всех объектах, переданных ему таким образом, когда им будет дано указание - обычно в конце текущего цикла цикла цикла.

Теперь, если это имеет смысл (то есть, если я объясню это ясно), вы можете видеть, что метод (2) действительно не требуется, поскольку вы всегда можете использовать метод (1); но, и это важно, но, в рамках MRC, для программиста гораздо больше работы - каждое значение, полученное от метода, связано с интересом к владению, которому в какой-то момент нужно управлять и отказаться от него - создать строку для ее вывода? Ну, тогда вам нужно отказаться от вашего интереса к этой временной строке... Так что (2) облегчает жизнь.

В одних руках компьютеры просто быстрые идиоты, а подсчет вещей и вставка кода для отказа от участия в собственности от имени интеллектуальных программистов - это то, к чему они хорошо подходят. Поэтому ARC не нуждается в пуле автоматического выпуска. Но это может сделать все проще и эффективнее, и за кулисами ARC оптимизирует его использование - посмотрите на выход ассемблера в Xcode, и вы увидите вызовы подпрограмм с именем, похожим на "keepAutoreleasedReturnValue"...

Итак, вы правы, его не нужно, но все равно полезно, но при ARC вы можете (обычно) забыть, что он даже существует.

HTH больше, чем это, вероятно, смущает!

Ответ 2

autorelease используется для возвращаемого функционального объекта, поэтому вызывающий абонент не принимает права собственности, а вызываемый освободит объект в будущем.

Если автореализован, он будет добавлен в пул автозапуска. Когда пул авторезистов сливается, отсроченный выпуск будет выполнен. функция/метод не нуждается в возврате объекта с автореализацией (например, это может быть ivar, который не получил цикл сохранения/авторекламы).

Тем не менее, ARC может рассчитывать право собственности на вызывающего абонента и выпускать его после использования, то есть он может вести себя так же, как Smart Pointer на С++. С ARC он может избавиться от автореферата, потому что автореферат не является детерминированным.

У этого есть потенциал. Нет никакой гарантии. Самая большая проблема заключается в том, что компилятор не знает/не заботится о механизме памяти возвращаемого объекта произвольного вызова. Он не может предположить, как возвращается объект, потому что ARC - это новое дополнение, которое предшествует MRC. Это важно, потому что это делает программы ARC совместимыми с программами, которые используют ручное сохранение/освобождение. Например, Foundation.framework может использовать ARC, или он может использовать MRC, или он может использовать оба. Он также может вызывать API, которые были созданы с использованием старых инструментальных цепей. Таким образом, это позволяет сохранить тонну существующего кода.

Причина, по которой я задаю этот вопрос, заключается в том, что я вижу возвращаемые объекты, вызывающие dealloc ранее в ARC, чем код без ARC.

Есть необязательный способ возврата объекта - см. ответ CRD (+1) о сборке и вызовы, которые вставляет компиляторы для выполнения операций подсчета ссылок, например. retainAutoreleasedReturnValue.

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

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

В теории я не понимаю, почему пулы автозавершения не могут быть устранены для новой системы. Тем не менее, я думаю, что слишком много существующего кода, который полагается на пулы автозаполнения, чтобы снять это ограничение - я думаю, что им нужно будет перейти в новый исполняемый формат (как в случае с ObjC Garbage Collection) и просмотреть тонну существующих API и программы для такого значительного перехода к успеху. Кроме того, несколько API, вероятно, просто нужно будет удалить. API-интерфейсы могут нуждаться в некотором усилении в отношении собственности для достижения этого, но большая часть этого завершена в программах, которые уже были перенесены в ARC. Черт, даже компилятор может (быть расширенным) внутренне использовать форму умных указателей для передачи и возвращения типов objc, а пулы авторесурсов могут быть исключены в такой системе. Опять же, для этого потребуется много кода для переноса. Таким образом, такое обновление будет похоже на ARC V2.

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

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

Ответ 3

Разница между ARC и авторекламой объясняется в коде:

ARC:

-somefunc {
  id obj = [NSArray array];
  NSLog(@"%@", obj);
  // ARC now calls release for the first object

  id obj2 = [NSArray array];
  NSLog(@"%@", obj2);
  // ARC now calls release for the second object
}

Автореферат:

-somefunc {
  id obj = [NSArray array];
  NSLog(@"%@", obj);

  id obj2 = [NSArray array];
  NSLog(@"%@", obj2);
}
// Objects are released some time after this

В основном ARC работает, как только переменная больше не используется в области, в то время как autorelease ждет, пока она не достигнет основного цикла, а затем вызовет release для всех объектов в пуле. ARC используется внутри области, autorelease используется вне сферы действия функции.

Ответ 4

autorelease по-прежнему используется в ARC. ARC просто делает звонок для вас и умеет коротко замыкать его. Вот демонстрация о том, как это работает, что я буду копировать здесь, если сообщение в блоге когда-либо исчезнет; все должное внимание Matt Galloway.

Итак, рассмотрим следующий метод:

void foo() {
    @autoreleasepool {
        NSNumber *number = [NSNumber numberWithInt:0];
        NSLog(@"number = %p", number);
    }
}

Это совершенно надуманно, конечно, но это должно позволить нам увидеть, что продолжается. В странах, не относящихся к ARC, мы предполагаем, что это число будет выделено внутри numberWithInt: и возвращено autoreleased. Поэтому, когда пул авторекламы будет опущен, он будет выпущен. Поэтому давайте посмотрим, вот что произошло (как обычно, это инструкции ARMv7):

    .globl  _foo
    .align  2
    .code   16
    .thumb_func     _foo
_foo:
    push    {r4, r7, lr}
    add     r7, sp, #4
    blx     _objc_autoreleasePoolPush
    movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4))
    movs    r2, #0
    movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4))
    mov     r4, r0
    movw    r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4))
LPC0_0:
    add     r1, pc
    movt    r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4))
LPC0_1:
    add     r0, pc
    ldr     r1, [r1]
    ldr     r0, [r0]
    blx     _objc_msgSend
    mov     r1, r0
    movw    r0, :lower16:(L__unnamed_cfstring_-(LPC0_2+4))
    movt    r0, :upper16:(L__unnamed_cfstring_-(LPC0_2+4))
LPC0_2:
    add     r0, pc
    blx     _NSLog
    mov     r0, r4
    blx     _objc_autoreleasePoolPop
    pop     {r4, r7, pc}

Ну да. Это точно, что происходит. Мы можем видеть призыв к нажмите пул автообновлений, а затем наберите номер с номеромWithInt: затем вызов поп-аутсорсинг-пул. Точно, чего ожидать. Теперь давайте посмотрим на тот же самый код, скомпилированный в ARC:

    .globl  _foo
    .align  2
    .code   16
    .thumb_func     _foo
_foo:
    push    {r4, r5, r7, lr}
    add     r7, sp, #8
    blx     _objc_autoreleasePoolPush
    movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4))
    movs    r2, #0
    movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4))
    mov     r4, r0
    movw    r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4))
LPC0_0:
    add     r1, pc
    movt    r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4))
LPC0_1:
    add     r0, pc
    ldr     r1, [r1]
    ldr     r0, [r0]
    blx     _objc_msgSend
    @ InlineAsm Start
    mov     r7, r7          @ marker for objc_retainAutoreleaseReturnValue
    @ InlineAsm End
    blx     _objc_retainAutoreleasedReturnValue
    mov     r5, r0
    movw    r0, :lower16:(L__unnamed_cfstring_-(LPC0_2+4))
    movt    r0, :upper16:(L__unnamed_cfstring_-(LPC0_2+4))
    mov     r1, r5
LPC0_2:
    add     r0, pc
    blx     _NSLog
    mov     r0, r5
    blx     _objc_release
    mov     r0, r4
    blx     _objc_autoreleasePoolPop
    pop     {r4, r5, r7, pc}

Обратите внимание на вызовы objc_retainAutoreleasedReturnValue и objc_release. Происходит то, что ARC определила для нас что ему действительно не нужно беспокоиться о пуле авторесурсов, который на месте, потому что он может просто сказать, что автореферата не произойдет (с вызовом objc_retainAutoreleasedReturnValue), а затем отпустите объект позже сам. Это желательно, поскольку это означает, что автореферат логика не должна произойти.

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

Теперь рассмотрим другой пример, который мы хотим использовать номер за пределами области пула авторекламы. Это должно покажите нам, почему с ARC интересно работать. Рассмотрим следующий код:

void bar() {
    NSNumber *number;
    @autoreleasepool {
        number = [NSNumber numberWithInt:0];
        NSLog(@"number = %p", number);
    }
    NSLog(@"number = %p", number);
}

Вы могли бы (правильно) думать, что это вызовет проблемы даже если он выглядит совершенно безобидным. Это проблема, потому что число будет выделено внутри блока пула авторезистов, будет освобождается, когда пул авторезистов появляется, но затем используется после его был освобожден. О, о! Посмотрим, правильны ли они, скомпилировав его без ARC:

    .globl  _bar
    .align  2
    .code   16
    .thumb_func     _bar
_bar:
    push    {r4, r5, r6, r7, lr}
    add     r7, sp, #12
    blx     _objc_autoreleasePoolPush
    movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4))
    movs    r2, #0
    movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4))
    mov     r4, r0
    movw    r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4))
LPC1_0:
    add     r1, pc
    movt    r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4))
LPC1_1:
    add     r0, pc
    ldr     r1, [r1]
    ldr     r0, [r0]
    blx     _objc_msgSend
    movw    r6, :lower16:(L__unnamed_cfstring_-(LPC1_2+4))
    movt    r6, :upper16:(L__unnamed_cfstring_-(LPC1_2+4))
LPC1_2:
    add     r6, pc
    mov     r5, r0
    mov     r1, r5
    mov     r0, r6
    blx     _NSLog
    mov     r0, r4
    blx     _objc_autoreleasePoolPop
    mov     r0, r6
    mov     r1, r5
    blx     _NSLog
    pop     {r4, r5, r6, r7, pc}

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

    .globl  _bar
    .align  2
    .code   16
    .thumb_func     _bar
_bar:
    push    {r4, r5, r6, r7, lr}
    add     r7, sp, #12
    blx     _objc_autoreleasePoolPush
    movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4))
    movs    r2, #0
    movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4))
    mov     r4, r0
    movw    r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4))
LPC1_0:
    add     r1, pc
    movt    r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4))
LPC1_1:
    add     r0, pc
    ldr     r1, [r1]
    ldr     r0, [r0]
    blx     _objc_msgSend
    @ InlineAsm Start
    mov     r7, r7          @ marker for objc_retainAutoreleaseReturnValue
    @ InlineAsm End
    blx     _objc_retainAutoreleasedReturnValue
    movw    r6, :lower16:(L__unnamed_cfstring_-(LPC1_2+4))
    movt    r6, :upper16:(L__unnamed_cfstring_-(LPC1_2+4))
LPC1_2:
    add     r6, pc
    mov     r5, r0
    mov     r1, r5
    mov     r0, r6
    blx     _NSLog
    mov     r0, r4
    blx     _objc_autoreleasePoolPop
    mov     r0, r6
    mov     r1, r5
    blx     _NSLog
    mov     r0, r5
    blx     _objc_release
    pop     {r4, r5, r6, r7, pc}

Раунд аплодисментов для ARC, пожалуйста! Обратите внимание, что используя число, выходящее за рамки блока пула авторезистов, поэтому он сохранил возвращаемое значение от numberWithInt: так же, как это было раньше, но на этот раз он разместил выпуск в конце панели а не перед запуском пула авторекламы. Что будет спасли нас в некотором коде, который, возможно, думал правильно, но на самом деле была тонкая ошибка управления памятью.

Ответ 5

Тем не менее, ARC способен считать право собственности на вызывающего абонента и освобождать его после использования, то есть он может работать так же, как Smart Pointer в С++. С ARC он может избавиться от автореферата, потому что автореферат недетерминированная.

Вы путаете ARC с подсчетом ссылок. Objective-C всегда полагался на подсчет ссылок для управления памятью. ARC продолжает эту традицию и просто устраняет необходимость в программировании вручную вставлять соответствующие вызовы в -retain, -release и -autorelease. В ARC компилятор вставляет эти вызовы для вас, но механизм подсчета ссылок остается таким же, как и всегда.

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