Introduction to Mac OS programming for iOS programmers


This post will help the iOS programmer get started with Mac OS programming.

We have the following goals for this part of the course:

  • Orient the iOS developer to Mac OS development
  • Leverage your existing knowledge
  • Think about making a Mac OS companion for your iOS app
  • Highlight a few interesting features of Cocoa for Mac OS apps

.

Getting started with Mac OS programming

The iOS developer can take advantage of what they know to get started with Mac OS programming. The language (Objective-C) is the same, and many of the Cocoa frameworks are the same.

The way in which data is persisted is the same. You can use a plist file (for arrays and dictionaries), archiving (for any type of object), and Core Data. The application also has access to data stored at network locations.

On iOS, the developer has UIKit, a framework with user interface classes that were designed for the iOS. On Mac OS, the developer uses AppKit, a richer set of user interface classes. The iOS offers the developer and user a single window, and a screen-at-a-time way of working with the application. The Mac OS enables the developer to use a larger screen, which allows the use of multiple windows.

Mac OS apps can be built as “document-based” applications, which means that the user is able to create, work with, and save document-oriented data. What format of data? What type? Well, it’s up to the developer. It can be as simple as a single data type (e.g. a text string in a text editor application), or a complex object graph, where (for example) a document consists of data that’s displayed in a tabular and/or graphical format, along with other data that helps make up a complete document. Document-based applications typically enable the user to “File > New” (Command+N), “File > Save” (Command+S), close (Command+W), and print (Command+P) documents.

When creating a new project, the Mac OS programming beginner will select one of the “Mac OS X” templates. For the first few projects, choose the Application > Cocoa Application template. Then, you can choose, with a check box, to create a document-based application, and/or use Core Data in your application.

A Mac OS app that doesn’t use either documents or Core Data gets created with the following:

  • Application delegate – similar in function and purpose to the iOS implementation
  • MainMenu nib – holds the menu choices, and a window object for the user interface

A Mac OS app that is based on the document-based template gets created with the following:

  • MyDocument controller class – similar in concept to an iOS view controller class
  • MainMenu nib – holds only the menu choices
  • MyDocument nib – holds the window, the view (user interface), and works with the MyDocument controller

A Mac OS app that uses Core Data but isn’t a document-based app gets created with the following:

  • Application delegate
  • MainMenu nib
  • Core Data model

A Mac OS app that uses Core Data and the document-based template gets created with the following:

  • MyDocument controller class
  • MainMenu nib
  • MyDocument nib
  • Core Data model

.

Memory management

Mac OS apps offer automatic memory management. This is new for iOS (4.x and earlier) developers, who must know and use memory management techniques.

Therefore, in Mac OS apps, you do not have to be concerned with reference counting, retain/release, and so on.

.

Example apps introduction

We have a number of example apps today.

One is a real simple “hello world” app, that highlights a few differences between a Mac OS app and an iOS app.

The second app is actually one that we configure with a base level of functionality, and then add on some features in a subsequent version. In between, we look at an example that clearly shows the Cocoa Bindings feature.

.

HelloWorld sample app

HelloWorld The first sample app is HelloWorld. You can get it from the example apps download area.

It is a simple app, where you can enter text into a text field, click a button, and the text gets displayed in another text field.

Along the way, we do a few things that enable you to see how a Mac OS app is, or can be, quite different from an iOS app. Build your own app as you go through the sample app. Choose the “Cocoa Application” template, and don’t select any options for “document” or “Core Data”. Here are a few highlights of what you’ll experience:

Template contents: As you have learned, this kind of app includes an app delegate, a MainMenu nib, and little else. Open up the MainMenu nib, and you’ll see a “Window” object in the document window.

Controller class: To do some work, you’ll have to add a controller class. Click the Classes group, and add a new class. You will chose a “Cocoa Class”, specifically the “Objective-C class” (a subclass of NSObject). You will then add a reference to this new class in Interface Builder, by dragging an “NSObject” into the MainMenu nib’s document window, and setting its class name (to the name of the class you just created) on the Identity Inspector.

In your new class, you need to reference an NSTextField for the input area, another NSTextField for the output area, and a button. The text fields need to be marked with IBOutlet, and you’ll need to declare a method to handle the button click.

Back in Interface Builder, with the MainMenu.nib, add the two NSTextFields and the NSButton. Specifically:

  • The “input area” NSTextField will be a multi-line wrapping NSTextField
  • The “output area” NSTextField will be a multi-line label NSTextField
  • The NSButton will be rounded-end “Push Button”

To replicate the full functionality of the HelloWorld sample app, you’ll have to add in the parts for speech synthesis. The program code is well-documented, so look at it for what-when-where-why info.

An iOS app’s screen is a constant size, and we’re always working with a screen at a time. A Mac OS app can have a resizable window area. Our sample app anticipates this, by enabling the user to resize the window. Smooth resizing is implemented mostly in Interface Builder, by setting properties in the Size Inspector. Focus on looking in this inspector, and experiment with your own version of the app.

For a bit more fun, our sample app allows resizing only to the same height-width proportion as the background picture. To do this, we implement a delegate method that helps us.

.

Information about user interface objects (controls)

The iOS programmer will notice differences in AppKit user interface objects – e.g. buttons, text fields, and so on – that are conceptually related to UIKit objects. For best results, do not assume that an AppKit object has the same properties and instance methods as its related UIKit object. Also, when you look in the documentation for a class member, you may not find what you’re looking for. In that situation, follow the object inheritance hierarchy, and look in the object’s parent, repeating this action until you find what you’re looking for.

For example, an AppKit NSTextField has the following inheritance hierarchy:

  • NSTextField inherits from…
  • NSControl, which inherits from…
  • NSView, which inherits from…
  • NSResponder, which inherits from…
  • NSObject

To repeat, if you’re looking for a class member in NSTextField, and cannot find what you’re looking for, look in NSControl. Repeat with NSView etc. as required.

To help you get started working with text fields, note the following:

  • To read the contents of an NSTextField, send the instance the “stringValue” message
  • To write the contents of an NSTextField, send the instance the “setStringValue” message

.

Professors sample app (“Professors base”)

ProfLoad The second sample app is Professors. You can download the base version (ProfessorsBase) from the example apps download area.

Your iOS apps often included UITableView based views. This Professors sample app uses a Mac OS NSTableView to display information about a list of professors.

While the iOS UITableView is a one-column table, an NSTableView enables the display of multiple columns. Each column can display text (the default), or other data types. For our simple example, we’ll stick with text display.

When we worked with an iOS UITableView, we implemented delegate and data source methods to handle table view operations. Although we could do that in a Mac OS app, we won’t – instead, we’ll use Cocoa Bindings, a Mac OS technology that can simplify table view operations. You’ll see that you can create a functional table view with little or no code.

.

Introducing Cocoa Bindings

Cocoa Bindings can simplify table view operations, and any other situation where you want to bind user interface objects to data model objects.

The data model objects can be simple – a string or an int for example – or they can be more complex and real-world – like an array, dictionary, or Core Data managed object graph. For best results, expose the data model object(s) as properties.

To introduce Cocoa Bindings, get the “Bound Slider” example app. It has a user interface with a slider and a text label. When the slider value changes, the text label is updated with the new value. The view controller has an int property, and both user interface objects are bound to the property. The Bindings Inspector enables you to establish the binding.

The following image illustrates the binding relationship:

Cocoa Bindings - bound slider

While the example app and the diagram above shows you how to bind to a simple and distinct data model object (i.e. the int), you may also need to bind to a collection of objects, to display for example, a table view (as in today’s Professors… example apps).

For this scenario, Cocoa offers an Array Controller object. The Array Controller is added to the window nib, and a reference is made from it to your data model object, which in today’s example, is an array called “professors” in the view controller. The professors array is exposed as a property, and holds instances of “professor” objects as its elements.

Then, user interface objects are bound to the Array Controller, by specifying a “key path” to the data model object properties. Ideal for use with a table view, an Array Controller has an “arrangedObjects” instance variable, which represents the data model object collection (as a result of its reference to – in today’s example – the “professors” array in the view controller). The user interface object specifies the arrangedObjects instance variable, and then the property name in a data model object.

Alternatively, if the user interface object is to be bound to a specific object (rather than the whole collection), the Array Controller’s “selection” instance variable (inherited from NSArrayController’s superclass, NSObjectController) is the binding key. This scenario is used for one-of user interface elements, like a text label or an image.

The following image illustrates the binding relationship in the “Professors base” example app:

Cocoa Bindings - array controller

.

Continue working on the  “Professors base” app

Now that you understand more about Cocoa Bindings, let’s continue building the app.

The first HelloWorld sample app was not a document-based application. Professors is, so as you’re following along, create a new Cocoa Application, and chose the “document” option. Notice that you get a MyDocument class and nib.

If you build and run, you will see that you get a fairly functional app from the template. You are able to create new (Command+N) document instances, close (Command+W) them, and so on. You can try saving (Command+S), but the save method hasn’t yet been implemented.

The next thing we want to do is to create a model class, “Professor”. This class will have properties for name, office, and photo. Nothing much is new here, when compared to the task in an iOS app. The class includes an init method overload that enables a fully working instance object to be returned.

Then, we will create an array that will be the data source for the table view. We do that in the MyDocument class. We configure it as a property, so that it will work with Cocoa Bindings.

ProfBase1 Now, we can create the user interface. It has two buttons (add a professor to the table view; delete a professor), a table view, and an image view (in which we’ll add photo support later). See the screen image on the right. On the window object’s Attributes Inspector, the “Resize” control has been unchecked/cleared, because we don’t want the user resizing the window.

After laying out the interface, do this: Drag an array controller from the library into the document window. On the Attributes Inspector, set the Class Name to “Professor”, and add the keys for the fullName, office, and photo properties. The keys match up to the model object’s properties, and are used by Cocoa Bindings. See the screen image below / to the left.

ProfBase2

What did you just do? You added an array controller, and told it to work with “Professor” objects. In a minute, we’ll connect it to the “professors” array in the MyDocument class.

ProfBase3 An array controller manages a collection of objects in a situation where we use Cocoa Bindings. The Cocoa Bindings technologies do a number of things for us, including reducing code dependencies, and synchronizing views when model data changes (and vice-versa). The array controller is a helper object, similar in a way that the “fetched results controller” is a helper object in an iOS app that uses Core Data and a UITableView.

So, the array controller knows it is working with “Professor” objects. Let’s connect it to the “professors” array in the MyDocument class. Click the Bindings Inspector (green rectangle and circle). In the Controller Content area, bind to File’s Owner (i.e. the MyDocument class), and enter “professors” in the model key path dropdown list. The other properties are fine as they are. See the screen image to the right.

The final array controller configuration task is to connect the “add” and “delete” buttons. Click to show the Connections Inspector. In the Received Actions area, click-and-drag the “add:” outlet to the add button in the user interface. Click-and-drag the “remove:” outlet to the delete button in the user interface. Your inspector panel should look similar to the example below.

ProfBase8

OK… now it’s time to connect the table view columns with the “Professor” properties fullName and office. Double-click the table view column for the professor’s name, and the window should look similar to the screen capture image below, on the left. Now, in the Bindings Inspector for that column, set these properties, so that they appear similar to the screen capture image below, on the right.

  • Bind to Array Controller
  • Controller Key is arrangedObjects (which is the “professors” array we just pointed to above)
  • The Model Key Path is fullName (that’s what we want to show up in the table view column)

ProfBase4 ProfBase5

Continue by configuring the office column. Double-click the table view column for the professor’s office, and the window should look similar to the screen capture image below, on the left. Now, in the Bindings Inspector for that column, set these properties, so that they appear similar to the screen capture image below, on the right.

  • Bind to Array Controller
  • Controller Key is arrangedObjects
  • The Model Key Path is office

ProfBase6 ProfBase7

ProfBase9 Save your work. At this point, you’ve configured an array controller helper object, and configured it to bind to the “professors” array. Run your app, and you will see that you can add and remove professors from the list.

The final thing we want to do with this app is to add the ability to drag-and-drop a professor’s photo into the image area of the app. It turns out to be easy to do. Click to select the image view. In its Bindings Inspector, set these properties, so that they appear similar to the screen capture image to the right.

  • Bind to Array Controller
  • Controller Key is selection this time; we’re relying on a selected professor in the table view list
  • The Model Key Path is photo
  • Conditionally Sets Editable is checked

Run your application again. Make sure you have created and selected (highlighted) a professor on your list. Now, open a Finder window that contains some photos, or a web page in Safari. Click, drag, and drop a photo into the image box on the app.

.

Professors sample app, enhanced (“Professors save and load”)

The third sample app extends Professors. You can download the enhanced version, ProfessorsSaveLoad, from the example apps download area.

As the name suggests, it adds the ability to save your list of professors as a document, and to load it up again.

We are going to use “archiving”, the same technology that we used on the iOS apps many weeks ago. To review, we have to configure the model class to know how to archive itself, and then we’ll implement methods in the controller that will take care of the saving and loading.

The first task is to edit the Professor .h interface to conform to the NSCoding protocol. Next, in its .m implementation, implement the initWithCoder: and encodeWithCoder: methods, as shown below.

Code1

Next, we write some code for some existing MyDocument controller methods that we’ve ignored up to now.

The dataOfType:error: method implements saving. It runs when the user chooses “Save” from the File menu (or presses Command+S), provides a file name, and clicks the save button. To make it work, make it return an NSData as shown below:

Code2

The readFromData:dataOfType:error method implements loading. It runs when the user chooses “Open” from the File menu (or presses Command+O), selects a file/document, and clicks the open button. To make it work, read (load) the data, place it into the “professors” property, and return YES, as shown below:

Code3

Finally, we need to change some settings for the overall app that it and Mac OS will be able it to recognize the documents the app works with. Expand/open the “Targets” group, right-click the “Professors save and load” app, and choose Get Info. Click the Properties tab. This sheet enables us to configure information about the documents that this app works with. Here’s what to do. For more information, consult the reference documentation.

Near the top, change the “Identifier” to a unique identifier – use some of your name for this, and the last part will be the app’s name.

In the Document Types list, change the only entry, so that it has the following properties:

  • Name – Professors document
  • Extensions – profs
  • OS Types – empty/blank/null

Close the dialog box to save your changes. See below for a before and after view of this dialog box.

Before…

Target - file extension config

After…

Target - file extension config

Now, run your app. The save and load/open operations should work.

.

Summary

This Mac OS programming introduction has shown you some of the similarities with iOS programming, and it has highlighted a few interesting capabilities that are available only on Mac OS apps. Take your time reviewing today’s notes, and recreate the examples on your own. Then, you will be ready to complete the last lab/assignment.
.


Advertisements
  1. October 2, 2011 at 1:59 pm

    I really appreciate that there are people like you! Great article. Thanks!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: