Sunday, January 31, 2010

 

Back in the Android saddle

So now that versions 2.0 of my iPhone app are up and running on the App Store, I've finally started writing an Android version. You may recall that this blog was supposed to be primarily about Android development from the get-go. We apologize for the eight-month sidetrack.

Anyway, It's been going quite well. Both the Android and iPhone SDK have their pros and cons. I like XCode better than Eclipse, and I generally (though not always) prefer Core Data to direct DB queries; on the other hand, string processing is far easier in Java, Android's multithreading is easier to work with, I vastly prefer single .java files vs twinned .h/.c files, and I love not having to worry about manual memory management.

The Android version is now mostly functionally complete. Things I have (sometimes re) learned which may be of interest:



More to come when I release v1.0, which should happen in the next ten days.

Labels: , , , , , , , ,


Monday, January 18, 2010

 

Using Core Data in a multithreaded environment.

You have to do a lot of iPhone stuff in background threads, to maintain a snappily responsive user interface. But if you're using Core Data, well - to quote the docs:

Managed objects are not thread safe [...] Core Data does not present a situation where reads are "safe" but changes are "dangerous"—every operation is "dangerous" because every operation can trigger faulting.

Sound intimidating? No worries: it's a piece of cake. Just wrap the code where you get your ManagedObjectContext in a method something like this:


@implementation Util

+(NSManagedObjectContext*)getManagedObjectContext {
UIApplication *app = [UIApplication sharedApplication];
MyAppDelegate *appDelegate = app.delegate;
if ([NSThread isMainThread])
return [appDelegate managedObjectContext];
else
return [appDelegate getMOCFor:[NSThread currentThread]];
}


and add the following method to your application delegate:
(where "threadMOCs", obviously, is a properly defined and synthesized ivar.)


- (NSManagedObjectContext*) getMOCFor:(NSThread*) thread {
if (!threadMOCs)
self.threadMOCs=[NSMutableDictionary dictionaryWithCapacity:16];

NSNumber *threadHash = [NSNumber numberWithInt:[thread hash]];
if ([threadMOCs objectForKey:threadHash]==nil) {
NSManagedObjectContext *newMOC = [[NSManagedObjectContext alloc] init];
NSError *error=nil;
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"myDBName.sqlite"]];
NSManagedObjectModel *model = [self managedObjectModel];
NSPersistentStoreCoordinator* threadPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: model];
if (![threadPSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error])
{ //handle error here }

[newMOC setPersistentStoreCoordinator: threadPSC];
[threadMOCs setObject:newMOC forKey:threadHash];
}
return [threadMOCs objectForKey:threadHash];
}


Et voila! A new object context and persistent store coordinare for every thread, which gives you full concurrent access to your data. (Though you probably still have to be careful about passing managed objects across threads...)

Labels: , , , , , , , , , , ,


This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]