why is "error:&error" used here (objective-c) - iphone

why is "error:&error" used here (objective-c)
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
wouldn't an object in objective-c be effectively pass-by-reference anyway?

The argument type for error: is NSError** (i.e. a pointer to a pointer to an object). This permits the moc object to allocate and initialize a new NSError object as required. It is a common pattern, especially in Cocoa.
The NSError documentation gives some indication of the motivation for this approach:
Applications may choose to create subclasses of NSError to provide better localized error strings by overriding localizedDescription.
Passing in an NSError** argument allows that method to return any subclass of NSError that makes sense. If you passed in NSError*, you would have to supply an existing NSError object, and there would be no way for the method to return a different object from the one you passed in.
To be clear, the method could look something like this:
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError**)error {
...
if ((error != NULL) && (some_error_condition)) {
*error = [[[SomeNSErrorSubclass alloc] init...] autorelease];
return nil;
}
}
Note that this also allows the calling code to ignore errors by simply passing in NULL for the error: parameter, as follows:
NSArray *array = [moc executeFetchRequest:request error:NULL];
Update: (in response to questions):
There are two reasons why the argument type has to be NSError** instead of NSError*: 1. variable scoping rules, and 2. NSError instances are imutable.
Reason #1: variable scoping rules
Let's assume that the function declaration were to look like this:
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error;
And we were to call the function like this:
NSError * error = nil;
[someArray executeFetchRequest:someRequest error:error];
if (error != nil) { /* handle error */ }
When you pass in a variable this way, the function body will not be able to modify the value of that variable (i.e. the function body will not be able to create a new variable to replace the existing one). For example, the following variable assignments will exist only in the local scope of the function. The calling code will still see error == nil.
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error {
...
error = [[[NSError alloc] init...] autorelease]; // local only
error = [[[SomeNSErrorSubclass alloc] init...] autorelease]; // local only
}
Reason #2: instances of NSError are immutable
Let's keep the same function declaration, but call the function like this:
NSError * error = [[[NSError alloc] init...] autorelease];
[someArray executeFetchRequest:someRequest error:error];
if (error != nil) { /* handle error */ }
First of all, the variable scoping rules guarantee that error can not be nil, so the if (error != nil) { ... condition will always be true, but even if you wanted to check for specific error information inside the if block, you would be out of luck because instances of NSError are immutable. This means that once they are created, you cannot modify their properties, so the function would not be able to change the domain or userInfo of that NSError instance that you created in the calling code.
- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error {
...
error.domain = ... // not allowed!
error.userInfo = ... // not allowed!
}

It's effectively another return value. The error is not dominant by convention in Cocoa when there is a return value for the operation. When an error is encountered, it may be returned to you by this out parameter.
In the case of NSError, it works this way because NSError is not a mutable type - its fields are set at initialization and never mutated. Therefore, you cannot pass an NSError as usual and set the error code.

Related

iOS parsing JSON from static library returning null

I'm trying to test out using static libraries, and am calling this method (which is in the static library)
-(NSMutableDictionary *)parseJSONfromURL:(NSURL *)url{
__strong NSMutableDictionary *json;
[self.delegate isParsing:(url != nil)];
if (url == nil) {
[NSException raise:NSArgumentDomain format:#"The passed url argument cannot be nil"];
}
NSError *err;
json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL:url] options:NSJSONReadingMutableLeaves error:&err];
if (err) {
[json setObject:err forKey:#"error"];
}
while (json == nil) {
NSLog(#"waiting...");
}
[self.delegate isParsing:NO];
[self.delegate didFinishParsing:(json != nil)];
return json;
}
I would expect the while loop to be infinite since json is returning null, but the delegate method didFinishParsing gets sent, meaning it isn't null.
like this (ACParser is a class in the library)
ACParser *p = [[ACParser alloc] initWithDelegate:self];
dictionary = [p parseJSONfromURL:[NSURL URLWithString:#"http://www.a-cstudios.com/text.json"]];
dictionary is declared like this
__strong NSMutableDictionary *dictionary;
the JSON at that URL is very simple
{
"text" : "testing"
}
however, every time this is called, in the delegate method didFinishParsing:, logging dictionary returns (null). What am I doing wrong here? Is it because I'm calling it from a static library?
Try adding this:
NSLog(#"%#", [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]] options:NSJSONReadingAllowFragments error:nil]);
in there and see if it prints out your expected JSON. If it doesnt, your URL is wrong. If it does, then your data isnt being retained. Try instantiating your json variable like this:
NSMutableDictionary *json = [NSMutableDictionary dictionaryWithDictionary:[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL:url] options:NSJSONReadingMutableLeaves error:&err]];
"json" within "parseJSONfromURL" is autoreleased / out of scope as soon as that method returns so it never has a chance to get assigned to your strong "dictionary" property.
That's why you are seeing NULL.
Try setting the property within your parseJSONfromURL method and see if that works, or create a non-autoreleased dictionary and return that.

UIManagedDocument - Validating Core Data Entity

I have an app that uses Core Data and it gets its ManagedObjectContext by using UIManagedObject. From reading, I see that I am not suppose to save the context directly - rather I should depend on autosaving of UIManagedObject or use saveToURL:... My issue is that I want to validate the data being stored in my entity. I have constraints on the entity that specify that the min length for the string properties is 1. However, I can create a new object, assign its properties empty strings, and save the file. In the completion handler of saveToURL:... it always has a true success value. I then created my own validator for the name property of my entity. I used sample code from the Core Data Programming Guide -
-(BOOL)validateName:(id *)ioValue error:(__autoreleasing NSError **)outError
{
if (*ioValue == nil)
{
if (outError != NULL)
{
NSString *errorStr = #"nil error";
NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorStr
forKey:NSLocalizedDescriptionKey];
NSError __autoreleasing *error = [[NSError alloc] initWithDomain:#"domain"
code:1
userInfo:userInfoDict];
*outError = error;
}
return NO;
}
else if( [*ioValue length] == 0 )
{
if (outError != NULL) {
NSString *errorStr = #"length error";
NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorStr
forKey:NSLocalizedDescriptionKey];
NSError __autoreleasing *error = [[NSError alloc] initWithDomain:#"domain"
code:1
userInfo:userInfoDict];
*outError = error;
}
return NO;
}
else
{
return YES;
}
}
When this runs, I see that the ioValue has 0 length and that it returns NO, but then my completion handler is never called. Any help would be great.
Is there something I am missing for how to handle saving errors with UIManagedDocument - particularly how to notify the calling code that an error happened while saving its information.
As a rule, you should only call saveToURL to create a brand new file. Let auto-save do the rest.
Also, I'm not sure I follow your question. If you are asking how to know about save failures, the best you can do is register for notifications (since all saves happen on a background thread).
Directly from the documentation:
A UIDocument object has a specific state at any moment in its life cycle. You can check the current state by querying the documentState property. And you can be notified of changes in the state of a document by observing the UIDocumentStateChangedNotification notification.
I guess I need to implement handleError:(NSError *)error userInteractionPermitted:(BOOL)userInteractionPermitted in a subclass of the UIManagedDocument. I found that via this article - http://blog.stevex.net/2011/12/uimanageddocument-autosave-troubleshooting/

How can I use NSError in my iPhone App?

I am working on catching errors in my app, and I am looking into using NSError. I am slightly confused about how to use it, and how to populate it.
Could someone provide an example on how I populate then use NSError?
Well, what I usually do is have my methods that could error-out at runtime take a reference to a NSError pointer. If something does indeed go wrong in that method, I can populate the NSError reference with error data and return nil from the method.
Example:
- (id) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
We can then use the method like this. Don't even bother to inspect the error object unless the method returns nil:
// initialize NSError object
NSError* error = nil;
// try to feed the world
id yayOrNay = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!yayOrNay) {
// inspect error
NSLog(#"%#", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
We were able to access the error's localizedDescription because we set a value for NSLocalizedDescriptionKey.
The best place for more information is Apple's documentation. It really is good.
There is also a nice, simple tutorial on Cocoa Is My Girlfriend.
I would like to add some more suggestions based on my most recent implementation. I've looked at some code from Apple and I think my code behaves in much the same way.
The posts above already explain how to create NSError objects and return them, so I won't bother with that part. I'll just try to suggest a good way to integrate errors (codes, messages) in your own app.
I recommend creating 1 header that will be an overview of all the errors of your domain (i.e. app, library, etc..). My current header looks like this:
FSError.h
FOUNDATION_EXPORT NSString *const FSMyAppErrorDomain;
enum {
FSUserNotLoggedInError = 1000,
FSUserLogoutFailedError,
FSProfileParsingFailedError,
FSProfileBadLoginError,
FSFNIDParsingFailedError,
};
FSError.m
#import "FSError.h"
NSString *const FSMyAppErrorDomain = #"com.felis.myapp";
Now when using the above values for errors, Apple will create some basic standard error message for your app. An error could be created like the following:
+ (FSProfileInfo *)profileInfoWithData:(NSData *)data error:(NSError **)error
{
FSProfileInfo *profileInfo = [[FSProfileInfo alloc] init];
if (profileInfo)
{
/* ... lots of parsing code here ... */
if (profileInfo.username == nil)
{
*error = [NSError errorWithDomain:FSMyAppErrorDomain code:FSProfileParsingFailedError userInfo:nil];
return nil;
}
}
return profileInfo;
}
The standard Apple-generated error message (error.localizedDescription) for the above code will look like the following:
Error Domain=com.felis.myapp Code=1002 "The operation couldn’t be completed. (com.felis.myapp error 1002.)"
The above is already quite helpful for a developer, since the message displays the domain where the error occured and the corresponding error code. End users will have no clue what error code 1002 means though, so now we need to implement some nice messages for each code.
For the error messages we have to keep localisation in mind (even if we don't implement localized messages right away). I've used the following approach in my current project:
1) create a strings file that will contain the errors. Strings files are easily localizable. The file could look like the following:
FSError.strings
"1000" = "User not logged in.";
"1001" = "Logout failed.";
"1002" = "Parser failed.";
"1003" = "Incorrect username or password.";
"1004" = "Failed to parse FNID."
2) Add macros to convert integer codes to localized error messages. I've used 2 macros in my Constants+Macros.h file. I always include this file in the prefix header (MyApp-Prefix.pch) for convenience.
Constants+Macros.h
// error handling ...
#define FS_ERROR_KEY(code) [NSString stringWithFormat:#"%d", code]
#define FS_ERROR_LOCALIZED_DESCRIPTION(code) NSLocalizedStringFromTable(FS_ERROR_KEY(code), #"FSError", nil)
3) Now it's easy to show a user friendly error message based on an error code. An example:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:FS_ERROR_LOCALIZED_DESCRIPTION(error.code)
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
Great answer Alex. One potential issue is the NULL dereference. Apple's reference on Creating and Returning NSError objects
...
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
...
Objective-C
NSError *err = [NSError errorWithDomain:#"some_domain"
code:100
userInfo:#{
NSLocalizedDescriptionKey:#"Something went wrong"
}];
Swift 3
let error = NSError(domain: "some_domain",
code: 100,
userInfo: [NSLocalizedDescriptionKey: "Something went wrong"])
Please refer following tutorial
i hope it will helpful for you but prior you have to read documentation of NSError
This is very interesting link i found recently ErrorHandling
I'll try summarize the great answer by Alex and the jlmendezbonini's point, adding a modification that will make everything ARC compatible (so far it's not since ARC will complain since you should return id, which means "any object", but BOOL is not an object type).
- (BOOL) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return NO;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
Now instead of checking for the return value of our method call, we check whether error is still nil. If it's not we have a problem.
// initialize NSError object
NSError* error = nil;
// try to feed the world
BOOL success = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!success) {
// inspect error
NSLog(#"%#", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
Another design pattern that I have seen involves using blocks, which is especially useful when a method is being run asynchronously.
Say we have the following error codes defined:
typedef NS_ENUM(NSInteger, MyErrorCodes) {
MyErrorCodesEmptyString = 500,
MyErrorCodesInvalidURL,
MyErrorCodesUnableToReachHost,
};
You would define your method that can raise an error like so:
- (void)getContentsOfURL:(NSString *)path success:(void(^)(NSString *html))success failure:(void(^)(NSError *error))failure {
if (path.length == 0) {
if (failure) {
failure([NSError errorWithDomain:#"com.example" code:MyErrorCodesEmptyString userInfo:nil]);
}
return;
}
NSString *htmlContents = #"";
// Exercise for the reader: get the contents at that URL or raise another error.
if (success) {
success(htmlContents);
}
}
And then when you call it, you don't need to worry about declaring the NSError object (code completion will do it for you), or checking the returning value. You can just supply two blocks: one that will get called when there is an exception, and one that gets called when it succeeds:
[self getContentsOfURL:#"http://google.com" success:^(NSString *html) {
NSLog(#"Contents: %#", html);
} failure:^(NSError *error) {
NSLog(#"Failed to get contents: %#", error);
if (error.code == MyErrorCodesEmptyString) { // make sure to check the domain too
NSLog(#"You must provide a non-empty string");
}
}];
extension NSError {
static func defaultError() -> NSError {
return NSError(domain: "com.app.error.domain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Something went wrong."])
}
}
which I can use NSError.defaultError() whenever I don't have valid error object.
let error = NSError.defaultError()
print(error.localizedDescription) //Something went wrong.
Well it's a little bit out of question scope but in case you don't have an option for NSError you can always display the Low level error:
NSLog(#"Error = %# ",[NSString stringWithUTF8String:strerror(errno)]);

Is there a convenient way to have two different "nil-like" possible return values from a method?

The method in question (actually a polymorphically-implemented family of recursive search methods) returns a pointer to a certain type of object. I had been returning nil in cases of failure. Now I want to have two different kinds of failure. What is the easiest way to implement that?
The best way to do this is to keep the return nil;, but take an error pointer as one of the function arguments. This way, you can send in an error, and check it for a value afterward to see what happened. Your function will still run, but you'll have some control over what gets returned.
As an example, here's some code I use for saving a managedObjectContext:
NSManagedObjectContext *moc = [self managedObjectContext];
NSError *error;
if (![moc save:&error]) {
NSString *description = [error localizeDescription];
NSInteger code = [error code];
}
I've tweaked the inside of the block to show a couple of the ways to pull info out of an error. For you, it'd probably be best to use simple error codes to distinguish between different nil values.
Here's a code example (though probably not the best way, as you'll have to duplicate code to interpret the error messages):
-(id) functionCall:(NSError *)error {
...
if (nilCondition) {
if (firstNilCondition) {
[error setCode:1];
}
if (firstNilCondition) {
[error setCode:2];
}
return nil;
}
}

How to pass the equivalent of nil for an (NSError **)

I have a method that takes an (NSError **) but I don't want to pass it one. When I pass it "nil" or "NULL" I end up with "EXC_BAD_ACCESS".
The offending line is "*error = nil;"
How do I pass it the equivalent of "nil" without crashing?
The offending line should be:
if (error != nil) { *error = nil; }
You're trying to dereference a null pointer, which is a surefire way to crash.
The alternative would be to pass it an NSError**, but then just ignore it afterwards.
When you are implementing such method, you can use the following trick so that you won’t have to check for nil all the time:
- (void) doSomethingMaybeCausing: (NSError**) error
{
NSError *dummyError = nil;
if (error == NULL)
error = &dummyError;
// ...later:
*error = [NSError …];
}
Now the caller can pass NULL if he’s not interested in the errors.
You have to pass it a valid pointer to something which it can modify. The standard way to do this would be:
NSError *error = nil;
[object callMethod:whatever error:&error];