Developing with Objective Pascal

Part 6: Introduction to iOS for Delphi Developers


Contents

Introduction
Doesn't Have
Does Have
iOS Simulator
Pascal Language
Runtime Library (RTL)
Free Component Library (FCL)
The Xcode Way vs. the Delphi Way


Introduction

In many ways, OS X has more in common with Windows than iOS has with either. These notes describe some of the ways that iOS differs from a desktop operating system and how you can address some of those differences when programming in Pascal.

Tip: If you've never developed for OS X or iOS before, you may find the previous articles in this series helpful. The complete list of articles is here. You can ignore most of the discussion of designing the user interface in Xcode since you'll be doing that in Delphi as usual.


Doesn't Have

Here's a list of some things that you will not find on iOS:


Does Have

Here's a list of some things that you will find on iOS:


iOS Simulator

You'll need a Mac to develop for iOS, but you do not need an actual iOS device to get started since Xcode includes iOS Simulator that you can use to simulate various iOS devices and versions.

Remember that iOS Simulator is a simulator, not an emulator. It does not emulate the ARM instruction set, but rather executes apps that have been compiled for x86 just like normal OS X apps. These apps are linked against x86 versions of the iOS frameworks rather than against ARM versions.

As a result, how an app operates under the Simulator can differ from how it operates on an actual device. This means you need to test on an actual device before deploying your app or submitting it to the App Store. However, the benefit of a simulator is speed - if you've ever developed for Android, you know that the Android emulator is almost useless because it's so slow.

Here are some things to watch out for when using the Simulator:


Pascal Language

Because you'll be using Free Pascal with Delphi XE2 to compile for both iOS Simulator and iOS devices, be aware that there are a few differences in language features between Free Pascal and Delphi. In general, these are either newish Delphi language features not yet supported by Free Pascal or somewhat esoteric features that you might not even have known about, much less ever used.

Here's a list of features not yet supported in the current stable version of Free Pascal (2.4.4):

http://wiki.freepascal.org/delphi_language_features_which_fpc_does_not_have

However, since presumably you'll be using version 2.5.1, some of these features should be available, as described here:

http://wiki.freepascal.org/FPC_New_Features_Trunk

Free Pascal supports UnicodeString, but string is still AnsiString. WideString is also available.

Objective Pascal

Free Pascal 2.5.1 supports an optional syntax extension that allows you to work with Objective C classes in Pascal on OS X and iOS. The primary use for this is to work with Objective C frameworks such as Foundation directly in Pascal. For example, you might want to use the Foundation framework's NSString class, which fully supports Unicode. More information about Objective Pascal is here:

http://wiki.freepascal.org/FPC_PasCocoa

A list of Objective C classes available with the Foundation framework on iOS is here.


Runtime Library (RTL)

You may not need to use the Objective C frameworks much for basic tasks. The units included with Free Pascal and Delphi should insulate you from much of the underlying system. To start, Free Pascal includes many of the standard non-UI runtime units that you use in any Delphi application, including the following:

You use these units the same as you do in Delphi and they should work on iOS the same as they do on Windows.

Presumably Delphi XE2 will include the IOUtils unit for iOS. This unit should make working with some aspects of the iOS file system easier. For example, to obtain the path to your app's temporary directory (tmp in the app's home directory), in Objective C you would use the Foundation framework's NSTemporaryDirectory function, as illustrated in this snippet of Objective Pascal code:

  var
    tmpDir : NSString;
  begin
    tmpDir := NSTemporaryDirectory;
To use tmpDir with the Pascal RTL, you would first need to convert it to an AnsiString. Part 5 introduced the NSHelpers unit that provides some basic string conversion routines for doing just that. However, if we assume the presence of the IOUtils unit, then presumably you could just do this instead:

  var
    tmpDir : string;
  begin
    tmpDir := TPath.GetTempPath;
More problematic is obtaining the path to your app's Documents directory. In Objective Pascal, you would use a somewhat awkward construction like this:

  var
    paths  : NSArray;
    docDir : NSString;
  begin
    paths := NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True);
    docDir := paths.objectAtIndex(0);
So what's the RTL equivalent? Well, presumably you could do something like this using IOUtils, although this code assumes both the name and relative location of the Documents subdirectory within the app home directory:
  var
    docDir : string;
  begin
    docDir := TPath.GetHomePath + TPath.DirectorySeparatorChar + 'Documents';
In some cases you may be forced to use the Foundation framework if a Pascal RTL equivalent is not provided. For example, an iOS app's home directory includes a Preferences subdirectory. You never write directly to Preferences, though. Instead you use the NSUserDefaults class to read and write user preferences and to save and restore your app's state. You can also use the CFPreferences unit, since this calls a C library in the older CoreFoundation framework and doesn't require Objective C. (The Foundation framework is mostly Objective C wrappers around CoreFoundation functions - that is, Foundation turns these C functions into Objective C classes.)


Free Component Library (FCL)

Free Pascal includes an extensive collection of additional units known as the Free Component Library (FCL). Many of these units have no counterpart in Delphi's standard units and, where they do, they're generally not compatible with Delphi's. If you use any of these units, you'll probably be tying your code, or at least a portion of it, to Free Pascal. With that in mind, however, you may find some of these units to be extremely useful, particularly on iOS. And it may also encourage you to divide your code into units that can easily be swapped out on other platforms.

For example, FCL includes units for working with XML files in a normal tree-oriented DOM fashion. The Objective C Foundation framework includes the NSXMLParser class, but this is an event-drive parser, designed for speed and minimal memory use, and you may not find it very useful. However, if you use the FCL XML units, you won't be able to compile your XML-handling code with Delphi.

For example, to load an XML file with the FCL XML units, you might do something like this:

  var
    XmlDoc : TXMLDocument;
  begin
    ReadXmlFile(XmlDoc, FileName);
In contrast, with Delphi you might write it like this:

  var
    XmlDoc : IXMLDocument;
  begin
    XmlDoc := TXMLDocument.Create(nil);
    XmlDoc.FileName := FileName;
FCL also includes units for working with SQLite databases. Every Mac and iOS device includes the SQLite library and since it's a normal C library, you don't need Objective C to use it, just the FCL sqlite3 and SQLite3db units.

For example, if your iOS app included a SQLite version of the FishFact database, you could open and query it like this:

  var
    DbFileName : string;
    SqliteDb   : TSQLite;
    FishName   : string;
    QryResult  : TStringList;
  begin
    DbFileName := 'biolife.sqlitedb';  //add appropriate path
    SqliteDb := TSQLite.Create(DbFileName);
    try  //assuming SqliteDb.LastError=SQLITE_OK
      FishName := 'Clown Triggerfish';
      QryResult := TStringList.Create;
      if SqliteDb.Query('SELECT "Species Name" FROM BIOLIFE WHERE Common_Name = "' +
                        FishName + '";', QryResult) then
        begin
        // do something with QryResult.Strings[1]
        end;
    finally
      QryResult.Free;
      SqliteDb.Free;
      end;

The Xcode Way vs. the Delphi Way

The gold standard for iOS development is Xcode, Objective C, and direct use of Cocoa Touch frameworks. However, many Delphi developers are likely to find this approach alien, if not downright repellent, particularly when designing an app's user interface.

Parts 1-5 of this series present an approach that substitutes Objective Pascal for Objective C, but otherwise uses Xcode and Cocoa Touch in essentially the same way as they are used in Objective C development. However, because Pascal is not integrated into the Xcode IDE, this approach requires some fairly awkward compromises. For example, since the only way to wire "connections" between the user interface layout and code in Xcode is via Objective C header files, an Objective Pascal Xcode project requires "placeholder" Objective C files which are not otherwise needed.

Delphi XE2 would appear to provide a reasonable "third way", moving user interface design and code editing out of Xcode (and off the Mac entirely) and into a Windows-hosted IDE that Delphi developers should find familiar, relegating Xcode to the final build step. To be sure, this approach comes with its own bit of awkwardness (flipping between Windows and OS X), but provides cross-platform opportunities that would not be possible with an Xcode-only approach.

However, there are some things that will probably require Xcode or direct access to Objective C frameworks. These range from the straightforward to the complex and the question is whether and how Delphi itself will address them.

For example, on both OS X and iOS, an app's Info.plist file controls many aspects of the app's behavior and is used to set the app's version, copyright statement, file associations, etc. While this is just an XML file, using the Xcode property list editor to set these things (rather than doing it on the Delphi side) would seem logical. One small example: To include a custom font file with an iOS app, you just add the name of the font to the UIAppFonts array in the Info.plist file and add the font .ttf file to your Xcode project. When Xcode builds your app, it will copy the font file into the app bundle automatically. It would seem rather pointless to duplicate this iOS-specific setting in a Windows-hosted IDE where it has no cross-platform correspondence.

A bigger challenge is accessing device-specific functionality. Will this be done via the iOS Objective C frameworks (perhaps accessed via Objective Pascal syntax) or in a cross-platform way? PhoneGap shows that a great deal of mobile functionality can be supported in a cross-platform fashion, even for JavaScript, so perhaps a cross-platform library for mobile will emerge eventually for Delphi too.

For example, to add a Google map to an iOS app in Xcode, you use the MapKit framework: Just drop an MKMapView onto a view, make a connection for it (in this case, myMap), then add code like this to display the map:

  var
    region : MKCoordinateRegion;
  begin
    region.center.latitude := myLatitude;
    region.center.longitude := myLongitude;
    region.span.latitudeDelta := 0.02;
    region.span.longitudeDelta := 0.02;
    myMap.setRegion(region);
    myMap.setMapType(MKMapTypeHybrid);
Most mobile platforms support mapping, so it's not hard to imagine a cross-platform Pascal library that supports, say, both Google and Bing maps.


Copyright 2011 by Phil Hess.

macpgmr (at) fastermac (dot) net

First posted Aug. 7, 2011.