In a previous post, I talked about the different ways to use web service on MacOS X and mentioned that I was using NSXMLParser. Well, I changed my mind.
One of the benefits of NSXMLParser was that it was event-based; the NSXMLParser delegate functions get called automatically based on certain events - like when it encountered a new tag, etc. These delegate functions are, as far as I can tell, scheduled on the run loop so parsing a document doesn’t necessarily consume one big chunk of processing time. However, as I’ve gotten farther into the development of Mugshot, I’ve found more and more places where I want all or nothing.
I want “All” in the sense that I want the parse to happen and I want the results returned to me right away. With the NSXMLParser delegate system, that’s difficult because once I kick off the process, the method I kicked it off in will end and I’ll get the event-based callbacks. In these situations, using NSXMLDocument to load a URL, and then using it’s -nodesForXPath: functions is much simpler. And I also want “Nothing” in the sense that I want kick the XML fetch and my custom parsing off into a separate thread, and then get notified when it’s done without it taking processing time away from the rest of the app. The easiest way to do that is the +detachNewThread method of NSThread. It runs a single method, and when that method is over, the thread gets destroyed. With NSXMLParser, the method would finish, but the parsing and results haven’t happened yet. Again, dealing with the callbacks became more complicated than necessary.
Right now I’m doing a pretty large rewrite of my “FlickrHandler” system. These handlers are the classes I’ve set up to handle all interaction with Flickr’s web services. I originally wrote them using NSXMLParser, but for this rewrite, I’m switching them all over to NSXMLDocument. The base class has methods to handle basic errors, empty documents, and Flickr’s error codes and messages. The base class also has the methods needed to call a Flickr method and return a dictionary of the results directly, return the results using a callback to a delegate object, or spin the execution off into a separate thread that will call back to the main thread with the results. To add a new Flickr method handler, just subclass one of the existing handlers and replace the -execute:(NSDictionary *)flags method - you get the callback and multi-thread execution for free. I think this system will be flexible enough to handle everything I need going forward, and simple enough to understand and debug.
I’d love to put this system out there as a separate product sometime - so other people could use it to tap into Flickr. But right now there are three small things preventing that. First, the handler system doesn’t stand completely alone from the rest of the Mugshot code. I need to add a system for setting the shared secret and a few other pieces of data; Mugshot stores these internally outside of the hanlders. Second, all results are returned using NSDictionaries and I haven’t really done any documentation of what you could expect to get. Basically, your’e going to get every tag and attribute that flickr returns as a group of nested NSDictionaries. I don’t know if that’s the best solution - but for me it has the benefit of being data model agnostic.
Lastly, one more piece to the system which ties the behavior of all the indivudal handlers together - The Flickr Service Library. For every web service method that my code supports, I’ve documented most of its attributes in an OmniOutliner 3 file - whether it requires authentication, what handler class code should use for that method, what arguments it takes, what the default callback selector is, etc. At build time, I have an AppleScript that exports the file to OPML. That OPML file gets included in the bundle, and at runtime, the FlickrServiceLibrary builds a big dictionary out of it. That dictionary, keyed by web service method name, allows the handler system, and any client code (in this case, just Mugshot) to look up information about how it should handle those methods. This is the piece that’s not nearly as user-friendly as I’d like it to be. Technically, it may not be necessary - maybe it’s just my inexperience making things more complicated than necessary. But on the other hand, this library allows a LOT of my UI code to be pretty generic. My objects can include a method name for how they get populated with children or photos - and then some very generic code can look that method up in the library, create handlers for it, interact with flickr, and display the results, all without knowing what the object actually is.
Bottom line: I’m using NSXMLDocument now instead of NSXMLParser, I taught myself some AppleScript so I could generate the OPML file as part of my Xcode build process, and may be adding needlessly “cool” pieces to Mugshot because I can. I love this job.
0 Responses to “I Changed My Mind.”