Принимая адрес переменной __block
не всегда делает то, что вы ожидаете.
В текущей реализации переменные изначально выделяются в стеке и затем «перемещаются» в кучу на любом из блоков, которые используют его, перемещаются в кучу (что вызвано копированием блока) ,
Таким образом, изменяется переменная переменной на протяжении ее жизни. Если вы берете его адрес и он перемещается, то вы больше не будете указывать на версию переменной, которую используют все остальные.
Здесь происходит то, что вы берете адрес __block
переменной getListJobId
, пока он все еще находится в стеке. Он все еще находится в стеке в тот момент, потому что он вызван для перемещения в кучу путем копирования любого блока, который его использует, но блок еще не создан.
Затем блок, который использует getListJobId
, копируется где-то, а getListJobId
перемещается в кучу. Точно там, где это происходит, не очень понятно, потому что ARC разрешено вставлять копии блоков в разных местах. Кроме того, код, который вы показываете здесь, не похож на ваш реальный код, потому что не было бы смысла синхронно вызывать «блок завершения» в конце метода (в этом случае вы просто вернетесь и позвольте вызывающему операции, которые они хотят выполнить). Скорее, ваш реальный код, вероятно, выполняет асинхронную операцию, в конце которой вызывается обработчик завершения. dispatch_async
и связанные с ними асинхронные функции копируют переданные им блоки (которые, в свою очередь, копируют все захваченные блоки и т. Д.).
Я предполагаю, что в вашем реальном коде обе строки *jobId = @"shiv";
и вызов блока завершения выполняются в асинхронной операции. Что происходит, так это то, что создание асинхронной операции копирует блок и вызывает перемещение getListJobId
в кучу. Таким образом, внутри асинхронной операции getListJobId
ссылается на кучную версию переменной. Тем не менее, *jobId = @"shiv";
записывает в стек версии переменной, потому что jobId
является указателем, взятым из адреса переменной, когда он все еще находится в стеке. Таким образом, вы пишете и читаете из разных переменных.
Кроме того, то, что вы делаете в *jobId = @"shiv";
, очень опасно, потому что к моменту асинхронной операции фрейм стека вызова исходной функции больше не существует. И запись в переменную в стеке после исчезновения фрейма стека - это неопределенное поведение, и вы можете перезаписать другие неизвестные переменные в памяти. Вам повезло, что он не потерпел крушение.
Попробуйте инициализировать 'getListJobId' до NULL вместо nil – gabuh
@gabuh: его не работает .. :( – shivam