我遇到了问题。我将一个对象通过它的引用传递给另一个类。设置该对象中的值。现在,当我在回调处理程序中访问此变量时,它就是nil。
我的示例代码是:
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]);
}
我在回调响应中的A类中得到 jobId nil 。如何从B类到A类获得此值。
感谢您的帮助。
答案 0 :(得分:1)
您不应该通过引用传递以获取方法中的更新值,因为ClassA和ClassB中的getListJobId
不指向相同的地址。
Obj-C块捕获其封闭范围之外的变量值。 请参阅“块可以从封闭范围中捕获值”部分。
我们可以从块的参数中获取更新的值,并在块中更新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);
}
答案 1 :(得分:0)
获取__block
变量的地址并不总是符合您的预期。
在当前实现中,__block
变量最初在堆栈上分配,然后在将使用它的任何块移动到堆中时“移动”到堆(这是由块所引起的)复制)。
因此, __block
变量的地址会在其生命周期内发生变化。如果您获取它的地址并移动,那么您将不再指向其他人正在使用的变量版本。
在这里,发生的事情是,当__block
变量getListJobId
仍在堆栈中时,它会获取该地址。它仍然在堆栈上,因为它通过复制使用它的任何块而被移动到堆,但是还没有创建块。
然后,使用getListJobId
的块被复制到某处,getListJobId
被移动到堆中。究竟发生这种情况的地方并不十分清楚,因为允许ARC在不同的地方插入块的副本。另外,你在这里显示的代码看起来不像你的真实代码,因为没有必要同步在方法结束时调用“完成块”(在这种情况下你只需返回并让调用者执行完成后他们想要的操作)。相反,您的实际代码可能执行异步操作,最后调用完成处理程序。 dispatch_async
和相关的异步函数复制传递给它们的块(它们会复制捕获的任何块,依此类推)。
我猜你的实际代码中,*jobId = @"shiv";
行和完成块的调用都发生在异步操作中。发生的事情是异步操作的创建会复制块并导致getListJobId
移动到堆中。所以在异步操作中,getListJobId
指的是变量的堆版本。但是,*jobId = @"shiv";
写入变量的堆栈版本,因为jobId
是从变量的地址中取出的指针,当变量仍在堆栈中时。所以你要写和阅读不同的变量。
此外,您在*jobId = @"shiv";
中所做的事情非常危险,因为在异步操作时,原始函数调用的堆栈帧不再存在。堆栈帧消失后写入堆栈中的变量是未定义的行为,您可能会覆盖内存中的其他未知变量。你很幸运它没有崩溃。