DX.Library : Utility functions for iOS (and other platforms) available via SVN

I just created a DX.Library SubVersion repository at Google and uploaded our DX.Apple.Utils.pas unit as first action.

As a start three functions are available:

Note: there is a dependency to Apple.Utils.pas (and later maybe to other units in the same directory), which ships with XE4, but is NOT in the default library path. That unit can usually be found here:
C:\Users\Public\Documents\RADStudio\11.0\Samples\Delphi\RTL\CrossPlatform Utils
///	<summary>
///	  Logs to the console
///	</summary>

procedure NSLog2(const AMessage: string);

/// <summary>
/// Retrieves the vendor specific device ID - DO NOT USE UIDevice.uniqueIdentifier - this would lead to AppStore rejection since May 1st, 2013!
/// </summary>
function VendorIdentifier: string;

/// <summary>
/// checks if the given URL can be openend by any App on the device
/// This is for custom URL schemes like fb://profile/omonien, which would open
/// the Facebook app - if installed on the device - and navigate to the given profile
/// </summary>
function CanOpenURL(AURL: string): boolean;

Contributions are welcome. All code is licensed under The MIT License.

Posted in Miscellaneous | Leave a comment

iOS OpenURL – Not just for HTTP URLs

Anders just recently blogged about how to open Safari from your iOS Delphi app and showed how to incorporate Cleggy’s Apple.Utils.pas unit to make it just as simple as:

OpenURL(‘http://www.embaracdero.com’);

The interesting point is now, that this would also work for other apps. If you want to open the iPhone Messenger for example, then just do this:

OpenURL(‘sms:1-408-555-1212′);

This also works with 3rd party Apps, you can open the Facebook app like this:

OpenURL(‘fb://profile’);

But what if the App is not installed or not available (like on the iOS simulator)? OpenURL will do just nothing, which is kind of stupid, you might want to do something as alternative probably.

For that reason there is CanOpenURL (which is not yet in Cleggy’s unit). That just returns true or false indicating if the required app is available. This is how you would implement/call it -

Update: CanOpenURL is now in DX.Library

uses

Apple.Utils;
function CanOpenURL(AURL: string):boolean;
begin
 result := SharedApplication.canOpenURL(StringToNSUrl(AURL));
end;

Here are a couple of links where you find information about available URL schemes:

Posted in Delphi, Development, iOS | Leave a comment

iOS: Identifying Your Users Devices – A Recipe How to Import iOS Classes

You might want to identify your users devices, for example to bind that information to some licensing mechanism. In earlier iOS days, you would have used UIDevice.uniqueIdentifier for that. That ID is unique for every iOS device out in the wild (well maybe except jail broken ones). Due to privacy concerns usage of that ID has been deprecated with iOS 5.0, and since May 1st, 2013 Apple imposes a no-usage policy. In other words if you use that id in your apps, apple will just reject your app from App Store  approval.

The new way to identify your users devices is to use UIDevice.identifierForVendor. That is still a unique identifier, but it is also unique per vendor. In other words your Apple Developer Account gets tied into that ID’s calculation, so that your own apps can identify all your users devices, even between apps. Other vendors/developer get different ids for the same device though.

Ok, so far so easy. If you want to use identifierForVendor from Delphi XE4 though, you will find, that it has forgotten to be imported. UIDevice as declared in iOSApi.UIKit.pas just doesn’t know about that function.

This made me try to import it on my own, and that worked pretty easy for me. There was an additional obstacle (the required class NSUUID does also not exist in XE4), but that was also easy to fix.

I started with a DX.Apple.Utils.pas helper unit, which will grow over time and for now does exactly two things:

  • Provide a Delphi NSLog2 function, which directly maps to Apple’s NSLog function, which will log to the console.
  • Provide a VendorIdentifier function which does what its name says

The most current version can be checked out anonymously from a SubVersion repository hosted at Google.

Below is the full source, which I will probably put into a public SVN –  eventually. That source basically contains the recipe how to import (even partial) classes from iOS into Delphi.

unit DX.Apple.Utils;

interface

/// <summary>
/// DX.Apple.Utils is a helper library to get easier acces to certain Apple Mac/iOS functions.
/// </summary>
/// <description>
/// This library also imports certain classes or parts of them which have been "forgotten" by EMBT
/// The code is intended to be used with Delphi XE4 only. Other versions may or may not work.
/// There is a dependency to AppleUtils.pas, which ships with XE4 and can usually be founc here:
/// C:\Users\Public\Documents\RAD Studio\11.0\Samples\Delphi\RTL\CrossPlatform Utils
/// Make sure use the most recent version - that samples folder above
/// is connected to an SVN repository of Embarcadero.
/// </description>
/// <remarks>
/// <para>
/// DX.Apple.Utils is Copyright 2013 Olaf Monien / Developer Experts, LLC.
/// </para>
/// <para>
/// All code comes "as is", without any guaranties granted. This code may contain bugs and my not work as advertised.
/// </para>
/// <para>
/// RESTClient is licensed under Mozilla Public License 2.0
///  In other words you are free to use this library in your projects, just leave this header intact.
/// </para>
/// </remarks>

// Logs to the console
// Named NSLog2 to avoid name clash
// iOS device: Xcode - Organizer -> Device - Console
// Mac / iOS Simulator: Mac - Console
procedure NSLog2(const AMessage: string);

// Retrieves the vendor specific device ID - DO NOT USE UIDevice.uniqueIdentifier - this would lead to AppStore rejection since May 1st, 2013!
function VendorIdentifier: string;

implementation

uses
  System.SysUtils,
  Apple.Utils,
{$IFDEF IOS}
  Macapi.ObjectiveC,
  iOSApi.Foundation,
  iOSApi.UIKit,
  iOSApi.QuartzCore,
  iOSApi.CocoaTypes
{$ELSE}
{$IFDEF MACOS}
  Macapi.ObjectiveC,
  Macapi.Foundation
{$ENDIF MACOS}
{$ENDIF IOS}
    ;

{$IFDEF IOS}

// Hack to import forgotten classes/functions and properties
// Be careful - classes with same name may already exist in iOSApi!!
type

  // **** NSUUID

  NSUUIDClass = interface(NSObjectClass)
    ['{D9518F5E-DDBC-4702-A555-411D32B85340}']
  end;

  // We just need  the UUIDString here
  NSUUID = interface(NSObject)
    ['{4C137FF5-E854-461F-B77E-8CD357FD4E9C}']
    function UUIDString: NSString; cdecl;
  end;

  TNSUUIDDX = class(TOCGenericImport<NSUUIDClass, NSUUID>)
  end;

  // **** UIDevice

  UIDeviceClass = interface(NSObjectClass)
    ['{D5105207-FBA7-4F55-BC7B-1ADACE347ECA}']
    { class } function currentDevice: Pointer; cdecl;
  end;

  UIDevice = interface(NSObject)
    ['{481E431F-2C02-4F2D-86C5-7728480ECF48}']
    function identifierForVendor: NSUUID; cdecl;
  end;

  TUIDeviceDX = class(TOCGenericImport<UIDeviceClass, UIDevice>)
  end;

{$ENDIF}

procedure NSLog2(const AMessage: string);
var
  LMessage: NSString;
begin
  LMessage := NSSTR(FormatDateTime('hh:nn:ss,zzz', now) + ' - ' + AMessage);
  iOSApi.Foundation.NSLog(PtrForObject(LMessage));
end;

{$IFDEF IOS}
function currentDevice: DX.Apple.Utils.UIDevice;
begin
  result := TUIDeviceDX.Wrap(TUIDeviceDX.OCClass.currentDevice);
end;

function VendorIdentifier: string;
var
  LDevice: DX.Apple.Utils.UIDevice;
begin
  LDevice := currentDevice;
  result := NSStringToString(LDevice.identifierForVendor.UUIDString);
end;
{$ENDIF}

end.
Posted in Delphi, Development, iOS | Leave a comment

Objective-C for Delphi users: Property Setters and Getters

Even though Embarcadero did a great job in abstracting the RTL and FireMonkey from iOS specifics in their latest Delphi XE 4 release, there will sometimes be the need to access iOs APIs directly – just like we did with the Windows API.

In contrast to the Win32 API, many iOS APIs (not all though) are object oriented. For example there is a UIView class which is the base class for all visual elements. One other prominent class is NSString, which obviously handles strings. (“NS” btw. originates from “NexXTSTEP”, Steve Job’s Operating System that he developed, before he came back to Apple)

iOS / Objective-C have (like Delphi) a concept of properties, accessing their values is a little uncommon though:

Lets assume we have a Delphi TFoo class, which has a String property name, then you can read and write a Foo’s name like this:

LFoo.Name := 'Joe';
LName := LFoo.Name;

Once you have an instance of an iOS class and you want to access some property, intuitively you would try like this:

var
  LView: UIView;
  LMode: Cardinal;
begin
... //instantiating UI classes will
... //be covered in a later blog post
LMode := LView.ContentMode; //works
LView.ContentMode := UIViewContentModeScaleAspectFit; //Does not work

The compiler will say “nay” though and it looks like we had a read only property here, which is not the case. The point is that Objective-C has a different syntax for properties. Access to a property ALWAYS goes through its corresponding setter and getter methods.

The getter usually has the same name as the property itself. Here we actually call a Getter function ContentMode() :

LMode := LView.ContentMode;

The setter method is usually named like the property with a “set” as prefix and of course needs to be called like a regular method with one value parameter, like this:

  LView.setContentMode(UIViewContentModeScaleAspectFit);

You will find this pattern in basically all iOS classes that have properties.

One might think “why didn’t they add some Delphi magic here?”, but I believe it is better to be close to iOS when accessing their API, so that samples etc from the iOS docs can be applied more directly.

Posted in Miscellaneous | Leave a comment

Delphi samples updated constantly

Since a while the samples that come with Delphi are actually connected to a SubVersion repository of Embaracderos, that is you might want to “update” them from time to with your favorite SVN client.

Samples for Delphi XE4 can usually be found here:

C:\Users\Public\Documents\RAD Studio\11.0\Samples

If you have Tortoise installed, then just right click “Samples” and hit “SVN Update”

Last checkin according to the log is from Monday, April 22nd – and thus not in XE4′s installation ISO. The log reaches back until July 21st, 2010 – so if you like you can track how features evolved over time and made it into the samples ;-)

Bildschirmfoto 2013-05-01 um 13.10.01

Posted in Delphi, Development | Leave a comment

XE4 added to Delphi Version Poll

I just added XE4 to my almost for ever running Delphi Version Poll.

So if you like just check the version you are using most. You can re-vote even if you already voted a while ago and your Delphi version preference changed.

Posted in Delphi, Development | Leave a comment

Entity Framwork and how to solve poor performance on large read-only batches

ORMs such as Entity Framework are great – as long as you don’t forget that there is quite a complex engine under the shiny hood.

I just ran into the situation that EF performed extremely poor while processing large sets of data. It even threw exceptions that indicated that my underlying connection or data reader just closed for no reason.

I a query similar to the one below in a fairly complex batch processing application. Of course you should avoid unlimited select statements on large datasets, but life is not always perfect ;-)

In this particular case I was iterating about 190k data rows. Not too bad, and in LinqPad this performed well enough.

var allCustomers = from c in context.Customer
                   select c;
foreach (var customer in allCustomers) {
    //do something based on some complex criteria
}

In the actual app this basically took forever and actually threw an exception after about 40k records processed. (Note: I am aware that a ToList() would avoid server round-trips, but ToList() showed the same bad performance, which lead me to the code above)

This is only one part of a large batch process, which all works on the same context – which gets saved at the very end of the process.

The point is that most of my queries are used in read-only mode, that is I don’t change any of the customer objects above.  EF doesn’t know about my read-only intention though and associates every single object with its Change Tracker – which will get messy after  thousands of objects being touched.

There are two ways to solve this:

  • Either always use a fresh and empty context for read-only query
  • Or – much better – mark the query as “No Tracking”, this will leave the change tracker alone and the result is a MUCH better performance:

Adding AsNoTracking() as in the code below makes the query run in LinqPad in about 3 seconds compared to about 12 seconds without it.

var x = from s in SubjectGroups.AsNoTracking()
        select s;

int i = 0;
foreach (var y in x) {
  i++;
}
i.Dump();
Posted in .NET, Development | Leave a comment

Use the Power of Delphi Carefully – Please!

Now that EMBT gave us Delphi for iOS, a.k.a. RAD Studio XE4, we got a quite powerful tool (not just) for developing iOS Apps in our hands. Compared to what it takes to get a halfway serious App done in Xcode (yes, we have some successful Xcode’d Apps out in the wild) it is amazing how hast you can get stuff done with Delphi for iOS.

I don’t wanna be a teacher here, but still: If you can do, doesn’t mean you should do!

I the last few days I have seen a few (hopefully early) drafts of applications that were built with Delphi for iOS. Honestly, some of them just look horrible – esp. those made for the iPad. I won’t post links here, as it is still early and I don’t want to intimidate.

The GUI concepts in these Apps have obviously been taken from Windows. With Delphi for iOS you can easily do that – even by using tools that “port” existing Apps to FireMonkey/iOS.

Please! Do not do that! Just because Delphi allows you so and Microsoft does a miserable job in the combination of desktop and mobile UI development, doesn’t mean YOU have to do apply the same mistakes too.

(Re-)Design the UI of your App specifically for the iPhone or iPad!

Take the time and read Apple’s iOS Human Interface Guidelines. It is not really Xcode / Objective-C specific and provides a lot of interesting advise how to design your mobile device UI. Esp. see the part about “Design the App for the Device”

Also check out how other apps work. Find good solutions and bad ones.

If you are looking for ideas how to solve a certain UI problem, then PTTRNS.COM might be helpful. They offer categorized screenshots of many real world Apps. Need to display a list of items? Check for different approaches at lists on pttrns.com

There are about 30 categories on pttrns.com, from “About” over “Empty Data” and “PopOvers” to “Wooden Shelfs” (which is clearly dominated by Apple’s iBooks ;-)

Posted in Delphi, Development, iOS, iPad, iPhone | Leave a comment

ARC: What if I call .Free? Will I get tared and feathered?

Disclaimer: I have been permitted by Embarcadero to officially blog about the next Delphi Version: Delphi XE4 / RAD Studio XE4

Now, in previous posts you learned that ARC releases you from calling Free yourself.

As you don’t have to worry about try-finally-free patterns any more, your code will get much easier to read and understand, as you can focus on business logic and not “technicalities”.

So far so good.

Now you decide to re-use your PlaceNewOrderForCustomer procedure and figure that you if you “cleaned” it from all those “try-fially-free” garbage, that it would massively leak in your Win32 app, which – unfortunately – your customers still want.

Adding in IFDEFs would even make your source even worse:

L := TCustomer.Create;
{$IFNDEF AUTOREFCOUNT}
try
{$ENDIF}

//do something

{$IFNDEF AUTOREFCOUNT}
finally
  L.Free;
end;
{$ENDIF}

So what now?

Well, even though Delphi for iOS is strictly ARC (to my knowledge there is no compiler switch to turn off ARC for mobile targets) , you can still use your “old” patterns. In other words: It is totally legal to call “Free” on an object instance in ARC.

The reason is easy to understand if you look at the implementation of Free under ARC:


procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
 if Self <> nil then
 Destroy;
{$ENDIF}
end;

So it is safe to call free under ARC, as the compiler understands that and simply assigns NIL to the variable where you called Free from.

This means that you can share code between Win32 and iOS without getting tared and feathered ;-)

Posted in Delphi, Development, iOS | Leave a comment

Delphi XE 4 – Is ARC for Everyone?

Disclaimer: I have been permitted by Embarcadero to officially blog about the next Delphi Version: Delphi XE4 / RAD Studio XE4

As mentioned previously, Delphi XE4 will come with a new memory management, which is supposed to release us from hunting for memory leaks: ARC – Automatic Reference Counting.

ARC will basically do what its name stands for: it counts references to class instances and once an instance has no more reference it will just destroy that instance. This obviously eliminates the need for explicitly calling Free() or even applying the good old Try-Finally-Free pattern. So you can focus on your actual business logic instead of spending too much time on how to get rid of your no longer needed objects.

This sounds very cool of course. Creating instances and no thinking about how to get rid of them again. The question is though:

Is ARC for everyone?

Well, it’s not – yet. ARC will only work with Delphi’s new compiler (a.k.a NextGen compiler) which currently exclusively targets the iOS platform. So you will see ARC at work only within the iOS Simulator and on actual iPhones/iPads and iPod touches. On Windows will still have to use the “classic” Delphi compiler, which doesn’t know about ARC. Longterm I hope that EMBT will give us at least the option to have Win32/64 to be compiled with that new NextGen compiler. If you follow Marco Cantú’s (Delphi Product Manager) blog, then you will have noticed, that the next compiler target will be the Android platform. I would be more than surprised, if we wouldn’t see ARC there as well.

In a later blog post I will go into more detail how this ARC actually works and what you need to know to successfully have your class garbage released.

Delphi for iOS information at Embarcadero

Posted in Delphi, Development, iOS, Miscellaneous | Leave a comment