One of the big problems I had with the Python and Ruby bridges to Objective-C was that neither Python nor Ruby worked well for multithreaded programs. For both, the best we could hope was to use them on an application’s main thread. But if you (like I) wanted to use a scripting language to write actions to be run on other threads, you were out of luck.
But Nu is different.
Nu source code is parsed into objects that can be evaluated on any thread. The parser produces a list of symbols and other values linked together with NuCell objects. To run that parsed code, you just send the top list element the evalWithContext: message along with a dictionary of variable bindings (this happens automatically whenever a message written in Nu is evaluated). This evaluation can be performed in any thread while any other evaluations are also taking place. Just be careful not to modify things that might be used by other threads.
The Benwanu example that ships with Nu shows this in action using the NSThread interface.
I’ve been looking for a good opportunity to show how Nu can be used to script NSOperations. Tonight I found it in my del.icio.us feed, thanks to Buzz Andersen. His link to Markus Zarra’s Cocoa Tutorial: NSOperation and NSOperationQueue revealed a perfect example to redo with Nu.
Here is the Nu version:
(import Cocoa) ;; loads BridgeSupport files
(class PageLoadOperation is NSOperation
(ivar (id) targetURL)
(- (id) initWithURL:(id) url is
(super init)
(set @targetURL url)
self)
(- (void) main is
(set webpage ((NSString alloc) initWithContentsOfURL:@targetURL))
(set document ((NSXMLDocument alloc) initWithXMLString:webpage
options:NSXMLDocumentTidyHTML
error:(set error ((NuReference alloc) init))))
(if document
(then ((AppDelegate shared)
performSelectorOnMainThread:"pageLoaded:"
withObject:document
waitUntilDone:YES))
(else (NSLog (+ "Error loading document: "
(@targetURL absoluteString)
" " (error description)))))))
(class AppDelegate is NSObject
(ivar (id) urlArray (id) queue)
(ivar-accessors)
(set sharedAppDelegate nil) ;; closure makes this a class variable
(+ (id) shared is
(unless sharedAppDelegate
(set sharedAppDelegate ((AppDelegate alloc) init)))
sharedAppDelegate)
(- (id) init is
(super init)
(set @urlArray (array "http://www.google.com"
"http://www.apple.com"
"http://www.yahoo.com"
"http://www.neontology.com"
"http://programming.nu"))
(set @queue ((NSOperationQueue alloc) init))
;; modify this to control the number of concurrent operations
(@queue setMaxConcurrentOperationCount:2)
self)
(- (void) applicationDidFinishLaunching:(id) notification is
(@urlArray each:
(do (urlString)
(@queue addOperation:
((PageLoadOperation alloc)
initWithURL:(NSURL URLWithString:urlString))))))
(- (void) pageLoaded:(id) document is
(NSLog "\n\n\n\n\n\n")
(NSLog "do something with this: #{(document description)}")))
((AppDelegate shared) applicationDidFinishLaunching:nil)
;; sit in a run loop until all operations complete
(while ((((AppDelegate shared) queue) operations) count)
;; the "distantPast" date makes the run loop return right away
((NSRunLoop mainRunLoop) runUntilDate:(NSDate distantPast)))
(NSLog "that's all of them")
That’s all of the code. To test it, save it to a file and run it with nush, the Nu shell. Or if you are using TextMate and the Nu TextMate bundle, you can run it from your TextMate window with Command-R. It uses a subclass of NSOperation to download and parse web pages in separate threads, and each operation marks its completion by sending a message back to the application delegate.
Try this for yourself, then make some changes and see where it leads. If you have questions, post or email them and I’ll try to help. Happy threading!


Comment on this post ↓
Leave a Comment (sign in with Twitter)