Archive | Delphi RSS feed for this section

Source code from my Skill Sprint session on Objective-C

The nice folks at Embarcadero asked me to do a guest lecture for their series of “Developer Skill Sprints.” During this afternoon’s live session, someone asked for the source code for the example. Here it is:

ObjectiveCSkillSprint.zip

If you haven’t seen the Skill Sprint series yet, head over to http://forms.embarcadero.com/DeveloperSkillSprintsWebinarSeries and sign up to attend these free sessions.

Finally, we’ll be running one more “live” session on the subject tonight at 5pm Pacific. If you’d like to attend a class with “Professor” Jacob, here’s your chance! Register to attend at the URL above.

Read full story · Comments { 0 }

Usertility has recorded 1,000,000 data points!

Just a quick note: This morning at 11:25:06 UTC, Usertility recorded its MILLIONTH data point.

Want to know how people really use your software? Usertility helps Delphi programmers learn how their software is used. Find out more at twodesk.com/usertility.

Read full story · Comments { 0 }

Castalia 2014.6 is now available

I’ve just released Castalia 2014.6, the latest version of my advanced code editor for Delphi programmers.

Order and buy essays cheap!

In the last few weeks, I’ve done a major rewrite of my integration/functional testing system, and written literally hundreds of new tests. This makes Castalia 2014.6 the most thoroughly tested version of Castalia ever!

Here’s a short list of what’s new in Castalia 2014.6:

  • New: Option to ignore the shift key state for code templates. For example, this allows templates to be triggered on both the Space and Shift+Space keys
  • Fixed: Prototype synchronization incorrectly identifies some non-overloaded methods as overloaded
  • Fixed: Prototype synchronization incorrectly removes method directives from interface declarations
  • Fixed: Structural highlighting doesn’t highlight class constructor, class destructor, or class operator methods
  • Fixed: Refactoring hotkey doesn’t work in Delphi 6

Users with a current maintenance subscription can download Castalia 2014.6 right now at subscribe.twodesk.com.

Everyone else can learn more and download a free trial at twodesk.com/castalia.

Read full story · Comments { 0 }

Using OS X APIs directly from Delphi

I spent a good chunk of time last week working on making Usertility work on operating systems other than Windows. The target last week was OS X. In this post, I’ll share a couple of things I learned about working with OS X in Delphi.

Specifically, I’ll talk about using objects directly from the operating system, in order to get access to features that FireMonkey doesn’t directly provide.

Note: This is obviously not cross-platform, since we’re going to be creating platform-specific code. If you’re going to use these techniques in a cross-platform application, you’ll need to rewrite this code for each platform, using $IFDEF to separate code for different platforms. In the case of OS X, you’ll want to enclose the platform-dependent code in {$IF DEFINED(MACOS)}..{$IFEND} pairs.

Rule #1 – The object you have is not the object you want

[Most of] The OS X API is object-oriented, which is cool. The platform API calls often require you to pass an object reference, known as an id in Objective-C parlance. Delphi is also object-oriented, and you can get those OS X objects as Delphi objects pretty easily (I’ll show you how a little below). But here’s the trick: The Delphi object is not the Objective-C id. That will make a little more sense below, but just remember that. If you have an object in Delphi, and you need to pass it to an OS X API, you need to get the id of the object.

With that out of the way, let’s look at doing something common direct from the API: Making an HTTP request.

Our quest: An HTTP request without using Indy

The Indy networking components are included with Delphi XE6, and work in applications created with the FireMonkey framework. Indy is kind of polarizing through, and while many developers use it and are very successful, others prefer not to use it. I’m not making any judgement of Indy, or anyone’s preferences, but for this demo, let’s assume that we want to make an HTTP request without any dependencies other than the operating system.

Step 1: How do we make an HTTP request in OS X?

The first step is figuring out what the OS X APIs would be in the first place. A little web searching leads us to the API docs for NSURLConnection, a class specifically designed for this task.

Looking at the API, we see this list of “tasks:”

NSURLConnection tasks

This is what we Delphi programmers would call the “methods” of the NSURLConnection class. The ones that are prefixed with a ‘-‘ symbol are the “instance” methods, and the ones prefixed with a “+” symbol are the “class” methods.

To keep this simple, we’ll send send a synchronous request, which means that we’re going to send our HTTP request and then wait for a response. (You shouldn’t really do this in your application’s main thread, because it will block your UI. For real-world use, either use a synchronous request in a background thread, or use an asynchronous request). NSURLConnection has a “method” called + sendSynchronousRequest:returningResponse:error:

Let’s look at the documentation for that method:

sendSynchronousRequestThis gives us a little more information:

  • It returns an NSData object
  • It takes 3 parameters:
    • an NSURLRequest, which is in object that represents the URL to load
    • an reference to an NSURLResponse variable, which the method will use as an OUT parameter
    • a reference to an NSError variabls, which the method will use as an OUT parameter. This can be NULL (or nil in Delphi terms)

How do we call this method in Delphi?

To call this class method, we need two things: First, we need a reference to the NSURLConnection class, and second, we need the parameters.

So, here’s the next big idea:

Getting an OS X class reference in Delphi

Many of the OS X classes, including NSURLConnection, are defined in the Macapi.Foundation unit. Add Macapi.Foundation to your uses clause.

If we search Macapi.Foundation.pas for NSURLConnection, we find three apparently useful types:

  • NSURLConnectionClass
  • NSURLConnection
  • TNSURLConnection

We know that we want the sendSynchronousRequest method, and that appears to be defined in NSURLConnectionClass, but NSURLConnectionClass is an interface, and we can’t call class methods on an interface, so how do we get a reference to that interface?

The key here is TNSURLConnection. It’s the “bridge” between the Delphi interfaces that represent the class, and the underlying OS X classes. We can use TNSURLConnection.OCClass to get a reference to NSURLConnectionCass.

IMPORTANT: This is a pattern throughout Delphi. If you want to call a class method on an ObjectiveC class, use T<WhateverTheClassNameIs>.OCClass.callTheMethod(...) (I’m pretty sure OCClass stands for Objective-C Class).

So, we can call TNSURLConnection.OCClass.sendSynchronousRequest(???). We just need to fill in the ???

The first parameter is an NSURLRequest. How do we get one of those?

Getting an OS X Object instance in Delphi

Most Objective-C classes don’t use a traditional constructor the way we’re used to in Delphi. Instead, they often have class methods that return an instance of the class. (If they do use a traditional constructor, it’s actually a pair of methods called alloc and init).

NSURLRequest has a class method +(id)requestWithURL: that returns an NSURLRequest. We’ll use that as our constructor, using the same pattern as above:

//var URLRequest: NSURLRequest
URLRequest := TNSURLRequest.OCClass.requestWithURL(???); //We'll figure out the parameter below

This looks good, but in fact, it’s wrong!

Remember rule #1: The object you want isn’t the object you have. The requestWithURL method returns the id of the Objective-C class. We can’t call Delphi methods on this id. We need the Delphi interface that wraps around this id. Again, TNSURLRequest is the bridge. We can call the wrap method of TNSURLRequest to get the Delphi wrapper interface for the Objective-C id:

URLRequest := TNSURLRequest.Wrap(TNSURLRequest.OCClass.requestWithURL(??)); //This works

IMPORTANT:  This is the other side of the pattern. To get a Delphi interface for an Objective-C class, use T<WhateverTheClassNameIs>.Wrap(ObjC_id);

Of course, now the rabbit hole goes deeper. We need that parameter to requestWithURL, which is an NSURL.

(At this point, we start to get a little frustrated: I just want to give it a string with a URL and get back the data at that URL! Never fear; we’re almost there.)

Looking at the API docs for NSURL, we find a glimmer of hope: NSURL has a class method +(id)URLWithString:. Hopefully that will let us create a url from our string and finally put this all together to get a result.

And indeed, we can. First attempt:

//var URL: NSURL
URL := TNSUrl.Wrap(TNSURL.OCClass.URLWithString('http://www.twodesk.com'));

This almost works, except it doesn’t compile. There’s an error “There is no overloaded version of URLWithString that can be called with these arguments.”

Remember rule #1 again. URLWithString takes an NSString, and we’re trying to pass it a Delphi string. The object we have is not the object we want. Thankfully, there’s a simple utility method to convert a Delphi string into an NSString object. It’s in the Macapi.Helpers unit, and it’s called StrToNSStr:

URL := TNSURL.Wrap(TNSURL.OCClass.URLWithString(StrToNSStr('http://www.twodesk.com')));

Finally! We have a URL object. Let’s put it all together:

var
  URL: NSURL;
  URLRequest: NSURLRequest;
  Data: NSData;
  Response: Pointer;
begin
  URL := TNSURL.Wrap(TNSURL.OCClass.URLWithString(
    StrToNSStr('http://www.twodesk.com')));
  URLRequest := TNSURLRequest.Wrap(TNSURLRequest.OCClass.requestWithURL(URL));
  Data := TNSURLConnection.OCClass.sendSynchronousRequest(URLRequest, @Response,
      nil);
  //Do something with the data
end;

The last step is to do something with the data:

Using NSData

NSData is a general-purpose class for representing any generic data. Its two most important members are NSData.bytes, which is a pointer to the actual data, and NSData.length, which is the size of the data in bytes.

In the case of an NSData object returned by TNSURLConnection in the example above, bytes is UTF-8 encoded text. This means we can directly access the bytes as a PAnsiChar in Delphi:

//var S: string
S := PAnsiChar(Data.bytes);

Put it all together

I created a FireMonkey HD Desktop app, and put a TButton (Button1) and TMemo (Memo1) on the form. Then, I changed the target platform to OS X (If you don’t change the target platform, none of the platform-specific code will compile). Here’s the code for the Button1 click event:

procedure TForm1.Button1Click(Sender: TObject);
var
  URL: NSURL;
  URLRequest: NSURLRequest;
  Data: NSData;
  Response: Pointer;
begin
  URL := TNSURL.Wrap(TNSURL.OCClass.URLWithString(
    StrToNSStr('http://www.twodesk.com')));
  URLRequest := TNSURLRequest.Wrap(TNSURLRequest.OCClass.requestWithURL(URL));
  Data := TNSURLConnection.OCClass.sendSynchronousRequest(URLRequest, @Response,
      nil);
  Memo1.Lines.Text := PAnsiChar(Data.bytes);
end;

Recap

To get direct access to the static methods of an Objective-C class in Delphi: T<ObjCClassName>.OCClass.<StaticMethodName>

To get a Delphi interface to an instance of an Objective-C class: T<ObjCClassName>.Wrap(<ObjC_id>)

(We didn’t use this in the code above, but for the sake of completeness) To get the Objective-C id from a Delphi interface: (<DelphiInterface as ILocalObject).GetObjectID

To convert a Delphi string into an NSStringObject: StrToNSStr(<DelphiString>) //In the Macapi.Helpers unit

Read full story · Comments { 0 }

New features in Usertility: Sortable tables and raw event counts

Last week, I pushed out a few updates to the Usertility web interface to help you better learn how people use your software. If you haven’t looked at Usertility in the last few days, you should check out the changes:

Sortable tables

Sorted OS VersionsBefore this update, data tables in Usertility were always sorted by the metric being measured. For example, if you were looking at the number of users using a particular operating system, it would be sorted from most popular to least popular.

Now, you can sort the tables however you like. So you could sort by user count, session count, OS version, etc….

Sorting is simple, just click the arrows in the header of the table. To sort by multiple columns, hold down the Shift key while clicking additional columns.

Raw event counts

In the Advanced Analysis tab of Usertility, I’ve added a new metric: Event count.

Prior to this update, you could view the number of Users or Sessions that triggered a particular event, but not the actual number of times the event had taken place. This update adds that ability, so you can now see the actual number of times that the event occured.

Advanced Analysis Event Count

Come check out the new features and learn how people really use your software at twodesk.com/usertility.

 

Read full story · Comments { 0 }

For programmers, by a programmer

Hi. My name is Jacob, and I'm the creator of Castalia.

I starting programming in 1986, learning Lightspeed Pascal on a Mac Classic. Today, I'm a professional programmer, teacher, and entrepreneur.

I have a Master's Degree in Computer Science, and I still love Pascal and Delphi.

I believe that writing code is the heart and soul of software development, and I love helping programmers write code more effectively.