Delphi to Cocoa

July 9, 2009

Bootstrapping an iPhone Application

Filed under: iPhone — rithban @ 10:24 pm
Tags: , , , ,

The Way It Was

To bootstrap a GUI program in Delphi, you use the global Application object instance. It provides the core event-driven framework for a Microsoft Windows application. If you look at the source code of a new application as found in the .dpr file, you’ll see code like:

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;

Delphi did a lot of work for the programmer in automatically creating a TForm subclass including the visual object resources (in the .dfm file) as well as the bootstrapping code.

If you wanted to be hard core, you could discard the default form subclass, instantiate a raw TForm and attach it to the Application global instance. But two of the three lines in the code wouldn’t change. You must still call

Application.Initialize

Do something to create a main form.

Application.Run

.

Raw Bootstrapping an iPhone Application

iPhone applications require a little more setup, but XCode pretty much does the same thing for the developer. It creates a default window and it Interface Builder resource file similar to how Delphi would create a default TForm subclass and its .dfm file.

As with everything, bootstrapping an iPhone application from scratch is a little more involved than how it use to be with Delphi… but it’s not really difficult.

main.m

As with all C-derived languages, main() is the program entry point called by the operating system.

Here is what the default main.m source file looks like.

#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {
    
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

As you can see, main() sets up the autorelease pool then disappears into UIApplicationMain() and never returns until the application terminates. In fact Apple’s documentation states that either this function returns 0 (success), or the program dies unceremoniously. That seems rather extreme to never return with an error, but that’s how the software is designed.

The Application Delegate

The application delegate is a class that handles setup and tear down of the application. It’s loosely related to Delphi’s TApplication.

When bootstrapping an application, UIApplicationMain() will look in the application’s plist (configuration file) so it knows which which application delegate to hand control over to. If you’re manually bootstrapping the application, that information will not be in the application plist. You’ll need to pass the name of the application delegate class as the fourth parameter to UIApplicationMain(), for example.

int retVal = UIApplicationMain(argc, argv, nil, @"Project1AppDelegate");

UIApplicationMain() will instantiate the application delegate class, then invoke its applicationDidFinishLaunching() method. This method will initialize the GUI, similar to what

  Application.CreateForm(TForm1, Form1);

did, but things are in different places. If interface builder is used to create the window, the application delegate will have an IBOutlet property for the window.

This article is bootstrapping a do-nothing application from scratch, so the application delegate will also contain the view instance. For example,

#import <UIKit/UIKit.h>

@interface Project1AppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UIView *view;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

The applicationDidFinishLaunching() method implementation may look like:

#import "Project1AppDelegate.h"

@implementation Project1AppDelegate

@synthesize window;


- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    
    // Get size of application frame
    CGRect lFrame = [[UIScreen mainScreen] applicationFrame];
    
    // Create main window
    self.window = [[UIWindow alloc] initWithFrame: lFrame]; 
    
    // Create main view for window
    lFrame.origin.y = 0.0;
    view = [[UIView alloc] initWithFrame: lFrame];
    
    // Attach view to window
    [window addSubview: view];

    // TForm.Show
    [window makeKeyAndVisible];
}


- (void)dealloc {
    [view release];
    [window release];
    [super dealloc];
}


@end

At this point, the application has been successfully bootstrapped, and the main event handler loop is running. Thus, this is similar to the Delphi Application.Run.

Bootstrapping an iPhone Application

Filed under: iPhone — rithban @ 10:10 pm
Tags: , , , ,

The Way It Was

To bootstrap a GUI program in Delphi, you use the global Application object instance. It provides the core event-driven framework for a Microsoft Windows application. If you look at the source code of a new application as found in the .dpr file, you’ll see code like:

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;

Delphi did a lot of work for the programmer in automatically creating a TForm subclass including the visual object resources (in the .dfm file) as well as the bootstrapping code.

If you wanted to be hard core, you could discard the default form subclass, instantiate a raw TForm and attach it to the Application global instance. But two of the three lines in the code wouldn’t change. You must still call

Application.Initialize

Do something to create a main form.

Application.Run

Raw Bootstrapping an iPhone Application

iPhone applications require a little more setup, but XCode pretty much does the same thing for the developer. It creates a default window and it Interface Builder resource file similar to how Delphi would create a default TForm subclass and its .dfm file.

As with everything, bootstrapping an iPhone application from scratch is a little more involved than how it use to be with Delphi… but it’s not really difficult.

main.m

As with all C-derived languages, main() is the program entry point called by the operating system.

Here is what the default main.m source file looks like.

#import 

int main(int argc, char *argv[]) {
    
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

As you can see, main() sets up the autorelease pool then disappears into UIApplicationMain() and never returns until the application terminates. In fact Apple’s documentation states that either this function returns 0 (success), or the program dies unceremoniously. That seems rather extreme to never return with an error, but that’s how the software is designed.

The Application Delegate

The application delegate is a class that handles setup and tear down of the application. It’s loosely related to Delphi’s TApplication.

When bootstrapping an application, UIApplicationMain() will look in the application’s plist (configuration file) so it knows which which application delegate to hand control over to. If you’re manually bootstrapping the application, that information will not be in the application plist. You’ll need to pass the name of the application delegate class as the fourth parameter to UIApplicationMain(), for example,

int retVal = UIApplicationMain(argc, argv, nil, @"Project1AppDelegate");

UIApplicationMain() will instantiate the application delegate class, then invoke its applicationDidFinishLaunching() method. This method will initialize the GUI, similar to what

  Application.CreateForm(TForm1, Form1);

did, but things are in different places. If interface builder is used to create the window, the application delegate will have an IBOutlet property for the window.

This article is bootstrapping a do-nothing application from scratch, so the application delegate will also contain the view instance. For example,

#import 

@interface Project1AppDelegate : NSObject  {
    UIWindow *window;
    UIView *view;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

The applicationDidFinishLaunching() method implementation may look like:

#import "Project1AppDelegate.h"

@implementation Project1AppDelegate

@synthesize window;


- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    
    // Get size of application frame
    CGRect lFrame = [[UIScreen mainScreen] applicationFrame];
    
    // Create main window
    self.window = [[UIWindow alloc] initWithFrame: lFrame]; 
    
    // Create main view for window
    lFrame.origin.y = 0.0;
    view = [[UIView alloc] initWithFrame: lFrame];
    
    // Attach view to window
    [window addSubview: view];

    // TForm.Show
    [window makeKeyAndVisible];
}


- (void)dealloc {
    [view release];
    [window release];
    [super dealloc];
}


@end

At this point, the application has been successfully bootstrapped, and the main event handler loop is running. Thus, this is similar to the Delphi Application.Run.

Anatomy of an iPhone Application Window

Filed under: conceptual,iPhone,objects — rithban @ 12:46 am
Tags: , , , ,

An iPhone application window doesn’t have the convenient TForm found in the Delphi VCL. This article explains the constituent parts.

Frame

A frame is a rectangular region of pixels on the screen. It is represented by a CGRect struct, analogous to the Delphi TRect.

More details can be found here.

Screen Area

iPhone applications typically use most of the screen. One can get the frame for the entire screen by:

CGRect frame = [[UIScreen mainScreen] bounds];

However, this includes the status bar. The application frame, which excludes the status bar, by:

CGRect frame = [[UIScreen mainScreen] applicationFrame];

Window

A window is the low-level support needed to make use of a frame. In this context, a frame is nothing more than an idea but a window is an actual object instance that can be put to use. By itself a window isn’t very useful, but it’s the object upon which a GUI can be built.

When instantiating a window object, you provide a frame to define its boundaries. Note that the origin of the window’s frame is an offset relative to the screen.

UIWindow window = [[UIWindow alloc] initWithFrame: frame];

View

A view is the base visual component, from which visual components are built. It is conceptually analogous to the Delphi TControl.

As with a window, we use a frame to define the size of the view. Note that the origin of the view’s frame is an offset relative to the window.

UIView view = [[UIView alloc] initWithFrame: frame];

The Delphi TForm

The old Delphi TForm class is conceptually a window and view paired together. You could manually instantiate a TForm class and make it visible by

lForm := TForm.Create(nil);
lForm.Show;

The rough iPhone equivalent consists of the following steps.

  1. Get the application frame
  2. Instantiate a UIWindow using that frame.
  3. Set the frame’s origin to (0,0).
  4. Instantiate a UIView object using the modified frame.
  5. Add the view to the window.
  6. Cause the window to be shown.

Thus, one could use code similar to this:

    // Get size of application frame
    CGRect frame = [[UIScreen mainScreen] applicationFrame];
    
    // Create main window
    UIWindow window = [[UIWindow alloc] initWithFrame: frame]; 
    
    // Create main view for window
    frame.origin.y = 0.0;
    UIView view = [[UIView alloc] initWithFrame: frame];
    
    // Attach view to window
    [window addSubview: view];

    // TForm.Show
    [window makeKeyAndVisible];

TRect vs. CGRect

Filed under: objects — rithban @ 12:10 am
Tags: , , , ,

CGRect corresponds to TRect, with the exception that the coordinates are floating-point values rather than integers.

The Objective C struct also does not support renaming like Delphi variant records, so the contents are organized as CGPoint and CGSize.

Nevertheless, CGRect is for all intents and purposes a TRect, as evidenced by the following brain-dead code:

CGRect lRect;

lRect.origin.x = 0.0;
lRect.origin.y = 0.0;
lRect.size.width = 100.0;
lRect.size.height = 100.0;

January 21, 2008

Loose Coupling Between Tools

Filed under: dev tools — rithban @ 3:24 pm
Tags: , , ,

The things that continues to trip me up is the same thing that appears to trip up other Delphi developers who move to Mac development with XCode: the loose coupling between developer tools, specifically XCode and Interface Builder.

In Delphi, when one creates a new form, the IDE creates both the source file and the DFM file. The DFM is analogous to the XCode NIB file. As one adds, removes, moves, or otherwise manipulates controls on the form at design time, the IDE automatically maintains the relationships between the form’s class and the DFM file. When the application runs, the libraries automatically create the UI elements from the DFM file and establish their relationship to the form’s class.

The downside, I am told, is that every control on a window has an equivalent of XCode’s IBOutlet in the class definition; therefore there may be a few extra bytes “wasted” for every object reference that is not actually used. Why this is a negative thing I’ve never understood.

In XCode, one must manually establish and maintain all of those relationships. I can’t accept the premise that this is a hard thing to do. This is not rocket science. Borland did it back in 1991(?).

I also find specious the argument that one would “lose too much control”. At least, to date nobody has been able to articulate exactly what control one is losing, and how it’s a typical scenario that would justify subverting the grand gains in productivity that tighter integration between XCode and Interface Builder would bring. At least make it an option!

Next I’ll delve into the details more. If I can explain it, I know that I understand it. If I’m going to explain it, others might as well benefit from that sharing.

December 25, 2007

Basic Terminology and Concepts

Filed under: conceptual,objects — rithban @ 12:39 am
Tags: , ,

I’ve created a page to hold general notes about terminology. Being computer languages, the concepts are same. How the concepts are approached and labeled are different, of course.

December 21, 2007

Object Lifetime Management in Objective-C

Why am I starting with this subject? This topic wasn’t immediately intuitive and required some digging… plus it’s a vital subject. Thoroughly understanding how a language handles object lifetime management (OLM) is a “must” for any software engineer. The biggest, most obvious benefit is allowing one to write code without memory leaks or distractions. What I mean by distractions is mental effort taken away from addressing the problem at hand and putting it towards something as trivial as actually writing the code. Ideas should flow out of the brain, through the fingers, and onto the keyboard without worrying about routine things like object instantiation and destruction.

Note that the official documentation must be referred to for details. These are only notes.

OLM and Delphi

The Delphi language presents the programmer with two mechanisms. The basic mechanism is wholly manual: explicitly allocating and freeing an object. You, the programmer get to do all the work. This was the original paradigm for objects when the language first supported them.

var
  lFoo :TFoo;
begin
  lFoo := TFoo.Create;
  try
  ... work with object ... 
  finally
    lFoo.Free;
  end;
end;

The second mechanism the Delphi language presents is using interfaces and reference counting. Interfaces were added to the language later, I believe with Delphi 2. There’s some great syntactic sugar in the compiler that almost allows one to forget about OLM once an object instance has been tied to an interface. The compiler generates code to implicitly call _AddRef and _Release automatically. I say almost because while it correctly addresses >99% of OLM, there are time where it’s beneficial to circumvent the default behavior.

var
  lFoo :IFoo;
begin
  lFoo := TFoo.Create;
  ... work with object ... 
end;

In Delphi, to take advantage of interfaces, one must use classes properly equipped to support them. Ordinarily one will descend from TInterfacedObject to pick up this behavior. The root object, TObject, has no capability to work with interfaces or reference counting. This is inconvenient sometimes, but interfaces and reference-counted OLM were later additions to the language.

OLM and Objective-C

Objective-C has a different history. Its intent from the start was to extend C, giving it object-oriented capabilities. Reference-counted OLM is part of the paradigm from the ground up. Its root object, NSObject, supports reference counting. As a result this is passed to every other object.

I found a great explanation of things here. Consider it required reading. The rest are just my re-interpretation of some of the concepts in that document that I find important to remember. In other words, they stand out as important divergences from Delphi.

So what do we have thus far?

Concept Delphi Objective-C
Reference Counting Class Objects (typically) descending from TInterfacedObject and bound to an interface. All objects.*

Increment Reference Count _AddRef (normally called implicitly) retain
Decrement Reference Count _Release (normally called implicitly) release
Reference Counts Maintained automatically manually

*All objects descend from the class NSObject — the Objective-C equivalent of TObject.

So, some good news and some bad news. We gain reference counting in all objects, but lose the automatic maintenance of the reference counts. So how do we maintain the reference counts? By adhering to a set of rules, and a little glue. First the rules. They’re similar in spirit to the original Delphi OLM.

.

If Then Therefore
If you allocate it… you own it, therefore you must call release.
If you didn’t allocate it… you don’t own it, therefore you must not call release.
If you didn’t allocate it… but you want to keep it around, you must call retain and release at the appropriate times.

Note that the “appropriate times” are the same times that one might manually call _AddRef() and _Release() in Delphi to keep a reference-counted object around (without using interfaces).

The specific rules are summarized here. Note that there are conventions for method naming that should be adhered to to avoid problems later.

Autorelease Pools

There are cases where reference counting can be a bit tricky. In Delphi these are ordinarily hidden from view through compiler magic. In Objective-C there’s an interesting work-around: autorelease pools. (See link for official documentation.) The autorelease pools are a stack-oriented hierarchy of object-specific memory pools to which objects may be attached. One attaches objects to them to keep them around for disposal at a future time. When one of these pools are released, all objects with a zero reference count are freed, and all other objects are moved to the next pool in the stack.

One can use (in interesting ways) autorelease pools to manage when autorelease objects are released.

Summary

  1. You own the object if you call alloc*, new*, or *[Cc]opy*. Be sure to call release.
  2. If you otherwise received an object, autorelease has already been called on it, pushing onto the autorelease pool. It is safe to use in your scope (as the caller).
  3. If you wish to keep a handle to an object “otherwise received” (see #2), call retain. When appropriate, dispose of the handle via release or autorelease as appropriate.

Blog at WordPress.com.