0

У меня есть метод, который принимает блок:Скопированных блоки и предупреждение утечки звона

- (void)methodWithBlock:(blockType)block 

Способ начинается путем копирования block, потому что она делает асинхронные вещи, прежде чем использовать его, и это было бы в противном случае. Отбрасывается Затем он вызывает метод в другом блоке, а затем освобождает его в этом блоке. Резюме:

- (void)methodWithBlock:(blockType)block 
{ 
    block = [block copy]; 
    [something asyncStuffWithFinishedBlock:^{ 
     // .. 
     block(); 
     [block release]; 
    }]; 
} 

CLANG жалуется на утечку памяти для «блока». Если я удалю операторы копирования и освобождения, блок исчезнет к тому времени, когда он будет вызван - по крайней мере, ранние сбои указывают на то, что это так.

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

ответ

3

Во-первых, -copy и -release не должны быть ненужными. Метод -asyncStuffWithFinishedBlock: должен скопировать переданный ему блок. Когда блок копируется и ссылается на другие объекты блока, он также копирует эти объекты блока. Вам нужно выяснить реальную природу аварии, которую вы видели.

Во-вторых, вы выпускаете неправильную вещь. [block copy] не изменяет block (получатель сообщения -copy), как-то превращая его в копию. Он возвращает копию этого блока. Именно эта возвращенная копия вы хотите ссылаться как в заявлении на вызовы (block();), так и при выпуске.

Таким образом, вы можете сделать:

block = [block copy]; 
[something asyncStuffWithFinishedBlock:^{ 
    // .. 
    block(); 
    [block release]; 
}]; 

Примечание переназначение локального block переменной, чтобы указать на копии.

Думайте об этом так: вы бы скопировали строку так, как вы пытались скопировать этот блок? Вы бы сделать:

[someString copy]; 
// ... use someString ... 
[someString release]; 
+0

Упс, я опечатал - в этом утверждении я имел в виду block = [block copy]. – Kalle

+0

Что касается их не нужно ... гах. Хорошо, спасибо, я сделаю некоторые исследования. – Kalle

1

Я не думаю, что вы должны сделать release внутри блока, как это. Вы предполагаете, что блок вызывается ровно один раз. Но только из кода мы этого не знаем. Может быть, этот метод вообще не выполняет блок, и в этом случае вы не будете выпускать, поэтому протекаете. Также может случиться так, что метод выполняет блок более одного раза, и в этом случае вы будете перевыпускать.

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

- (void)methodWithBlock:(blockType)block 
{ 
    block = [block copy]; 
    [something asyncStuffWithFinishedBlock:^{ 
     // .. 
     block(); 
    }]; 
    [block release]; 
} 

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

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

+0

Я забыл упомянуть об этом, но да, блок - это одноразовая вещь, которая сбрасывается. – Kalle

Смежные вопросы