какао блоки как сильные указатели против копирования

<p>я работал несколько раз с блоками, как с указателями, на которые я имел сильную ссылку</p><p>я слышал, что вы должны использовать копирование, но <strong>что подразумевается при работе с блоками как указателями, а не с необработанным объектом?</strong></p><p>я никогда не получал жалобу от компилятора, что я не должен использовать</p><pre><code>@property (nonatomic, strong) myblock block; </code></pre><p>но следует использовать</p><pre><code>@property (nonatomic, copy) myblock block; </code></pre><p>насколько я знаю, блок - это просто объект, так почему же в любом случае предпочтительнее копировать?</p>

<p><strong> короткий ответ </strong></p><p>ответ это исторический, вы совершенно правы, что в текущем коде arc нет необходимости использовать <code>copy</code> и свойство <code>strong</code> вполне подойдет. то же самое касается, например, локальных и глобальных переменных.</p><p><strong> длинный ответ </strong></p><p>в отличие от других объектов блок <em> может </em> храниться в стеке, это <em> оптимизация реализации </em> и, как таковая, должна, как и другие оптимизации компилятора , не имеют прямого влияния на написанный код. эта оптимизация выгодна в общем случае, когда блок создается, передается как аргумент метода/функции, используется этой функцией, а затем отбрасывается - блок может быть быстро размещен в стеке и затем удален без кучи (динамический пул памяти) быть вовлеченным.</p><p>сравните это с <em> локальными переменными </em>, которые (a), созданные в стеке <em> </em>, (b), автоматически уничтожаются, когда владеющая функция/метод возвращает и (c) может быть передан по адресу в методы/функции, вызываемые функцией-владельцем. адрес локальной переменной не может быть сохранен и использован <em> после того, как </em> возвращена его собственная функция/метод - переменная больше не существует.</p><p>однако ожидается, что <em> объекты </em> превзойдут свою функцию/метод создания (если требуется), поэтому в отличие от локальных переменных они размещаются в куче <em> </em> и не уничтожаются автоматически в зависимости от возврата созданной ими функции/метода, а скорее в зависимости от того, нужны ли они по-прежнему, а arc в эти дни автоматически определяет "потребность".</p><p>создание блока в стеке может оптимизировать общий случай, но это также вызывает проблему - если блок должен пережить своего создателя, как это часто делают объекты, то он должен быть перемещен в кучу, прежде чем его стек создателей будет уничтожен.</p><p>когда реализация блока была впервые выпущена, оптимизация хранения блоков в стеке стала видна программистам, поскольку компилятор в то время не мог автоматически обрабатывать перемещение блока в кучу, когда это необходимо - программистам для этого приходилось использовать функцию <code>block\_copy()</code> самих себя.</p><p>хотя этот подход может быть неуместным в мире c низкого уровня (а блоки - конструкцией c), наличие высокоуровневых программистов objective-c вручную управляющих оптимизацией компилятора на самом деле не очень хорошо. как apple выпустила новые версии улучшений компилятора, где были сделаны. ранее программистам было сказано, что они могут заменить <code>block\_copy(block)</code> на <code>[block copy]</code>, вписываясь в обычные объекты objective-c. затем компилятор начал автоматически копировать блоки из стека по мере необходимости, но это не всегда было официально задокументировано.</p><p>некоторое время не было необходимости вручную копировать блоки из стека, хотя apple не может сбрасывать со счетов свое происхождение и называет это "наилучшей практикой", что, безусловно, является дискуссионным. в последней версии, сентябрь 2014 г., apple <a href="https://developer.apple.com/library/ios/documentation/cocoa/conceptual/programmingwithobjectivec/workingwithblocks/workingwithblocks.html">работа с блоками</a> , они заявили, что в свойствах с блочными значениями следует использовать <code>copy</code>, но затем сразу же появятся чистые (<em> выделение </em> добавил):</p><blockquote> <p><strong> примечание: </strong> вы должны указать copy в качестве атрибута свойства, поскольку необходимо скопировать блок, чтобы отслеживать его захваченное состояние вне исходной области видимости. <em> это не то, о чем вам нужно беспокоиться при использовании автоматического подсчета ссылок, так как это произойдет автоматически, но рекомендуется, чтобы атрибут свойства показывал результирующее поведение. </em></p> </blockquote><p>нет необходимости "показывать результирующее поведение" - сохранение блока в стеке в первую очередь является <em> оптимизацией </em> и должно быть прозрачным для кода - как и другие оптимизации компилятора код должен получить выигрыш в производительности без участия программиста.</p><p>поэтому, пока вы используете arc и текущие компиляторы clang, вы можете обрабатывать блоки как другие объекты, и поскольку блоки являются неизменяемыми, это означает, что вам не нужно их копировать. доверяйте apple, даже если они кажутся ностальгирующими по "старым добрым временам, когда мы все делали вручную", и призываем вас оставлять исторические напоминания в вашем коде, <code>copy</code> не требуется.</p><p>ваша интуиция была права.</p><p>нтн</p>

<p>вы спрашиваете о модификаторе владения для собственности. это влияет на синтезированный (или автоматически синтезированный) геттер и/или сеттер для свойства, если оно синтезировано (или автоматически синтезировано).</p><p>ответ на этот вопрос будет отличаться между mrc и arc.</p><ul> <li> <p>в mrc модификаторы владения недвижимостью включают <code>assign</code>, <code>retain</code> и <code>copy</code>. <code>strong</code> был введен в arc, и когда <code>strong</code> используется в mrc, он является синонимом <code>retain</code>. таким образом, вопрос будет касаться разницы между <code>retain</code> и <code>copy</code>, и есть большая разница, потому что установщик <code>copy</code> сохраняет копию заданного значения.</p> <p>блоки должны быть скопированы для использования вне области, в которой они были созданы (с литералом блока). поскольку ваше свойство будет хранить значение как переменную экземпляра, которая сохраняется при вызовах функций, и возможно, что кто-то назначит незанятый блок из области, в которой он был создан, соглашение заключается в том, что вы должны его скопировать. <code>copy</code> является модификатором права собственности.</p> </li> <li> <p>в arc <code>strong</code> делает базовую переменную экземпляра <code>\_\_strong</code>, а <code>copy</code> также делает ее <code>\_\_strong</code> и добавляет семантику копирования в установщик. однако arc также гарантирует, что при сохранении значения в переменную <code>\_\_strong</code> типа указателя блока выполняется копирование. ваше свойство имеет тип <code>myblock</code>, который, как я полагаю, является typedef для типа указателя блока. следовательно, копия все равно будет сделана в установщике, если квалификатор владения был <code>strong</code>. таким образом, в arc нет разницы между использованием <code>strong</code> и <code>copy</code> для этого свойства.</p> </li> </ul><p>если это объявление может использоваться как в mrc, так и в arc (например, заголовок в библиотеке), было бы неплохо использовать <code>copy</code>, чтобы оно работало правильно в обоих случаях.</p>

<pre><code>what is the implication in working with blocks as pointers and not with the raw object? </code></pre><p>вы никогда не используете необработанное значение, у вас всегда есть указатель на блок: блок является объектом.</p><p>глядя на ваш конкретный пример, я предполагаю, что вы хотите сохранить блок, <strong> "так почему же в любом случае предпочтительнее копировать" </strong> <code>enter code here</code>? ну, это вопрос <strong> безопасности </strong> (этот пример взят из блога майка эша). поскольку блоки расположены в стеке (а не в куче, как остальные объекты в target-c), когда вы делаете что-то вроде этого:</p><pre><code>[dictionary setobject: ^{ printf("hey hey\n"); } forkey: key]; </code></pre><p>вы выделяете блок в кадре стека вашей текущей области, поэтому, когда область заканчивается (например, вы возвращаете словарь), кадр стека уничтожается, и блок идет вместе с ним. таким образом, у вас есть свисающий указатель. я бы посоветовал прочитать <a href="https://www.mikeash.com/pyblog/friday-qa-2010-01-15-stack-and-heap-objects-in-objective-c.html">статья майка</a> полностью. в любом случае, вы можете использовать свойство <code>strong</code>, если при назначении блока вы копируете его:</p><pre><code>self.block = [^{} copy]; </code></pre><p><strong> редактировать: </strong> посмотрев на дату статьи майка, я предполагаю, что это было поведение pre-arc. на arc кажется, что он работает, как ожидалось, и не будет зависать.</p><p><strong> edit2: </strong> после экспериментов с не-arc он также не падает. но этот пример показывает разные результаты в зависимости от использования arc или нет:</p><pre><code>void (^block[10])(); int i = -1; while(++i < 10) block[i] = ^{ printf("%d\n", i); }; for(i = 0; i < 10; i++) block[i](); </code></pre><p>цитируя майка эша о различных результатах:</p><blockquote> <p>причина, по которой он печатает десять 9 в первом случае, довольно проста: блок, созданный в цикле, имеет время жизни, привязанное к внутренней области видимости цикла. блок уничтожается на следующей итерации цикла и при выходе из цикла. конечно, "уничтожить" просто означает, что его слот в стеке доступен для перезаписи. просто так получается, что компилятор повторно использует один и тот же слот каждый раз в цикле, поэтому в конце массив заполняется одинаковыми указателями, и, таким образом, вы получаете идентичное поведение.</p> </blockquote>

<blockquote> <p>примечание: вы должны указать copy в качестве атрибута свойства, потому что необходимо скопировать блок, чтобы отслеживать его захваченное состояние за пределами исходной области видимости. это не то, о чем вам нужно беспокоиться при использовании автоматического подсчета ссылок, так как это произойдет автоматически, но лучше всего, чтобы атрибут свойства отображал результирующее поведение. для получения дополнительной информации см. <a href="https://developer.apple.com/library/content/documentation/cocoa/conceptual/blocks/articles/00\_introduction.html#//apple\_ref/doc/uid/tp40007502">блокирует темы программирования</a> .</p> </blockquote>