Its a common pattern to add an error output parameter when writing Objective-c methods.
As far as I know this is how you create a method that return an error if something is wrong:
- (void)doSomethingWithObj:(id)obj error:(NSError *__autoreleasing *)error {
BOOL success = NO;
// do somthing...
if (!success) {
*error = [NSError errorWithDomain:@"the.domain" code:0 userInfo:nil];
}
}
Now there are times when you just want that error parameter to reflect an error occurred in some other method you use inside your method, lets say:
- (void)fetchObjectInContext:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SomeObject"];
NSArray *results = [context executeFetchRequest:request error:nil];
}
So I thought ok, I'll just pass the error parameter to the inside method, like this:
- (void)fetchObjectInContext:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SomeObject"];
NSArray *results = [context executeFetchRequest:request error:error];
if (error) {
NSLog(@"error %@", error);
}
}
But this approach has two issues:
1. the if (error)
check returns YES
even if there is no error.
2. the log line generates this warning: Format specifies type 'id' but the argument has type 'NSError *__autoreleasing *'
So what am I doing wrong here?
There are a couple of things wrong. Firstly the NSError
object should not be used to test for errors, instead use the method's return value. Therefore your first example method should return BOOL
to indicate success:
- (BOOL)doSomethingWithObj:(id)obj error:(NSError *__autoreleasing *)error {
BOOL success = NO;
// do somthing...
if (!success) {
if (error) { // Check it's been passed, and if so create the error object.
*error = [NSError errorWithDomain:@"the.domain" code:0 userInfo:nil];
}
}
return success;
}
And test for results
being nil
, not error
being non- nil
:
- (void)fetchObjectInContext:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SomeObject"];
NSArray *results = [context executeFetchRequest:request error:error];
if (!results) {
if (error && *error)
NSLog(@"error %@", [(*error) localizedDescription]); // Here is your 2. I think.
else
NSLog(@"Unknown error");
}
}
Secondly the error
parameter is commonly optional (as seen in your code where you pass nil
, which should be NULL
actually). Therefore you need to test if it's been passed before dereferencing it (see code above).
However to answer your overall question, yes it's good to pass the error
parameter along to subordinate method calls and is commonly used.
I have no idea about your 2. until you update your code... standing by.
I think your 2. issue is because you need to use [error localizedDescription]
with NSLog()
.
You are passing address of error not actual error this means &error
So you need to derefrence the error pointer. NSError *__autoreleasing *
you are taking parameter as address of error
.We generally do this because objective c
can return only one value.But error need to be known from where we are calling the mehod so passing it as address of error will make change to error if there an error comes in calle function
. So if any error comes in below line
NSArray *results = [context executeFetchRequest:request error:error];
than it is automatically know to calle function
ie doSomethingWithObj
if (*error) {
NSLog(@"error %@", (*error).description);
}
Use
NSLog(@"error %@", (*error).description);
instead of
NSLog(@"error %@", (error).description);
you have to pass &error
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.