1====================================== 2Understanding existing PyObjC examples 3====================================== 4 5Introduction 6------------ 7 8This tutorial is aimed primarily at people with little or no background 9in Objective-C and Cocoa, and it will help you to understand PyObjC programs 10written by other people, such as the examples included with the distribution. 11This document is actually not a true tutorial: you do not get to build anything, 12only read and examine things. 13 14It is strongly suggested that you first do the 15:doc:`Creating your first PyObjC application <firstapp>` tutorial to get some hands-on 16experience with PyObjC, Cocoa and especially Interface Builder. 17 18Model-View-Controller 19--------------------- 20 21If you have used another GUI toolkit in the past it is essential that 22you understand that Cocoa is different. For this once this isn't 23marketing-speak: Cocoa is inherently different from common toolkits such as 24Tk, wxWindows, Carbon, MFC, etc. Apple's documentation explains this, but 25such introductory text is often skipped. It is a good idea to refer back to 26`Application Architecture`__ after reading this section. If you want, you can 27write code that does not follow the Model-View-Controller paradigm, but you 28would be on your own. Cocoa and Interface Builder are designed to suit this 29model. 30 31.. __: http://developer.apple.com/documentation/Cocoa/Conceptual/AppArchitecture/index.html 32 33Cocoa is built on the Model-View-Controller paradigm (MVC). What this means 34is that the application code should be split into three parts: 35 36- The *Model* is the storage of and operations on the data. The model 37 could be as complicated as a large database, or as simple as a 38 currency conversion function that only knows how to multiply two floating 39 point numbers, as in the Currency Converter application built in the first 40 tutorial. 41 42- The *View* is what the user sees and interacts with on-screen. 43 44- The *Controller* is the glue that binds the Model and the View together. 45 In the Currency Converter tutorial it is the callback that is triggered 46 when the user presses the "Convert" button, which gets the data from the 47 "amount" and "rate" fields of the View, passes them to the Model for 48 computation and sends the result back to the View. 49 50To summarize: the Model knows nothing about the user, the View knows nothing 51about the data and operations, and the Controller only knows how to relate 52the Model and the View. For really tiny applications, such as the currency 53converter, it may be tempting to do away with the Model and simply put that 54code in the Controller. You probably shouldn't do this, as it can make 55your code harder to read since it will be a mix of algorithms and glue code, 56however there is no technical limitation that prevents you from doing this. 57If you do combine the functionality of the model and controller, it is 58customary to name it as if it represented the document (without "Controller"). 59Note that the MVC paradigm is not specific to Cocoa and can be used with almost 60any GUI toolkit, but Cocoa is explicitly designed for this paradigm. 61 62You should have an MVC trio for every distinct unit of information in your 63program. In case of a simple dialog-style application such as Currency 64Converter you will have one such trio. Most applications, however, will have 65at least two: one for the application itself and one for the "documents" the 66application handles. These may be real documents (i.e. files), but a document 67can be more abstract. For example, if your application does scientific 68simulations that run in separate windows, each simulation could be a document. 69 70The NIB file 71------------ 72 73Cocoa and Interface Builder strongly encourage you to use a NIB file 74per MVC trio. You should follow this encouragement unless you are sure 75that you know what you are doing. 76 77This brings us to the second big difference between Cocoa and other GUI 78toolkits: almost all of the boilerplate code is replaced by the NIB. 79The source of Cocoa programs that do little work, especially example programs, 80will typically be much shorter than the equivalent with other toolkits. 81 82The NIB file is *not* a description of dialogs and menus and buttons, as you 83would get out of interface-builders for other toolkits. A NIB file is more: 84it contains a archived object graph that represents the GUI, conceptually 85similar to a pickle in Python. You tell Interface Builder 86about all the relevant classes in your application, the instances you 87want to create from those classes, and how the classes should connect to 88each other. Interface Builder the actually instantiates the classes, makes 89all the connections and at that point freezes and stores the whole lot. 90 91Unarchival of a NIB happens in two phases. The objects are restored using the 92``NSCoding`` protocol (``initWithCoder:`` is similar to ``__setstate__`` of 93Python's ``pickle`` protocol), and then each object is sent an 94``awakeFromNib:`` message so that they may do any initialization that depends 95on a fully restored object graph (``pickle`` does not have this functionality 96built-in). 97 98The section above explains a lot of the strangeness in AppKit-based PyObjC 99applications: 100 101* Windows and dialogs are typically not explicitly created, because they were 102 instantiated by the NIB. 103 104* Initialization is not always done in ``__init__`` or equivalent, because 105 the object graph may not be completely unarchived until the first 106 ``awakeFromNib:`` is called. 107 108* Attributes that reference other objects are not typically set explicitly, 109 but are done by the NIB file during unarchival. 110 111This also explains why you want separate NIB files for each MVC trio: 112the objects and classes in a NIB file are all unarchived together. In other 113words, if you had created your document window in your application NIB 114(even if you set it to "hidden" initially so it does not show up) it would 115become very difficult to create a second window for a new document. 116 117If you think about the consequences of this section for a while it will 118become clear why all the boilerplate code is missing from Cocoa applications: 119you don't need it. Like the output of other gui-builders, a NIB usually 120contains enough information to recreate the view objects, but a NIB can also 121contain a large proportion of the setup for your Model and Controller 122functionality. This is especially true when using `Cocoa Bindings`__. 123 124.. __: http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/ 125 126Delegates 127--------- 128 129If you are familiar with other object-oriented GUI toolkits such as MFC 130another thing to notice is that Cocoa applications often use a *delegate* 131object where other toolkits would use a subclass. For example: it is not 132common to use your own subclass of ``NSApplication`` for the main application 133object. ``NSApplication`` objects have a helper called its ``delegate``. 134The application object will attempt to inform its delegate many interesting 135events, and the delegate implements only the methods for the events it is 136interested in. 137 138For example, the method ``applicationShouldTerminate:`` of the delegate 139is called just before the application quits, and it has a chance to return 140``NO`` if it is not appropriate to quit just yet. 141 142Examining a NIB file 143-------------------- 144 145Let us examine the final NIB of the Currency Converter tutorial with this in 146mind. If you open it and look at the main window (titled "MainMenu.nib") 147and select the "Instances" pane you should see six objects. Two of these 148have greyed-out names ("File's Owner" and "First Responder"), these are present 149in every nib can not be changed. The "File's Owner" is either the Controller 150or the combined Model-Controller object, and is specified by the application 151when it loads the NIB. For the main nib, which is loaded automatically by 152``NSApplicationMain`` or ``PyObjCTools.AppHelper.runEventLoop``, this will be 153the instance of ``NSApplication``. Currency Converter is not a document-based 154application, so the MVC trio for the conversion window are in here too. These 155are named ``Converter``, ``Window`` and ``ConverterController`` respectively. 156 157Let us have a look at the ``ConverterController`` object by double clicking it. 158The "MainMenu.nib" window goes to the "Classes" tab, and an info window shows 159up. In the "MainMenu.nib" window the ``ConverterController`` class is 160selected, and you can see it is a subclass of ``NSObject``. Having the same 161name for the class and the instance is common in Cocoa programs, the main 162exception being the File Owner object. 163 164The info window shows more information on the ``ConverterController`` class. 165It should pop open to the "attributes" page. In the "Outlets" tab you see that 166instances of this class have four attributes, ``converter``, ``rateField``, 167``dollarField`` and ``totalField``. In any instance of ``ConverterController`` 168you can connect these to other objects, as we shall see below. The "Actions" 169tab shows that there are two methods ``convert:`` and ``invertRate:``, and 170again you can arrange for these to be called on instances of your 171``ConverterController`` on certain events by making connections. 172 173So let us now look at the connections for our ``ConverterController`` 174*instance*. Select the "Instances" tab in the main window, select 175``ConverterController`` and set the info window to show "Connections". You 176now see all the outlets defined in the class. Select one, and in the lower 177half of the info window you will see which object it connects to. Moreover, a 178blue line will also link the object representations in the main window and 179in the dialog preview window. 180 181Finding out who calls your ``convert:`` method is more difficult, though, with 182this view. But, if you select the "Convert" button in the dialog you will see 183that its ``target`` action will go to the ``ConverterController.convert_`` 184method. 185 186Luckily there is a way to find such incoming connections without reverting to 187guessing. For instance, you will be hard put to find who, if anyone, calls 188``ConverterController.invertRate_``. The solution: go to the "MainMenu.nib" 189window and look at the top of the vertical scrollbar. There are two little 190icons there, one with lines and one with squares, with the squares being 191highlighted. Press it. The view will change to a scrollable list with objects 192in the left column and an indication of connections in the right column. You 193can now see our ConverterController object has four outgoing connections (the 194ones we found earlier) and two incoming connections. Click on the incoming 195connections icon. The view will change again and ConverterController will 196probably scroll out of sight. Locate it, and see that there are two lines 197going out of the ConverterController object. One goes to ``NSButton(Convert)`` 198and is labeled ``convert:``, we knew about that already. The other one goes to 199an object ``NSMenuItem(Invert Exchange Rate)`` and is labeled ``invertRate:``, 200so that is where calls to ``invertRate:`` come from. And if you look at where 201this ``NSMenuItem`` sits in the object hierarchy you find that it is an entry 202in the "Edit" menu in the menubar. 203 204Examining an Apple example 205-------------------------- 206 207This section remains to be written. Contributions will be gratefully accepted 208:-) 209