0
votes

In my project, I have a function like this:

- (void)doSomething:(NSError**)error {
...
}

I need to call this function on another thread by using function performSelector:onThread:withObject:waitUntilDone: , something like this:

[self performSelector:@selector(doSomething:) onThread:anotherThread withObject:??? waitUntilDone:NO];

But the function parameter is of type NSError**. I am considering refactor the parameter type of function -(void)doSomething: from NSError** to NSValue* and pass NSValue* type as argument.

Which means, I need to wrap the &error (which is of type NSError **) into a NSValue and pass it as argument, and unwrap it later. How to wrap & unwrap NSError** with NSValue class?

2
Why do you need to wrap the NSError in an NSValue? - rmaddy
I want to wrap the NSError** and pass the wrapped NSValue as the argment , then call performSelector:withObject , - Leem.fin
1) Why do you need to wrap the NSError with NSValue just to pass it to performSelector:withObject:? There's no need to wrap it. 2) Why do you need to use performSelector:withObject:? There's always a better way than that. I suggest updating your question with more specific details about what you really need to accomplish so people can offer better advice. - rmaddy
I am going to update my question with more detail, thanks. - Leem.fin
updated with more detail - Leem.fin

2 Answers

0
votes

I think you can use NSValue's valueWithPointer: and pointerValue. But I would suggest you use something else, like GCD to run a block asynchronously instead of changing your method's signature to fit the limitations of performSelector:

dispatch_async(anotherQueue, ^{
    [self doSomething:&error];
});

Also this question has a few more ideas on how to approach this problem if you really want to go down that path.

0
votes

You need to rethink your approach to this problem. Your method:

- (void)doSomething:(NSError**)error

follows the standard Objective-C pattern of passing the address of an NSError * variable so that the method can set the variable to return the error.

If you try to call this method asynchronously, whether with performSelector:onThread:withObject:waitUntilDone: as you are attempting or using GCD (as Felipe Cypriano has also suggested), you have to be careful - the variable whose address you pass must exist as the time the async call is executed, and even after you've addressed that you have to figure out when the async call has finished so you can check if it has set the variable...

A common way to deal with issues like this is to use a completion block which the async method calls when it is finished, passing on any results - an NSError * in your case. For example you could write a method:

- (void) doSomethingAsyncAndThen:(void (^)(NSError *))completionBlock
{
   dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0),
                  ^{
                     NSError *error = nil;
                     [self doSomething:&error];
                     completionBlock(error);
                  });
}

and call it like:

[self doSomethingAsyncAndThen:^(NSError *error) { NSLog(@"error: %@", error); }];

though you will want to do something other than just NSLog the result.

HTH