Introduction to Objective-C in MorphOS 3.10
Objective-C is conceptually similar to BOOPSI - it's generally an add-on to the C programming language. In both Obj-C and BOOPSI calling a method implies calling a dispatcher function that resolves the actual method to call and invokes it. With the addition of reference counting to BOOPSI in MorphOS, both follow the same memory management principles.
The main difference comes from the fact that BOOPSI classes need to be manually created with functions being manually assigned their IDs and let's not even start on the extra hassle of having to write the code for the dispatchers. This made programmers reluctant to add new classes in their applications, in turn making the overall code less object oriented.
Here's where Objective-C fills in.
The framework is essentially what Foundation is in Cocoa. It contains the root Object class as well as core application, threading, signalling, messaging and data management classes. All of the data classes are (apart from their prefixes) compatible with Foundation's classes. The classes are:
- OBArray
- OBData
- OBDictionary
- OBEnumerator
- OBHashTable
- OBIndexSet
- OBMapTable
- OBNumber
- OBSet
- OBString
and more including mutable variants, object coding support, autorelease pools, etc.
The MorphOS native parts include:
- OBApplication - base class for the Objective-C applications under MorphOS
- OBContext - a global runtime info class
- OBLocalization - in-source localization support (no writing .cd files by hand!)
- OBPerform - class supporting all sorts of method invocation
- OBPerformQueue - a generic replacement for MUI's PushMethod
- OBSignalHandler - exec.library signal handler class
- OBStringNative - convenience class handling the system charset encoded strings
- OBSystemTime - convenience class to query the system time
- OBThread - threading support class
- OBTimer, OBScheduledTimer - timing support classes
The framework is essentially a wrapper for the MUI's BOOPSI interface. Each of the MUI's public classes and many 3rd party classes get their equivalents the Obj-C framework. The underlying BOOPSI instances are created on demand, usually when the MUI application and its windows are constructed.
- All MUI methods can be overloaded
So mAskMinMax(IClass *cl, Object *obj, struct MUIP_AskMinMax *msg) becomes- (void)askMinMax:(struct MUI_MinMax *)minmaxinfo
- Setters and getters for MUI attributes can be overloaded
So MUIA_Disabled becomes- (BOOL)disabled; - (void)setDisabled:(BOOL)disabled;
And can be used like myObject.disabled = YES; (Objective-C 2.0) - Setting and getting MUI attributes works even if the underlying BOOPSI object has not yet been instantiated!
- No more murky ownership issues - if you add an object to a MUIFamily subclass it's retained. If you set a value to a property that has an object type - it's retained.
Notifies are a notable exceptions here, since the notify target cannot be retained, since that'd often cause a retain cycle. - Unicode - everywhere! Since ob.framework's OBString class is Unicode aware, all strings in MUI apps should be Unicode as well. The framework will convert them to the native system codepage if necessary when passing to the mui.library.
Internationalization of MUI apps should be done using OBLocalization:button.contents = OBL(@"Click Me", @"Label of a button that the user needs to click");
where the first string will be displayed as the text of the button and the latter is to be a hint to the translator about the purpose of the label.
The .cd file will be generated automatically with the obcd utility.
To initialize localization support just call[OBLocalizedString openCatalog:@"myapplication.catalog" withLocale:NULL];
right after creating the MUIApplication object. - Notifications on MUI attributes can be set up as usual:
[addRowButton notify:@selector(selected) trigger:FALSE performSelector:@selector(addRow) withTarget:_list];
... or you can overload the MUIButton class and its - (void)selected method! - The Notify on Dead Object issue can now easily be worked around thanks to the autorelease pools - simply add [[self retain] autorelease] in the method the notify invokes.
There's also a simple detection of zombie objects - where calling a method on an already dealloc'd object will produce an informative debug message rather than a random crash. - The MUIFamily protocol has been extended to several classes which followed similar principles, but did not inherit from MUIC_Family directly. The protocol is based on the OBArray class' interface. The classes that implement the protocol are MUIApplication, MUIGroup, MUIMenu, MUIList, MUIMenuitem, MUIMenustrip.
- MUI's obsolete input handling methods have been removed, classes need to overload the handleEvent:muikey: method and use the handledEvents property to set handled IDCMP flags.
- MUIRequest, MUICheckmark, MUIButton are now classes to avoid having to call MUIMakeObject().
- The underlying BOOPSI instance may always be accessed via the muiInstance property of the MUIObject class.
- Where applicable, method parameters and properties will use strong typing - that is, MUIArea's contextMenu property will return MUIMenustrip * rather than MUIObject * or id.
- MUISlave and MUIProcess as well as the pushMethod were intentionally disabled since the ob.framework offers better functionality while working in an Objective-C environment.
The following list names unsupported functionality:
- 3rd party MCCs - MCCs generally need to be added to the framework to become usable. Contact the SDK maintainers to find out how to get them added.
- Objective-C only attributes aren't automagically available through the BOOPSI interface. This also implies that you cannot setup a MUI Notify on them.
- This means that adding a 'myState' property to a class that inherits from MUINotify does not mean that there'll be MUIA_MyClass_MyState attribute supported.
Generally, this should not be necessary at all in a Objective-C MUI application. - Objective-C cannot be used to create standalone MUI Custom Classes (mcc).
Please consider the following notes:
- exceptions: work, but the frameworks themselves will never throw
- @synchronized: works
- frameworks use OBAlloc/OBFree to allocate memory, several methods may require that the programmer uses those (see OBData for example)
- method forwarding is currently unsupported
The current frameworks do not yet have a stable API, therefore the SDK will only allow linking them statically. This should change within a couple of months.
As of 3.10 release: LogTool, Synergy, Zoom, Defrag. The upcoming Iris email client is written in ObjectiveC++.