NSError objects with NSFetchedResultsControllers - objective-c

This is a simple one: I'm currently creating a new NSError object every time I perform a fetch on my NSFetchedResultsController. This occurs across a number of methods, so there are currently nine of them in my main view controller. Should I create one NSError as a property and use that, or is it more conventionally accepted to create a new one each time you use it?
I'm guessing the advantage of creating multiples is that if more than one error occurs, you can get at both independently, but if this is unlikely to occur, is it acceptable to use a shared one for all performFetch calls? I'm learning a lot of programming convention and technique, so apologies if this is something of a non-issue, I'd just like to get some feedback on the more typical approach to using NSError objects in a variety of places.

You aren't really creating NSError objects. You are declaring references to NSError objects and then passing the reference to a method which may point the reference at an NSError object it creates.
NSError *err; // just a reference, no object created
// this creates an object, but you don't do this
err = [NSError errorWithDomain:#"foo" code:0 userInfo:nil];
// You do this....
BOOL success = [fetchedResultsController performFetch:&err];
The distinction is, you aren't really creating a bunch of objects which require overhead. So if you re-use the same variable for all of them or you create a new variable for each one, it isn't going to impact performance.
So to answer the question... either use 1 variable or many as you see fit. Some code might fail on any error and refuse to continue so 1 error is fine. Other code might want to try and keep going so you keep all the errors and spew them out at the end. It's a matter of what fits best with the specific coding you are working on at the time.

Just declaring one on the stack and passing it's address is virtually free. So you could do:
NSError *errorA;
// do something, passing &errorA
if (!errorA) {
// do something passing &errorA again
}
Or, at hardly any additional cost (just another pointer on the stack)
NSError *errorA, *errorB;
// do something, passing &errorA
// do something, passing &errorB, that doesn't care whether the last thing succeeded
if (!errorA && !errorB) {
// do something else
}
There's no need to worry about allocations of NSError here. It should be more about the logic of dependency between the first action success and doing a second action.

Related

Do I need to save NSManagedObjectContext of Main thread concurrency inside a perform block of a private context?

I need an answer from a reliable source, about saving NSManagedObjectContexts. Imagine I have a long writing task in in a global queue, I have two contexts as singleton reference (1 of NSMainQueueConcurrency, the other private)...
I have a large task of writing into database and my code look like this:
[privateMOC performBlock^:{
// Here goes a large writing task
................................
// And here goes saving
[privateMOC save:nil];
[mainMOC performBlock^:{
[mainMOC save:nil];
}]
}];
My question is: is it necessary to call save to main context inside a performBlock^ of a privateContext, and another note is that there is no parent-child context structure, but there are two NSPersistentStoreCoordinators.
Thx in advance :)
As usual, it depends what you want and need. :)
In general there's no requirement for one context's save call to be nested in a block passed to another context. You might want to do that in some cases, though. In your sample code, you guarantee that [mainMOC save:nil] won't get called until after [privateMOC save:nil] finishes. Is that important? There's not enough detail in your question to say if it matters in your case, so you'll have to consider that for yourself.
While I'm at it though, you really need to check the results of your save calls. The method returns a boolean to tell you if saving succeeded, and it can return an NSError by reference to tell you why it failed. Your code doesn't check the result and doesn't allow for an NSError-- meaning that if saving ever fails, you've ensured that you won't know that it failed or why. Use the information that the framework is trying to give you.

NSUUID as Unique ID as replacement to NSManagedObjectID

I've run into some problems using NSManagedObjectID and it changing depending on it's saved state.
As such I've decided to use my own UniqeIDs as recommended in the docs and by others. I've seen many examples here on Stack Overflow and on other places where it's a simple matter of storing a NSUUID string value in a core data field.
However, this isn't quite enough for what I want. One of the useful things about NSManagedObjectID is that it is always the same object and can be compared by pointer, so you can post notifications around using the NSManagedObjectID as their object, anything that requires information about the entity can register for notification based on the NSManagedObjectID without writing additional code to check if the notification is indeed the one we're looking for.
However, would that be still be true if an NSString is passed around instead of the NSManagedObjectID? We're always supposed to use isEqualTo for NSString comparison, even if it might be the same object. I feel like using an NSString as an object for a notification is a bit of a no no.
In my case, it's pretty much guaranteed be the same object, unless objective c messes around with NSString behind the scenes. the uniqueID is generated once on insertion of an object, and would be passed around unaltered as required, and I simply want to replace all calls where I use NSManagedObjectID with something I can drop in with minimal changes.
A CFUUID would seem ideal, as they can be guaranteed to share pointer values, however CFUuidRef is not an objective-c object, so can't be used for notifications among other things. An NSUUID seems next to best apart from the caveat in the documentation that says they aren't guaranteed to be the same object. But if my NSUUID is created, stored and retrieved on a single object, could we guarantee the passed around NSUUID to be the same object throughout the application? If so, couldn't we say the same thing about an NSString? Even if we could, I'd be happier just going with NSUUID.
I can't pass around the Entity directly, as I'm using the notification to post information between separate threads. Even though I only ever modify the entities on the main thread, and entities can be accessed for readonly across threads, I've had many problems in the past, that all went away once I implemented a system based on using just the NSManagedObjectID.
Maybe I got you wrong, but why not passing around instances of NSUUID (if you do not want to use instances of NSString) and comparing them on equality?
#interface NSUUID(Equality)
- (BOOL)isEqualToUUID:(NSUUID*)other;
#end
#implementation NSUUID(Equality)
- (BOOL)isEqualToUUID:(NSUUID*)other
{
return [self.UUIDString isEqualToString:other.UUIDString];
}
// Only for completness
- (BOOL)isEqual:(id)other
{
if( [other isKindOfClass:[NSUUID class]] )
{
return [self isEqualToUUID:other];
}
return NO;
}
#end
BTW: The same reasons that make you feel badly using instances of NSString as notification object does not apply to instances of NSUUID?
BTW 2: Handling CF-objects in ARC code is not that difficult.

Objective-C should I be using NSError and why presentError function not working

I am creating an application on iPhone where I am taking code written and Java and translating into Objective-C, as the app must work similarly in both Android and iPhone. Now problems of course are there are certain areas where the languages differ quite a bit, and can be difficult to implement just right.
One of the areas where it is of course different is you cannot create NSMutableArrays or NSMutableDictionaries which only accepts objects of a certain type. So when I am creating the getters and setters for these objects, I have been doing this, example below:
-(void)setPerson:(NSMutableArray *)personList_p
{
BOOL bAllowed = YES;
for(int i = 0; i < [personList_p count]; i++)
{
if(![[personList_p objectAtIndex:i] isKindOfClass:[Person class]])
{
bAllowed = NO;
break;
}
else
{
bAllowed = YES;
}
}
if(bAllowed)
{
personList_i = personList_p;
}
else
{
//Raise error here
}
}
Now originally I was using NSRaise Exception, but after doing reading up on it, it recommends against this as exception handling is resource intensive and should not be used for this type of situation. So NSError I read was a good solution, so I was reading up on this guide
http://www.cimgf.com/2008/04/04/cocoa-tutorial-using-nserror-to-great-effect/
My question is two fold, if I decide to use NSError should, is it best practice to declare the NSError object in the method, i.e like this
-(void)setPerson:(NSMutableArray *)personList_p : (NSError **)error
Or is it okay just to declare the error within the else statement above, like this
NSError *error = nil;
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:#"Invalid object passed into Array, object must be of type Person." forKey:NSLocalizedDescriptionKey];
error = [NSError errorWithDomain:#"Invalid Object" code:200 userInfo:details];
NSLog(#"%#", [error localizedDescription]);
Secondly, in the guide I linked above, in the conclusion the author says
In this example, I am checking to see if the error is still nil after
my message call. If it is no longer nil I know that an error occurred
and that I need to display it to the user. Apple provides a built in
method to do this with a call to presentError: on the NSApplication
instance
and he uses this line of code here
[NSApp presentError:error];
This does not work for me, I do not get an autocomplete option with this code, just says use of undeclared identifier. Am I missing something obvious here?
Also, just to be sure, is the method I am using, the best method to go about ensuring the user sends in an array with the correct object types? Or is there another method which could be used which would achieve the same thing but in a more efficient manner.
Thanks in advance!!
EDIT:
Additional question, would it be such a bad idea to use NSException, as the problem with NSError is the app carries on, I am considering having it so if they do pass in an array with an invalid object, that it does just cause the application to crash and raise an exception. Is there any major reason why I shouldn't do this??
Now originally I was using NSRaise Exception, but after doing reading
up on it, it recommends against this as exception handling is resource
intensive and should not be used for this type of situation. So
NSError I read was a good solution, so I was reading up on this guide
He does not actually say that raising exceptions is inherently bad or resource intensive, he argues that #try/catch is the wrong way to go about things. That, and Cocoa applications (even more so I'm Cocoa-Touch) should refrain from throwing exceptions whenever possible. Exceptions indicate undefined behavior, not simple errors.
Secondly, in the guide I linked above, in the conclusion the author...
uses this line of code here
[NSApp presentError:error];
This does not work for me, I do not get an autocomplete option with
this code, just says use of undeclared identifier. Am I missing
something obvious here?
That is because NSApp is a concept only accessible to Cocoa(or Mac) applications. It represents a pointer to "the application itself", and has some pretty neat functions associated with it. Of course, iOS has no parallel concept, so errors are traditionally presented in a UIAlertView.
Additional question, would it be such a bad idea to use NSException,
as the problem with NSError is the app carries on, I am considering
having it so if they do pass in an array with an invalid object, that
it does just cause the application to crash and raise an exception. Is
there any major reason why I shouldn't do this??
It is generally a bad idea to use NSException for anything other than extremely serious logic (such as when a call is made to an index out of the bounds of an NSArray, or when a UITableView's data source happens to be out of sync with what the table demands). If you absolutely must stop program execution, it's much cleaner to use NSAssert() to throw conditional exceptions. And even then, setters are not the place to be throwing exceptions. It would be far easier to simply return nil when the condition fails, then have the caller check for such an outcome and handle it appropriately.

how to use pointers in Objective c

I have seen some iOS developpers using code like this :
- (void)setupWebView:(UIWebView**)aWebView {
UIWebView *webview = [[UIWebView alloc] init];
.....
if (*aWebView) {
[*aWebView release];
}
*aWebView = webview;
}
Do you know what'is this mean and why we use this ? thanks
- (void)setupWebView:(UIWebView**)aWebView {
That is awful. You should never have a method that returns void, but sets an argument by reference unless:
• there are multiple arguments set
• the method is prefixed with get
That method should simply return the created instance directly. And this just makes it worse -- is flat out wrong:
if (*aWebView) {
[*aWebView release];
}
*aWebView = webview;
it breaks encapsulation; what if the caller passed a reference to an iVar slot. Now you have the callee managing the callers memory which is both horrible practice and quite likely crashy (in the face of concurrency, for example).
it'll crash if aWebView is NULL; crash on the assignment, specifically.
if aWebView refers to an iVar slot, it bypasses any possible property use (a different way of breaking encapsulation).
It is a method to initialize a pointer. The first line allocates the object. The if statement makes sure that the passed in pointer-to-a-pointer is not already allocated, if it is it releases it. then it sets the referenced pointer to the newly allocated object.
The answer by #bbum is probably correct, but leaves out one aspect to the question that I see there. There are many examples in Foundation which use pointer-pointers in the method signature, so you can say it is a common pattern. And those are probably not a beginners mistake.
Most of these examples are similar in that they fall into one category: the API tries to avoid the usages of exceptions, and instead use NSError for failures. But because the return value is used for a BOOL that signals success, an NSError pointer-pointer is used as output parameter. Only in the probably rare error case an NSError object is created, which can contain error code and error descriptions, and localized descriptions and possibly even more information (like an array of multiple errors in the case of bulk operations). So the main success case is efficient, and the error case has some power to communicate what went wrong, without resorting to exceptions. That is the justification behind these signatures as I understand it.
You can find examples of this usage in both NSFileManager and NSManagedObjectContext.
One might be tempted to use pointer-pointers in other cases where you want multiple return values and an array does not make sense (e.g. because the values are not of same type), but as #bbum said, it is likely better to look hard for alternatives.

objective c "Did you forget to nest alloc and init?"

I am just starting climbing the Objective C learning curve (using Nerd Ranch iOS programming book).
Based on what I have know from other languages about "nesting" multiple executions within one line I assumed that I can alter:
NSString* descriptionString = [[NSString alloc] initWithFormat:#"%#", possesionName]
with a two line version:
NSString* descriptionString = [NSString alloc];
[descriptionString initWithFormat:#"%#", possesionName]
but it seems that the second attempt raises an exception
2012-01-22 18:25:09.753 RandomPossessions[4183:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -length only defined for abstract class. Define -[NSPlaceholderString length]!'
Could someone help me understand what exactly I am doing wrong here? Thanks a lot in advance.
PS. If this is a way Objective C messages work and you have to make alloc and init in one line just let me know - I assumed this is just a set of functions that either can be executed two in one go or one after another.
An important difference between both versions (they are not exactly equal) is that in the first version you use the result of initWithFormat for the variable descriptionString, while you use the result of alloc in the second. If you change your code to
NSString* descriptionString = [NSString alloc];
descriptionString = [descriptionString initWithFormat:#"%#", possesionName]
all should be well again. It is specified that an object returned by alloc shall not be seen as initialized and functional until some init Method has been called and init might return something else.
The alloc method will allocate memory for a new object. But the init method might throw away that memory and return a completely different object. Or it might return nil. This is why you must always do self = [super init] when you override an init method.
NSString is one class that does this kind of thing all the time.
I'm not exactly sure why the exception is happening, but I believe it could be ARC injecting code in between your two lines of code or something similar. Whatever it is, something is trying to act on the allocated object that has never been initialised, and this is a huge problem that can lead to all kinds of issues. Consider yourself lucky it threw an exception, sometimes it wont.
The NSString class might not actually be a real class. It may contain almost no methods and almost no variables. All it has is a bunch of factory methods to create "real" string objects of some other class, and this is done using methods like initWithFormat:. So, by long standing convention alloc/init must always be done in a single statement and there are a handful of places where, usually for performance reasons, something will rely on this convention being used.
Basically, objective-c is a language where you don't need to know exactly what is going on inside an object. You just need to know what messages can be sent to an object, and how it will respond. Anything else is undefined behaviour and even if you learn how it works, it is subject to change without notice. Sometimes the behaviour will change depending on circumstances that are completely illogical, for example you might expect the "copy" method to give you a copy of the object you send it to, and while this is the default behaviour, there are many cases where it will actually just return the same object with slightly different memory management flags. This is because the internal logic of the class knows that returning the same object is much faster and effectively identical to returning an actual copy.
My understanding is copy sent to NSString may return a new object, or it may return itself. It depends on which NSString subclass is actually being used, and there isn't even any documentation for what subclasses exist, let alone how they're implemented. All you need to know, is that copy will return a pointer to an object that is perfectly safe to treat as if it was a copy even though it might not be.
In a "proper" object oriented language like Objective-C, objects are "black boxes" which can intelligently change their internal behaviour at any time for any reason, but their external behaviour always remains the same.
With regard to avoiding nesting... The coding style for Objective-C often does require extensive nesting, or else you'll be writing 10 lines of code when only 1 is really needed. The square brace syntax is particularly suited to nesting without making your code messy.
As a rule of thumb, I turn on Xcode's "Page Guide at column" feature, and set it to 120 characters. If the line of code exceeds that width then I'll think about breaking it into multiple lines. But often it's cleaner to have a really long line than three short lines.
Be pragmatic about it. :)
From Apple's library reference, initWithFormat:
Returns an NSString object initialized by converting given data into Unicode characters using a given encoding.
So you can use these two lines of code:
NSString* descriptionString = [NSString alloc];
descriptionString = [descriptionString initWithFormat:#"%#", possesionName];
For more info please go to:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/initWithFormat: