I have worked with Cocoa / Obj-C on and off over the years. As of 2010 I find it quite limiting compared to WPF / NET Framework. I will list some of the differences I’ve found, and you can judge for yourself.
Markup language
When I design in WPF I get markup that is very simple XML that I can easily hand-edit or edit using tools I write myself. In Cocoa I must use xib files, which are not designed for easy hand-editing or manipulation. Here is a simple example of WPF markup:
<DockPanel>
<Label>Select your favorite food:</Label>
<ComboBox
SelectedText="{Binding FavoriteFood}"
SelectedItemsSource="{Binding AllFoods}" />
</DockPanel>
This is the entire markup, and is equivalent to about 50 lines of hard-to-edit .xib.
The ability to see and edit simple XAML is incredibly valuable for:
- Direct manual editing
- Communication with peers (eg StackOverflow)
- Source contrrol
- Searching
- Automated transformations
Layout capabilities
In WPF I can use panels to automatically lay out my controls as the window size changes. I can use styles to define the spacing between my controls, or I can adjust margins to get the precise look I want, or both. In either case my UI will automatically adjust to changes in font sizes, window size, and screen resolution. In Cocoa, all controls are at specific x and y locations as with WinForms and the only thing I can do is auto-resize. This is extremely limiting. For example:
- Controls cannot wrap around to a new row or column as the window gets smaller (WrapPanel)
- Controls cannot add/remove detail based on available space
- Controls cannot move around to make room for a control that has more text than was originally expected
- Controls cannot selectively shrink or enlarge to fill available space
- Interface Builder initially sets controls to comply with interface guidelines, but a applying new style cannot change layout.
The advantage of WPF layout is that you can express your intent via the way you add controls to panels, then adjust the precise layout later. Note that WPF can also work the old-fashioned way but once you’ve used panels for layout you’ll never go back to X/Y layout.
For example, one application I did had rows containing star ratings plus comment boxes. Normally the row was only the height of a star rating, but when long commments were typed in the text box the TextBox got taller which made the row taller, so the following rows moved down. With WPF I got this behavior for free – with Cocoa I would have had to hand-code it.
Data connectivity
With Cocoa / Obj-C you are pretty much limited to the built-in data connectivity, which includes basic database access and serialization to and from files. With WPF / NET Framework you can directly bind your UI to practically anything under the sun, including:
- Relational databases (SQL, Oracle, etc)
- Object databases (Objectivity, Versant, etc)
- Legacy databases (Access, dBase, R:Base, etc)
- COBOL databases on mainframes
- Proprietary database formats (hundreds)
- Web pages
- Web services (SOAP, REST, etc)
- XML files
- Flat files (comma-delmited, tab delimited, fixed width)
- Office documents (Word, Excel, etc)
- OpenOffice documents
- PDF form fields
- GPS receiver data (current location)
- Positions of physical switches, buttons, levers, knobs, sliders, etc
- Time (local or network)
- Performance counters (CPU utilization, etc)
- Cameras (Video cameras, web cams, still image cameras, etc)
- Analog electronic inputs
- MIDI (musical instrument keyboards, pickups, etc)
- OBD-II (vehicle monitoring)
- LDAP and Active Directory (user account information)
- WBEM and SNMP (network device status and configuration)
In fact, you can bind to practically anything that has had a driver written in any NET Framework language – and there are over a hundred NET Framework languages.
Repetitive code
In Cocoa your model consists of a .h and a .m file, your controller consists of a .h and a .m file, and your view consists of a .xib file. Every single field in every object in your model must be referenced every one of these places!
In WPF / NET, a single field generally only appears in two lines of code: Once where the model is defined, and once where it is presented by the view. For example, in my code I usually define simple model fields in XML:
<Property Name="City" Type="string" />
then to create a text box to edit the city I simply drag the “City” property into my view and end up with this XAML:
<TextBox Text="{Binding City}" />
So “City” is mentioned in only two lines of code in my entire application (unless I have another “City” text box elsewhere). In Cocoa “City” will be referenced at least five times.
Binding directly to the model
In Cocoa a single controller is really only suitable for a single view: If you create a new view for the same model you need a new controller. In WPF / NET there is a better way to do it, though you can still create controllers if you really want to.
In WPF / NET a view will typically bind most of its controls directly to the model (see my City example above). Other controls will be bound to a “View Model” that models the state information associated with the current view. For example, if you are searching the “View Model” would contain the search string so it can be used by the view both to filter the results and to hilight the search text.
In WPF / NET you can also bind multiple properties of a control to the same or different parts of your model (or view model):
<TextBox Text="{Binding AmountToTransfer}"
Background="{edf:Binding UserIsHappy ? Green : White}" />
The difference is that in WPF a view model is usually shareable between several screens that are similar in their behavior, so in a LOB application when you create a custom view all you need to do is edit a single file.
Command architecture
In Cocoa a button stores its target and action in a NSActionCell
within the view, which means that it will invoke a specific method on a specific object (typically the controller). In WPF / NET a button has a Click event that works the same way, but it also has a Command property that allows you to invoke a command.
Commands in WPF are very powerful, since a single Command may be shared throughout the application. For example, WPF itself defines a Delete command. As long as your model responds to this command, adding a “Delete” button to your view is as simple as selecting the Delete command in the properties window, which creates this XAML:
<Button Command="Delete" />
This is all you have to do to get a functional delete button that deletes the object from a list. Note the built-in Delete command also:
- Has a key binding to the Delete key on the keyboard
- Supplies language-appropriate text (“Delete” or “Eliminar” or “Löschen” or “Supprimer” or …)
- Includes a descriptive tool tip
A command is routed to ancestor objects and models, so in a typical application you almost never need to specify which object receives the command.
Style sheets
In Cocoa there is no mechanism to apply style sheets to panels and have them affect all the controls in the panel, either at design time or at run time. For example an application may want to:
- Make all the TextBoxes in a given area read-only
- Make all labels bold
- Give all ComboBoxes a light green background
- Add uniform spacing between a set of buttons
- Use a large green checkmark for a set of checkboxes
- Add a Delete button to all lists
- Make all Delete buttons appear as a red “brushed” X instead of as a traditional button
- Make the same settings on several separate items
WPF / NET makes all of these operations trivial through the use of styles. You can set any property of any object through a style. Styles can be set implicitly by object type or explicitly, for example:
<Button Style="{StaticResource DeleteButtonStyle}" />
Style sheets can be defined anywhere you like: in a control libraries, at the application level, specific to a “theme”, on a window, in a specific control’s resource dicitionary, or directly on a control.
Control templates
In Cocoa you cannot do much to change the visual styling of controls except to subclass them, since they each draw their own appearance. In WPF / NET the appearance of a control is given by its template which can be freely replaced with pretty much anything you can think of.
For example:
- You can use a ListBox in your drop-down menus and style it to look like regular menu items (with a checkbox beside the currently-selected item)
- You can change a TreeView to appear as a sequence of ListBoxes instead of a tree
- You can change a slider’s “thumb” to appear as a business symbol or cartoon character depending on your target audience (slide a light bulb or Mickey Mouse back and forth)
- You can change a slider to appear as a knob or to follow a non-linear path
- You can change a CheckBox to appear as a click on / click off button, a lock icon that opens and closes, or a door that opens and shuts
Control templates and data templates may also include built-in animations, so for example your door can actually animate swinging open and closed when you click on it. This is trivially simple to do in Expression Blend: It takes about 20 clicks of the mouse. Just create two linear animations and attach them to event triggers.
Custom controls
Cocoa and WPF both allow you to subclass existing controls to create new ones. In Cocoa the new controls are serialized to the .xib / .nib file. In WPF they are part of the XAML just like the built-in controls:
<StackPanel>
<TextBlock>
Hello, <Run Text="{Binding FirstName}" />.
<Bold>Good morning!</Bold> How are you today?
</TextBlock>
<my:JoySelector Happiness="{Binding Happiness}" />
</StackPanel>
In this example JoySelector would be a control I defined and Happiness would be one of its properties.
A big difference between Cocoa and WPF is in the drawing of the custom controls. In Cocoa you must code calls to drawing primitives to create your control’s appearance. While this is an option in WPF, it is usually much more easily done using a control template.
For example, in Cocoa you might write:
CGSize size = CGSizeMake(30, 20);
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0, 1.0, 0.0, 0.0);
CGContextFillEllipseInRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
whereas in WPF using XAML the equivalent would be:
<Ellipse Width="30" Height="20" Fill="Red" />
or in WPF in code (C#):
return new Ellipse { Width=30, Height=30, Fill=Brushes.Red };
A ControlTemplate may of course have multiple items:
<ControlTemplate TargetType="my:JoySelector">
<Grid Width="50" Height="50">
<Ellipse Width="30" Height="20" Fill="Red" VerticalAlignment="Left" />
<Path Data="M0,0 L3,5 L8,8 L5,3 L0,0" Fill="Blue" />
<ComboBox
SelectedItem="{TemplateBinding Happiness}"
Style="{StaticResource JoySelectorBoxStyle}" />
</Grid>
</ControlTemplate>
This XAML would typically be created in Expression Blend by right-clicking a JoySelector, selecting Edit > Template > Create New, drawing the Ellipse, Path, and ComboBox using the drawing tools, and selecting the ComboBox binding and style from the Properties window.
Data templates
In Cocoa if you want a list or tree of items of various types, such as an equipment inventory in a game or a list of various types of accounts (investment, money market, savings), you pretty much have to code it all yourself. In WPF / NET you can use DataTemplates.
For example, if every weapon has a “hit strength” and a “defense strength” you might include a data template like this:
<DataTemplate TargetType="game:Weapon">
<DockPanel TextElement.FontWeight="Bold">
<Image Source="{StaticResource WeaponDrawing}" />
<TextBlock Text="{Binding WeaponName}" DockPanel.Dock="Top" />
<TextBlock Text="{Binding HitStrength}" Foreground="Red" />
<TextBlock Text="{Binidng DefenseStrength}" Foreground="Blue" />
</DockPanel>
</DataTemplate>
Other game objects would use different templates, then the inventory could be displayed using a ListBox using a WrapPanel to lay them out in reading order. (Note that in WPF, a ListBox doesn’t have to present its items in a vertical list: Any panel can be used.)
This same technique is important in LOB applications: For example, you can have a default representation for an Invoice that is set in an application-wide DataTemplate, so any part of your application that presents lists of Invoices will automatically display them in the default format. This might include an icon, the invoice number, a tooltip popup with additional information, and a context menu that allows the invoice to be opened and/or edited.
Triggers and animations
In Cocoa you can do animations, but must write code both to create the animation and to apply the animation. In WPF you can define the animation using a timeline in Expression Blend, and set EventTriggers and PropertyTriggers in the view to control when it runs. To create an animation that shakes a button, just right-click to create a timeline, set the button’s position, rotation or scale using the mouse at a few points on the time line, and change the automatically-created EventTrigger to the event you want to trigger the button.
Cocoa has no animation property store or coercion mechanism, so any changes made by the animation are permanent: You can’t remove the animation and have the property values revert. Also you cannot animate properties of shared resources (such as brush colors) without manually copying them, and you can’t animate to out-of-range values and have the control itself coerce to the appropriate value. In WPF the animation system has the ability to keep track of animation values, bound values, default values and coerced values separately so you don’t run into these problems.
In WPF you can set animations to run on UI events like button clicks, property state changes (including data changes in the model), events generated by the model, to run continuously, or via code.
In WPF you can create custom animation classes and use these with Expression Blend as if they were part of WPF. You can also draw the Geometry objects used by the built-in PathAnimation rather than coding it yourself.
Note that WPF has the ability to construct and start animations in code if you really want to. Also note that embedding an animation from a separate application such as Quartz Composer, is not the same thing as animating properties of UI objects. Both Cocoa and WPF can embed animations created with other technologies but with WPF you can use Expression Blend to create a timeline that animates any part of your UI.
Conversions as part of binding
Cocoa has the ability to do conversions to and from from a single value using a NSFormatter. Anything more complicated must be done in the controller. In WPF you can use a StringFormat for the simple cases Cocoa’s built-in NSFormatters cover, but you can also specify an IValueConverter or IMultiValueConverter to implement custom conversion of values. For example, you can add a custom converter to a bar chart data series to cause the data items in the bar chart to animate to their target values in rapid sequence (known as a “jelly” animation). WPF’s converters can be used one-way or two-way and can convert a single value or multiple values.
Conversions also allow you to bind to multiple properties or calculations and to format the result, for example:
<TextBlock Text="{edf:Binding (Height + Width)/2, StringFormat=0.000}" />
This sort of binding with conversion is not possible in Cocoa.
Third party controls
In Cocoa you can generally only include UI widgets designed for Cocoa in your application. In WPF you can include WPF controls but you can also include sections of your UI developed using WinForms, MFC, HTML, Java, Flash, and other technologies. WPF provides facilities for integrating these other technologies directly into WPF, even to the extent of using its markup system to construct the objects and set their properties, for example:
<StackPanel>
<TextBlock>Here is a WinForms control:</TextBlock>
<WindowsFormsHost>
<tools:LegacyChartingControl
Width="20" Height="30"
Title="Graph of something"
SeriesXMin="0"
SeriesXMax="10" ... />
</WindowsFormsHost>
</StackPanel>
Externally-created media
Both Cocoa and WPF can include media such as videos, animations, and bitmaps that have been created in third-party tools. Each environment supports all such media types supported by the underlying operating system. WPF provides a bit more than Cocoa in terms of controlling the media, for example you if you set a button’s command to “MediaCommands.NextTrack” or “MediaCommands.FastForward”, the media will automatically respond appropriately. Also, WPF provides some improvements in the asynchronous loading of media.
WPF (through Silverlight) also supports several high quality video and audio codecs in a fully cross-platform manner so you can rely on your media working on any platform.
There are also tools that allow you to convert drawings created in tools like Illustrator or animations created in tools like Flash into native WPF drawings and animations, allowing you to manipulate and data-bind their properties. For example, you could take a bouncing ball animation created in Flash and data-bind its Y coordinate at apogee so that the ball bounces higher or lower based on the data value in your model.
Garbage collection
As of 2007 garbage collection is finally supported in Cocoa / Obj-C, but many libraries still can’t handle it so most of the Cocoa code being written today is still using manual memory allocation with reference counting. Thus even today you still a lot of “[abc release]” sprinkled throughout Cocoa code! WPF / NET has had garbage collection from day one, so it does not have this problem.
Execution within web browser
Cocoa applications are currently limited to executing as desktop applications, whereas WPF can run just as easily within the web browser as on the desktop, using either XBAP or Silverlight technology.
Cross-platform capability
The story here is similar:
-
Cocoa applications run natively on Mac OS X, and can also run on Windows and Linux by using Cocotron or GNUstep and restricting yourself to a subset of the features.
-
WPF applications run natively on Windows, and can also run on Mac OS X and Linux by using Silverlight and restricting yourself to a subset of the features.
The only significant difference is that Silverlight can run in the browser and has much better vendor support and tooling than Cocotron or GNUstep.
Other advanced capabilities of WPF
So far I have not found any capability in Cocoa that is not also in WPF / NET, but I have found many in WPF / NET that are not in Cocoa, for example:
- All controls such as buttons, textboxes, comboboxes, etc can operate just as well within 3D scenes as within 2D layouts. They can also be arbitrarily stretched, rotated, skewed, etc.
- Advanced drawing capabilities such as PolyBeziers, combined geometries, RenderTransform vs LayoutTransform, alpha transparency control, etc
- Advanced brushes such as gradient brushes, tiled image brushes, and “Visual brushes” which allow you to create an arbitrarily complex brush for painting, for example you can paint a reflection of your window including all its controls.
- Animation subsystem allows practically every property to be animated, for example I animated a TextBox’s “Text” property to make it appear that text was being typed in
Third party algorithms and drivers
Cocoa / Obj-C can call pre-compiled libraries that use C calling conventions and call invoke methods on objects defined in certain other languages. This means that a C-style API is generally required for third-party code that needs to be integrated into your application. WPF / NET can include code written in over 100 languages directly into your application and allows you to access all functionality directly. In addition, it can also call into precompiled code written in other languages using C, C++, COM, DCOM, Web Services, and other calling conventions. In addition, there are open-source shims allowing NET Framework code to call directly into a wide variety of other languages and systems. This means that WPF applications almost never have to include more than a tiny amount of glue code to connect to third party code, including device drivers.
Language comparison
Comparing Objective-C with C# is a major task, and one I will not attempt. Suffice it to say that as of version 4.0, C# contains all the features on Objective-C and many, many, many more. I learned Objective-C in 1989 – a long time before C# was even conceived of – and at the time it was an amazingly powerful language. Now when I use it I cringe, especially at the loss of LINQ and Generics.
Try this sort of data transformation in Objective-C:
DataContext =
from lesson in AllLessons
where lesson.Active
groupby lesson.Category into category
select new
{
categoryName = category.Key.Name,
lessonsInCategory =
from lesson in category
select new
{
lesson,
fullName = lesson.ShortName + " " + lesson.Suffix,
priority = rand.Next(10)
}
};
If AllLessons is provided dynamically, you can directly bind this result in WPF (with <ListBox ItemsSource="{Binding}" />
) and have it dynamically update in real time.
When using LINQ with C# you can also do joins, sorting, etc. There is no back-end code to write at all, and Visual Studio’s IntelliSense helps you complete the names of properties, etc as you edit and even underlines your mistakes.
I don’t know of any good comparison between Objective-C and C#, but there is a good comparison between C# and Java on wikipedia that calls out many of C#’s features that are also missing from Objective-C.
Language bindings
Cocoa is not restricted to Objective-C, and WPF is not restricted to C#. Both are accessible from a number of other languages. The difference is that Cocoa is built around Objective-C so that using it from another language can become quite awkward. For example, actions become an Objective-C method call which has very different semantics than Java or other languages. On the other hand, WPF was intentionally designed to not require any special C# features so it could be easily used from other languages. For example, when used with Java (which is lacking true properties), the PropertyDescriptor uses get and set methods instead.
In addition, because it is built on the NET Framework, a WPF application can simultaneously work against objects and libraries coded in multiple languages. This means that if you find a great C++, Haskell or Ruby implementation of an algorithm you can simply use the code without rewriting it into your language of choice. With Cocoa you generally have to rewrite the code as Objective-C or create shim code to call the other language.
Common advantages
Here are several advantages of Cocoa over its competitors that it shares with WPF:
- Rich typography functionality
- Ability to include 3D graphics
- Built in rich text editing including spell checking
- Undo/redo
- Adding functionality to existing classes (categories in Obj-C, attached properties and styles in WPF)
- Easy remoting of method calls
Final notes
When comparing Cocoa to WPF, you should compare Interface Builder with Expression Blend, not with Visual Studio. Visual Studio is fine for writing code, but in my opinion, Expression Blend is the only tool for designing the user interface.
For practical application developement, the main difference between WPF and Cocoa is generally not the more powerful graphics abilities of WPF, since these can be included in a Cocoa application by hand-coding them. The main difference is the data binding and the evolution from model-view-controller to model-view-viewmodel that makes WPF so much more efficient for actually developing applications.
I may have missed a recent Cocoa improvement in the above description since I have not used Cocoa very much recently. If I have been unfair to Cocoa (or to WPF for that matter) in any way, please add a comment and let me know what I missed.