Copyright ©1998 by AAA+ Software Forschungs- und Entwicklungs Ges.m.b.H. All Rights Reserved.
Joy Expert Topics
This section explains Joy's more arcane features and points out some potentially troublesome spots.
Retain/Release
The following might be a problem if you are new to Yellow Box programming. Try the following in any Joy command window:
joy> set string [@ hugo]
NSInlineCString@0x8bae8
joy> $string length
invalid target object: "NSInlineCString@0x8bae8"
Is this a bug? No, it isn't. Almost all commands, functions, or methods that allocate new objects and return them to the caller, autorelease these objects before they are returned. The application's autorelease pool is emptied after every event it processes, so the object that's pointed to by $string ceases to exist in the moment you hit the return key. Now try the following:
joy> set string [[@ hugo] retain]
NSInlineCString@0x8bb70
joy> $string length
4
joy> $string release
This is a problem only when you are interactively typing Joy commands into a command window. In any longer stretch of code, where there is no danger of the current autorelease pool being emptied, you do not need to retain/release your objects! You might want to consult the Yellow Box documentation if you are unsure about how its object reference counting scheme works.
Application inspector
Joy's application inspector is a useful tool, but it does have its limitations. First of all, the application inspector runs inside the address space of the application you are inspecting (unlike the debugger, or the AppInspector tool you might remember from NEXTSTEP 3.3 days, that peep into the program from the outside). This means that you can crash your application by peeking inside the wrong object, or calling the wrong message. Also, it is not possible to use the application inspector while the application's execution is suspended by the debugger.
Second, the object instances that are listed by the application inspector are only those that are "known" to Joy (see the Joy Language Summary if you are unsure about what that means), not all instances existing in your program. In particular, Joy doesn't have any chance of seeing an instance that was allocated earlier than the first Joy interpreter instance, unless it is returned to Joy from an Objective-C method, accessed through a pointer or instance variable, or passed as an argument to a Joy method. Also, the instances display is a snapshot, meaning that listed instances could already have been released. To avoid an infinitely growing instances list, the instances corresponding to the application inspector's cells are never displayed.
The application inspector includes a few checkboxes you can use to customize its behaviour: By turning off the "Enable Autorelease" checkbox, you can prevent the application's autorelease pool from ever being emptied, so all listed instances remain available for inspection. By turning off the "Trust Id Pointers" option, you can prevent some application crashes at the cost of not being able to follow pointers to "unknown" instances. If you experience frequent crashes when using the application inspector, try toggling this option. By checking the "Auto-Display Selection" box, you can tell the application inspector to always show the contents of the currently selected browser cell in the command text view below the browser. This is useful to view long strings that don't fit into a browser column. If you check "Auto-Update", the browser will update its last column automatically every few seconds. You can restrict the display in the last browser column by typing a glob-style search pattern into the text field above the browser, e.g. NS* will restrict a classes display to show only classes from the Apple frameworks.
Teaching delegate methods
Methods intended to be called by another object via the delegate mechanism should always be taught before the call to setDelegate:, to guard against the possibility of the setDelegate: method caching the method implementation. Even if you want to change the implementation of a delegate method later, you should do something like
$obj setDelegate: nil
objc:teach $delegate {- void delegateMethod: sender {new implementation}}
$obj setDelegate: $delegate
Teaching skills to instances of a class cluster
Be aware that it is not safe to teach skills to instances of a class cluster, such as NSArray. That is because teaching a skill to an instance involves dynamically creating a subclass of that instance's class, and subclassing a private subclass inside a class cluster is not supported by Apple.
Multiple interpreter issues
While simple Joy applications will not need more than the one Joy interpreter instance that is already provided when you choose the New Joy Application menu command in InterfaceBuilder, you can have your application use any number of them by dragging additional interpreter instances off the Joy palette.
In addition to those interpreter instances that appear in your application's NIB files there is always another interpreter called the main interpreter. In InterfaceBuilder the main interpreter is created when the Joy palette is loaded (the window you get by choosing Command Window... in the Joy menu evaluates your commands in the main interpreter). In a stand-alone application the main interpreter is created by the startup code and eventually sources the main.tcl file, which in turn causes NSApp to be created and the application's main NIB file to be loaded. Every Joy interpreter contains a global variable called mainInterp that points to this main interpreter instance. When the test {$self == $mainInterp} returns true, your code is running in the main interpreter itself. You can use the main interpreter as a repository for global information that all other interpreter instances in your application should share (everybody can eval code in the main interpreter by calling $mainInterp eval: code). Another way to access the main interpreter is to tell Joy to substitute any interpreter instance in a NIB file with the main interpreter when the NIB file is loaded, by checking the appropriate box in the interpreter's InterfaceBuilder inspector. When this box is checked, the interpreter's init file (if any) will in reality be sourced by the main interpreter, and its connection variables will also be created in the main interpreter. When you use this feature, be aware that now the same init file can be sourced more than once by the same interpreter, which is not normally the case.
Initialization sequence
Every Joy interpreter sources various initialization tcl files when it is created. The very first file sourced by the main interpreter is always itkRuntimeInit.tcl, followed by appInit.tcl, followed by itkDeveloperInit.tcl (only if running in InterfaceBuilder). Other interpreters source only appInit.tcl. All of this happens in the -[ITKTclInterp init] method. Default versions of these files are in the Resources folder of the joyRuntime.framework (or the Joy.palette), but you can override them with your own versions by putting a like-named file in any of the directories that appear in $auto_path before the standard directories (e.g. your application's Resources folder).
Then, after any connection variables have been set, the interpreter's init file (if any) is sourced in the -awakeFromNib method. Joy interpreter init files are kept inside the NIB file package and are always named after the interpreter instance in InterfaceBuilder's object view, with the extension .tcl. If you change the name in the object view, Joy will rename the init file automatically when you double-click on the interpreter object the next time. Be careful to edit the correct version of the file, or your changes might have no effect!
Connection variables
When you control-drag from a Joy interpreter instance in InterfaceBuilder to any other object, you can then label the connection with a variable name. This tells Joy to set the given global variable in the interpreter to the id of the object when the NIB file is loaded. Also, when the connected object does have neither its target nor its action set to something other than nil (0), then Joy sets the target to the object itself, and the action to the selector action:. Joy provides a default implementation of the selector action: in a category of NSObject, which does nothing. The net effect of all this is that you can teach skills action: (and, in some cases, doubleAction:) directly to the GUI object that are performed if it is clicked or double-clicked, but you can still use the standard target-action paradigm of the Yellow Box if you prefer that.
Remember that all connection variables are global! If you want to access them from skill implementations or Tcl procedures, you have to put a global varName... statement at the start of the skill or procedure, or you will not be able to access them. There is always one global variable called self that points to the current interpreter instance. Do not confuse this global self with the hidden parameter self that points to the target of the current message inside skill implementations. If you need to access both, use code like upvar #0 self currentInterp. You can then refer to the current interpreter with $currentInterp and to the message target with $self. Alternatively, you can prefix any variable name with ::, which tells Tcl to look for the variable in the global namespace, so you can use both $::self and $self, for example.
Multiple Nib files
If you are using Joy Developer to build a more complex application, you might want to use multiple Nib files, maybe to handle multiple documents. Each of your Nib files can contain any number of Joy interpreter instances, and since you cannot draw InterfaceBuilder connections across Nib files, it is not immediately obvious how the various interpreters should communicate. There are a number of strategies you can use:
The next section provides a short language summary.