Dealing with Google App Engine development datastore.
I’ve been using GAE for a couple of years now, and I’ve become pretty much accustomed to its foibles, except for one: it occasionally wipes out my development datastore for no apparent reason. It always happens when I have to restart the dev. server application, and it usually happens when I switch between two of my applications. But whatever the cause, it can be really annoying. So I’ve found a workaround of sorts.
Digging thorough the development server documentation, I found two options that are making my life much easier:
- –use_sqlite
- Use sqlite for the local datastore.
- –datastore_path=[path to datastore file]
- Keep the datastore in the file specified.
By doing these two things, you can now see where GAE is keeping your datastore and you can make intermediate backups and restore them at will. You can also view your datastore using the command line sqlite client. Just add these two parameters to the Extra Flags box in your app’s info in the App Engine Launcher (or to the command line) and you’re good to go. Enjoy!
iPhone Core Data/undo gotcha of the day.
In general, I like the NSUndoManager functionality in iOS, but sometimes the secret handshakes you need to know can really get me down. For example, I needed to disable undo/redo when setting a particular property of a model entity. Reading the documentation, this seemed pretty straightforward:
[[theApp.managedObjectContext undoManager] disableUndoRegistration]; detailItem.fieldImageFile = relativePath; [[theApp.managedObjectContext undoManager] enableUndoRegistration];
Seemed very clear, but it didn’t work! So, after much poking around on the Internet, I found a posting that alluded to the fact that changes to undo don’t occur until the run loop executes. So, to get the desired effect, I ended up with the following code:
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:[NSDate date]]; [[theApp.managedObjectContext undoManager] disableUndoRegistration]; detailItem.fieldImageFile = relativePath; [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:[NSDate date]]; [[theApp.managedObjectContext undoManager] enableUndoRegistration];
Yet another head-scratching API decision from Apple.
Key-value Observer (KVO) on the iPhone.
Here’s one for the you-learn-something-new-every-day file. Objective C supports a key-value-observer model that lets you monitor changes on an object’s property values. Unfortunately, I found this out the hard way while working on a MKMapKit project.
What I wanted to do seemed simple: have a map view with a bunch of moving objects on it. Each object pulls its current position from an XML document on the web. I already had my XML-wrapper object written when I wanted to display it on the map, so I simply implemented the MKAnnotation protocol. All of my objects appeared, and all seemed to be right with the world.
Then, I started updating my objects and found that the annotations didn’t move. At all. I found a bunch of people on the web trying to solve the same problem, but I wasn’t very happy with the solutions I found. Most of them involved removing the annotations and adding them back into the map view. But, thankfully, I found one article that mentioned KVO on the iPhone. I was pretty familiar with KVO from my Flex projects, but didn’t even realize it was supported in Objective C.
To make a long story short, if you don’t use the willChangeValueForKey and didChangeValueForKey before and after updating your coordinate property on your annotation object, the MKMapView will not be aware that it has moved. After bracketing my XML update code with those two calls, all of a sudden my annotations started moving around.
-(void)xmlProperty:(NSString *)newXml
{
[self willChangeValueForKey:@"coordinate"];
[xml release];
xml = [newXml retain];
[self didChangeValueForKey:@"coordinate"];
}
Exporting from Core Data on iOS.
So, I’m working on the latest release of our scrapbooking app (Coolibah) and I needed to export some objects that are stored in SQLLite through Core Data to my server. After googling around for a while (and finding not much, it seems like search results have started to really suck lately) I had to strike out on my own and work something up. I got to use a very cool Objective C feature that I’ve only recently discovered: categories.
I was able to extend the NSManagedObject class and add a new xmlString property. By using the entity property to do some simple introspection, I was able to write a serialization function in about 50 lines of code. Enjoy!
NSManagedObject+XMLSync.h
// // Created by Scott Means on 1/5/11. // Released into the public domain without warranty. #import <CoreData/CoreData.h> #import <Foundation/Foundation.h> @interface NSManagedObject (XMLSync) @property (nonatomic, readonly) NSString *xmlString; @end
NSManagedObject+XMLSync.m
//
// Created by Scott Means on 1/5/11.
// Released into the public domain without warranty.
#import "NSManagedObject+XMLSync.h"
@implementation NSManagedObject (XMLSync)
- (NSString *)xmlString
{
NSEntityDescription *ed = self.entity;
NSURL *uri = self.objectID.URIRepresentation;
NSMutableString *x = [NSMutableString stringWithFormat:@"<%@ id=\"/%@%@\"",
ed.name, uri.host, uri.path];
for (NSString *a in ed.attributesByName.allKeys) {
id value = [self valueForKey:a];
if (value) {
if ([value isKindOfClass:[NSString class]]) {
[x appendFormat:@" %@=\"%@\"", a, value];
} else {
if (![value respondsToSelector:@selector(stringValue)]) {
NSLog(@"no stringValue");
}
[x appendFormat:@" %@=\"%@\"", a, [value stringValue]];
}
}
}
bool hasChildren = NO;
for (NSString *r in ed.relationshipsByName) {
if (!hasChildren) {
[x appendString:@"/>"];
hasChildren = YES;
}
NSRelationshipDescription *rd = [ed.relationshipsByName objectForKey:r];
if (rd.isToMany) {
hasChildren = YES;
[x appendFormat:@"<%@>", r];
for (NSManagedObject *c in [self valueForKey:r]) {
[x appendString:c.xmlString];
}
[x appendFormat:@"%@>", r];
}
}
if (hasChildren) {
[x appendFormat:@"%@>", ed.name];
}
return x;
}
@end
Next project: figure out how to do better code formatting in WordPress!
Preserving good code for posterity.
I’ve recently had to learn a couple of new programming languages in a hurry. I’m a pretty fair programmer in half-a-dozen other languages, but starting from scratch is always difficult. Even though flow control and syntax might be similar to something you already know (“is it for each or foreach?”) there is definitely a “natural” way to do things in every language. Some of the worst coding train-wrecks I’ve seen (and I’ve seen some doozies) happen when a programmer attempts to do something complex in a language they barely understand. They might know a way to do it in another language and try to map that knowledge into the target language, but that rarely leads to a clean solution.
So, wanting to do my bit, I created a new website called Native Code to try to make this easier. My goal is to create a database of common low-level coding idioms (micro-patterns, if you like) and then have them expressed in as many programming languages as possible. And not just expressed, but expressed well. So, please feel free to add your own contributions, create your own idioms, and otherwise capture your coding know-how for the ages. Enjoy!
