Handling Cocoa Notifications With Lua
This is less a “cool Lua trick” and more a “cool way to use Lua”. What I’m doing is using Lua to write a Cocoa application. There are a couple tools to do this (Wax and LuaCore spring to mind) but they work on a different paradigm: they’re like RubyCocoa in that they have a bridge where you can write Lua code that makes Cocoa objects, and write your whole app in Lua. I don’t want to do that because I don’t want to get in a race with Apple. Cocoa has a pretty good Objective C interface, including stuff like blocks and Interface Builder and CoreAnimation, and I’m perfectly happy to use it. I would just prefer to write the parts of my program that aren’t tied to Cocoa objects in something a little more terse.
I’m going to go over what I did, conceptually, because last time having all the code made the post way too long.
To start, let’s talk a little about the way you’re supposed to architect Cocoa programs. Cocoa is an older model of OO programming than the C++ / Java model, and it really does draw a distinction between message passing and function calls. Not only can you have a function respond to arbitrary messages (like method_missing
in Ruby) but you can broadcast a message to the world in general and let other objects decide whether they want to handle it. This is called a “notification” in Cocoa (it’s a pretty common facility in GUI libraries but Cocoa uses it more than most), and you can use it not only to tie objects in your program together but actually as a form of IPC to have your program talk to other programs. It’s a really powerful system.
So, the way you’re supposed to design a Cocoa program is that nothing has a reference to anything else; you have a controller that (say) listens for a button press and then posts a notification, and some other objects that wait for a “saveDocument” notification and handle it. Everything is little self-contained objects created by a NIB file you made in Interface Builder, and they talk through notifications.
This struck me as a good way to embed Lua. Before, I had gotten bogged down trying to expose enough to Lua to let it drive the interface directly; that code was all simple but extremely repetitive. So instead, I made a LuaManager class that encapsulates a Lua state, and exposed two C functions to it that let Lua code post notifications and call Lua functions in response to notifications.
It took three or four hours and is incredibly simple; all I ever send across are numbers, strings, and tables, so no having to define userdata or anything. I create an instance of LuaManager in Interface Builder, tell it what Lua source file to run (stored in the app bundle), it sits there happily processing notifications. Lua objects stay in Lua (except strings and numbers, which are trivial to convert) and Cocoa objects stay in Objective C, nothing can directly talk to anything else so there’s very little glue code to write.
If you’d like to look at it, here’s the code. It’s going to eventually be some kind of puzzle game. I’m thinking something like Chip’s Challenge crossed with Pachinko; you drop a ball in and it falls through this machine, hitting switches and redirecting things and pushing things into other things.