]> git.saurik.com Git - wxWidgets.git/blame - docs/cocoa/coding_patterns.txt
Fix typo in wxSingleInstanceChecker docs, props Lauri Nurmi.
[wxWidgets.git] / docs / cocoa / coding_patterns.txt
CommitLineData
b1c702af
DE
1=== wxCocoa coding patterns ===
2
3Any language or library tends to have a particular set of coding patterns that serve to make the code easier to read
4by making it look consistent across the project. Objective-C makes particularly heavy use of patterns as does wxWidgets.
5It is not the intention of this document to repeat Cocoa or wxWidgets documentation except for clarity.
6
7--- Class design ---
8
9wxCocoa takes a rather unique approach by decoupling interaction between C++ and Objective-C from the wxWidgets classes.
10For any given Objective-C class you wish to override messages from or receive action messages from (e.g. as a delegate
11or notification observer) you should implement a C++ wxCocoa##ObjcClass class and one or more Objective-C classes.
12
13The C++ class goes in a file include/wx/cocoa/ObjcClass.h (where ObjcClass is the Objective-C class name) and the
14Objective-C classes can either be declared in the implementation file (src/cocoa/ObjcClass.h) or separated into an
15include/wx/cocoa/objc/ObjcClass.h file.
16
17Take NSButton as an example. The include/wx/cocoa/NSButton.h declares a wxCocoaNSButton class. Classes such as
18wxButton, wxCheckBox, and wxRadioButton all multiply inherit from this (protected). These classes can almost
19be thought of as an interface whereby the inheriting class is essentially declaring that it is able to respond
20to the various Cocoa_ methods that will be called. It is not quite a pure interface as it actually contains the
21logic for this as well, but it can be thought of from a design perspective as such.
22
23Because we do not wish to subclass Objective-C classes except when absolutely necessary we use a hash map so
24that the wxCocoaObjcClass instance can be retrieved knowing only the ObjcClass instance. This is acheived by
25the sm_cocoaHash static member and the GetFromCocoa method. These are provided by the HASHMAP series of macros
26in the include/wx/cocoa/ObjcAssociate.h header.
27
28In addition to the GetFromCocoa method, the pattern also provides for a pair of Associate##ObjcClass and
29Disassociate##ObjcClass methods. These non-virtual methods if implemented by the macro merely insert and
30remove the Objective-C/C++ pair from the hash map. More often than not they require more than just associating
31using the hash map but also require setTarget: and setAction: to be called. This is a leftover of the original
32design where it was expected that the classes would be subclasses already containing the code to call the
33C++ virtual methods. Later design decisions changed this to use target/action and delegates whenever possible
34which is more often the case than not.
35
36To implement a response to an action message, one should simply create a singleton instance of a controller class
37that can be used for all instances of the given Objective-C class. For NSButton there is the wxNSButtonTarget
38class which implements the (arbitrarily named) wxNSButtonAction: method. The wxCocoaNSButton::AssociateNSButton
39method is implemented to setTarget:sm_cocoaTarget (the singleton wxNSButtonTarget) and
40setAction:@selector(wxNSButtonAction:). When the button is clicked, the NSButton will send a wxNSButtonAction:
41message to its target (the singleton wxNSButtonTarget) with itself as the sender. The implementation of
42that message simply looks up the wxCocoaNSButton in the hash map and calls the Cocoa_wxNSButtonAction method.
43
44The wxWidgets class (e.g. wxButton or wxCheckBox) implements that method as it sees fit. For example, to
45simply send the corresponding wxWidgets wxEvent.
46
47It should be noted that a better design might have used a generic target/action handler since target/action isn't
48actually specific to buttons. This might be a future design change.
49
50Of note, wxCocoaNSButton does not inherit from anything, particularly from wxCocoaNSControl. This is because
51of the C++ non-virtual base class problem. Instead, wxControl inherits from wxControlBase and wxCocoaNSControl.
52wxButtonBase in turn inherits from wxControl and wxButton in turn inherits from wxButtonBase and wxCocoaNSButton.
53
54One may be wondering how NSControl events (if any) make their way to the wxControl. The answer is in the way
55the Associate* methods are called. This is where the Set* methods come in.
56
57Within the wxWidgets class (e.g. wxButton) there is a SetNSButton(NSButton*) method. This method calls
58AssociateNSButton and DisassociateNSButton appropriately and also calls the base class SetNSControl implemented
59by the wxControl class (note: not the wxCocoaNSControl class). SetNSControl does a similar thing but then
60calls its base class SetNSView method. All of these are implemented using the same macro except for SetNSView
61which is implemented to do proper retain/release and set the m_cocoaNSView instance variable in wxWindow.
62
63In addition to the Set* set of methods, there is also a Get* set. These are implemented (inline) to cast
64the root class pointer type to the desired type. For instance, GetNSButton merely returns
65(NSButton*)m_cocoaNSView. These are a convenience for coding the library itself and are also public such that
66users of wxCocoa wishing to make Cocoa-specific calls can easily get at a properly-typed instance.
67
68This works well for the common case like a button or checkbox where one Cocoa class clearly represents one
69wxWidgets class. For more complex cases involving a Cocoa view hierarchy one may need to implement these
70methods in a different manner.
71
72
73--- The view hierarchy ---
74
75Because the Cocoa view hierarchy isn't a perfect match with the wxWidgets hierarchy, there are some conventions
76used to resolve this conflict. The first is that m_cocoaNSView is defined to be the view which most-closely
77represents the wxWidgets view. For instance, a wxButton has an NSButton instance and a wxStaticBox has an NSBox
4c51a665 78instance. Unfortunately, wxWidgets defines some behaviour that Cocoa cannot directly implement. This is primarily
b1c702af
DE
79window scrolling (e.g. without using a wxScrolledWindow) and window hiding.
80
81Scrolling is implemented in a separate class known as wxWindowCocoaScrollView. This class does not fit into
82the wxWidgets class hierarchy but instead implements the wxCocoaNSView interface itself, including listening for
83the Cocoa_FrameChanged notification. This is a good example of why the Objective-C to C++ shim code is
84unrelated to the wxWidgets class hierarchy. As you can clearly see, it allows the shim code to be used for
85classes that aren't part of the wxWidgets hierarchy.
86
87Hiding is implemented in another class known as wxWindowCocoaHider in a similar manner to wxWindowCocoaScrollView.
88This is an artifact of the pre-Panther days of Cocoa where there was no method for hiding a view.
89
90What these classes do is provide a Cocoa view that sits between the wxWidget's parent window's view and the
91m_cocoaNSView provided by the window. The wxWindow class has a GetNSViewForSuperview() method that returns either
4c51a665 92the m_cocoaNSView (if the window does not need scrolling behaviour and is not hidden) or returns the scroll view
b1c702af
DE
93for the case of scrolling or the dummy view in the case of hiding. As the name suggests, the method is used
94from the parent wxWindow (the superview) when it sends something like an addSubview: message. The method is under
95no circumstances intended to be used as the receiver of an addSubview message. In fact, not even the GetNSView()
96method should be used for this as in [m_parent->GetNSView() addSubview:GetNSViewForSuperView()] because this
97functionality is provided by the CocoaAddChild method.
98
99Note that there is a small hole in the API here because classes other than wxWindow wishing to implement a view
100hierarchy will not be able to correctly do this since CocoaAddChild is not virtual and there is no virtual
101GetNSViewForSubviews() method.
102