UXDesignable
UXDesignable is how a loaded nib connects itself to your controller. It has
two methods, and you do not write either of them.
#use <UXKit> // or #import "UXDesignable.xc"Overview
Section titled “Overview”protocol UXDesignable { bool setOutlet(u8* name, Object* value); bool wireAction(u8* name, UXControl* control);}A class that declares any outlet field or :action method auto-conforms,
and the compiler generates both bodies from the decorations:
class MainController : Object{ outlet UXLabel* statusLabel; outlet UXView* canvas;
void onSave(UXControl* sender) :action { … } void onQuit(UXControl* sender) :action { … }}That class now answers setOutlet("canvas", …) and wireAction("onSave", …)
with no further code. Writing : Object <UXDesignable> by hand is equivalent;
either way the compiler generates the bodies.
UXNib.loadWired uses these two methods to
connect a resource’s outlets and actions by name.
Why this and not reflection
Section titled “Why this and not reflection”xc has no reflection, no selectors and no message forwarding, so a nib cannot
look up a field by string at run time the way Cocoa does. The information a nib
needs is declared (outlet, :action) and the lookup is generated from
those declarations.
This has three benefits:
- A misspelled outlet in your source is a compile error, not a nil field that crashes at first use.
- A nib naming an outlet your controller does not have returns
falseat load, so a mis-wired interface fails where you can see it. - There is no run-time cost beyond a string compare, and no metadata to keep in step with the code.
Topics
Section titled “Topics”setOutlet
Section titled “setOutlet”bool setOutlet(u8* name, Object* value)Assigns the named outlet field with a checked cast. Returns false for an
unknown name or a type mismatch, so connecting a UXButton to an outlet
declared UXLabel* fails instead of corrupting the field.
wireAction
Section titled “wireAction”bool wireAction(u8* name, UXControl* control)Binds the named :action method to the control: control.setAction(&self.<method>),
performed inside this call. Returns false for an unknown name.
Using it from code, so the nib path stays honest
Section titled “Using it from code, so the nib path stays honest”This protocol is useful even if you never load a nib. A hand-written builder can call the same two methods instead of assigning fields directly.
// Not this — it works, and it exercises nothing a nib will use:c.canvas = view;
// This — the code path becomes a hand-written nib:if (!c.setOutlet((u8*)"canvas", (Object*)view)) { return false; }if (!c.wireAction((u8*)"onSave", saveButton)) { return false; }Written the second way, every wiring name in your builder is one a nib will later carry as data, and a typo fails in both paths. Written the first way, the nib path is never exercised, and its errors surface only when a nib is first loaded.
Rocks builds its own main window this way. The builder is a nib written in code,
so replacing it with UXNib.loadWired later changes one file and nothing else.
See also
Section titled “See also”UXNib: loads a resource and calls these two methodsUXNibV2: the newer formatUXControl: whatwireActioncallssetActionon- Bound methods and callbacks: what
&self.onSaveis