使用 NSValue 进行包装和解包
Posted
技术标签:
【中文标题】使用 NSValue 进行包装和解包【英文标题】:wrap & unwrap with NSValue 【发布时间】:2016-08-12 20:48:47 【问题描述】:在我的项目中,我有这样的功能:
- (void)doSomething:(NSError**)error
...
我需要使用函数 performSelector:onThread:withObject:waitUntilDone: 在另一个线程上调用此函数,如下所示:
[self performSelector:@selector(doSomething:) onThread:anotherThread withObject:??? waitUntilDone:NO];
但是函数参数的类型是NSError**
。我正在考虑将函数-(void)doSomething:
的参数类型从NSError**
重构为NSValue*
,并将NSValue*
类型作为参数传递。
这意味着,我需要将&error
(类型为NSError **
)包装成NSValue
,并将其作为参数传递,然后再将其解包。如何用NSValue
类包装和解包NSError**
?
【问题讨论】:
为什么需要将NSError
包裹在NSValue
中?
我想包装 NSError**
并将包装后的 NSValue 作为 argment 传递,然后调用 performSelector:withObject ,
1) 为什么你需要用NSValue
包裹NSError
只是为了将它传递给performSelector:withObject:
?没必要把它包起来。 2) 为什么需要使用performSelector:withObject:
?总有比这更好的方法。我建议更新您的问题,详细说明您真正需要完成的工作,以便人们提供更好的建议。
我将更详细地更新我的问题,谢谢。
更新了更多细节
【参考方案1】:
我认为你可以使用NSValue
的valueWithPointer:
和pointerValue
。但我建议你使用其他东西,比如 GCD 来异步运行一个块,而不是更改方法的签名以适应 performSelector
的限制:
dispatch_async(anotherQueue, ^
[self doSomething:&error];
);
如果你真的想走这条路,this question 也有更多关于如何解决这个问题的想法。
【讨论】:
谢谢,但我需要使用otherThread
变量,所以我需要使用 performSelector:onThread:WithObject【参考方案2】:
您需要重新考虑解决此问题的方法。你的方法:
- (void)doSomething:(NSError**)error
遵循传递NSError *
变量的地址 的标准Objective-C 模式,以便方法可以设置变量以返回错误。
如果您尝试异步调用此方法,无论是尝试使用 performSelector:onThread:withObject:waitUntilDone:
还是使用 GCD(正如 Felipe Cypriano 也建议的那样),您必须小心 - 您传递其地址的变量必须作为时间存在异步调用被执行,即使你已经解决了你必须弄清楚异步调用何时完成,这样你才能检查它是否设置了变量......
处理此类问题的常用方法是使用完成块,异步方法在完成时调用该完成块,传递任何结果 - 在您的情况下为 NSError *
。例如你可以写一个方法:
- (void) doSomethingAsyncAndThen:(void (^)(NSError *))completionBlock
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0),
^
NSError *error = nil;
[self doSomething:&error];
completionBlock(error);
);
然后这样称呼它:
[self doSomethingAsyncAndThen:^(NSError *error) NSLog(@"error: %@", error); ];
虽然你会想要做的不仅仅是NSLog
结果。
HTH
【讨论】:
以上是关于使用 NSValue 进行包装和解包的主要内容,如果未能解决你的问题,请参考以下文章