0

У меня возникла проблема. Я передаю объект другому классу по его ссылке &, устанавливая значение в этом объекте. Теперь, когда я получаю доступ к этой переменной в обработчике обратного вызова, тогда она равна нулю.Прохождение по ссылке в обратных вызовах

Мой пример кода:

Класс A:

__block NSString *getListJobId = nil; 
ClassB *bobject = [[ClassB alloc]init]; 
    [bobject getItemsWithJobId:&getListJobId onSuccess:^(NSArray *response) { 
     NSLog(@"job id %@",getListJobId); //It is nil, It should be **shiv** 
    } onFailure:^(NSError *error) { 
    }]; 

Класс B: .h

- (void)getItemsWithJobId:(NSString **)jobId onSuccess:(void (^)(NSArray *))completedBlock onFailure:(void (^)(NSError *))failureBlock; 

.m

- (void)getItemsWithJobId:(NSString **)jobId onSuccess:(void (^)(NSArray *))completedBlock onFailure:(void (^)(NSError *))failureBlock 
{ 
    *jobId = @"shiv"; 
    completedBlock([NSArray new]); 
} 

Я получаю эту JobIdноль в классе А в ответ обратного вызова. Как я могу получить это значение от класса B до класса A.

Буду признателен за вашу помощь.

+0

Попробуйте инициализировать 'getListJobId' до NULL вместо nil – gabuh

+0

@gabuh: его не работает .. :( – shivam

ответ

1

Вы не должны передавать по ссылке, чтобы получить обновленное значение в методе, поскольку getListJobId в ClassA и ClassB не указывают тот же адрес.

Блок Obj-C фиксирует значение переменных вне его охватывающей области. См. Раздел «Блоки могут захватывать значения из области охвата».

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html

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

Класс A:

__block NSString *getListJobId = nil; 
ClassB *bobject = [[ClassB alloc] init]; 
[bobject getItemsWithJobId:getListJobId onSuccess:^(NSArray *response, NSString *updatedJobId) { 
    getListJobId = updatedJobId; 
    NSLog(@"job id %@", getListJobId); // job id **shiv** 
} onFailure:^(NSError *error) { 
}]; 

Класс B: .h

- (void)getItemsWithJobId:(NSString *)jobId onSuccess:(void (^)(NSArray *, NSString *))completedBlock onFailure:(void (^)(NSError *))failureBlock; 

.m

- (void)getItemsWithJobId:(NSString *)jobId onSuccess:(void (^)(NSArray *, NSString *))completedBlock onFailure:(void (^)(NSError *))failureBlock 
{ 
    NSString *updatedJobId = @"**shiv**"; 
    completedBlock([NSArray new], updatedJobId); 
} 
0

Принимая адрес переменной __block не всегда делает то, что вы ожидаете.

В текущей реализации переменные изначально выделяются в стеке и затем «перемещаются» в кучу на любом из блоков, которые используют его, перемещаются в кучу (что вызвано копированием блока) ,

Таким образом, изменяется переменная переменной на протяжении ее жизни. Если вы берете его адрес и он перемещается, то вы больше не будете указывать на версию переменной, которую используют все остальные.

Здесь происходит то, что вы берете адрес __block переменной getListJobId, пока он все еще находится в стеке. Он все еще находится в стеке в тот момент, потому что он вызван для перемещения в кучу путем копирования любого блока, который его использует, но блок еще не создан.

Затем блок, который использует getListJobId, копируется где-то, а getListJobId перемещается в кучу. Точно там, где это происходит, не очень понятно, потому что ARC разрешено вставлять копии блоков в разных местах. Кроме того, код, который вы показываете здесь, не похож на ваш реальный код, потому что не было бы смысла синхронно вызывать «блок завершения» в конце метода (в этом случае вы просто вернетесь и позвольте вызывающему операции, которые они хотят выполнить). Скорее, ваш реальный код, вероятно, выполняет асинхронную операцию, в конце которой вызывается обработчик завершения. dispatch_async и связанные с ними асинхронные функции копируют переданные им блоки (которые, в свою очередь, копируют все захваченные блоки и т. Д.).

Я предполагаю, что в вашем реальном коде обе строки *jobId = @"shiv"; и вызов блока завершения выполняются в асинхронной операции. Что происходит, так это то, что создание асинхронной операции копирует блок и вызывает перемещение getListJobId в кучу. Таким образом, внутри асинхронной операции getListJobId ссылается на кучную версию переменной. Тем не менее, *jobId = @"shiv"; записывает в стек версии переменной, потому что jobId является указателем, взятым из адреса переменной, когда он все еще находится в стеке. Таким образом, вы пишете и читаете из разных переменных.

Кроме того, то, что вы делаете в *jobId = @"shiv";, очень опасно, потому что к моменту асинхронной операции фрейм стека вызова исходной функции больше не существует. И запись в переменную в стеке после исчезновения фрейма стека - это неопределенное поведение, и вы можете перезаписать другие неизвестные переменные в памяти. Вам повезло, что он не потерпел крушение.

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