使用 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】:

我认为你可以使用NSValuevalueWithPointer: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 进行包装和解包的主要内容,如果未能解决你的问题,请参考以下文章

为 CAAnimation 目的将 Swift 结构转换/包装为 NSValue?

NSNumber 与NSValue

性能 - NSValue 中的结构与容器对象

OC系列高级-NSValue

NSNumber和NSValue

Object - C 值对象 NSNumber和NSValue