‘Dynamic’ Delphi/C++ samples on SourceForge via Subversion

Many of you will have already bumped into this information, but I’m posting it for the benefit of those who haven’t come across it. In much the same way as how the static RAD Studio online documentation is complemented by updatable and updated web-based documentation at http://docwiki.embarcadero.com, the sample applications supplied with RAD Studio are also updated over time and available via an online Subversion repository hosted at SourceForge. The RAD Studio Demo Code Web Site is at http://radstudiodemos.sourceforge.net and the SourceForge project page is http://sourceforge.net/projects/radstudiodemos. To pull down the demos you can use your favourite Subversion client and use the checkout functionality. With regard to Subversion clients I like using TortoiseSVN from within Windows Explorer, although there is also a TortoiseSVN plug-in for the RAD Studio IDE. Of course if you use Delphi XE or later you can perhaps more sensibly just use the built-in RAD Studio IDE Subversion support. Suitable Subversion repository URLs for the RAD Studio demo projects include: https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/trunk for the main demo trunk, although this misses out a bunch of XE4 demos, so maybe a specific branch (see rest of this list) might be more appropriate https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE – RAD Studio XE demos https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE2 – RAD Studio XE2 demos https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE3 – RAD Studio XE3 demos https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE3_Update – RAD Studio XE3 demos, including 64-bit C++ https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE4 – RAD Studio XE4 demos, including iOS demos https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE5 – RAD Studio XE5 demos, including iOS and Android demos From time to time you can again use your Subversion client to update the demos to take advantage of any changes made in the online repository. It’s good to be kept up to date! Above I touched on the online up-to-date documentation. For completeness I should mention that the docwiki is available from Delphi’s Help menu (RAD Studio Docwiki) and I should also offer up this list of entry pages to the online help systems: RAD Studio 2010 main page RAD Studio XE main page RAD Studio XE2 main page RAD Studio XE3 main page RAD Studio XE4 main page RAD Studio XE5 main page Finally, it’s always nice to get a refresher on what’s been added in recent product releases, so do stop by the What Was New In Past Releases page on the docwiki.
Read More

Delphi for iOS – some notes

The typical current requirements of the customers I work with, so they tell me, are to stick with Windows + VCL thanks to the long-term projects they have ongoing. Because of this I’ve not really spent too much time getting to know FireMonkey in excruciating detail since it was introduced. However, given that the quintessence of the XE4 release has been iOS support and this typically† revolves around using FireMonkey, I figured maybe it was about time to roll the sleeves up and get stuck in. This post is a summary run-though of the things I bumped into, how I got on, what I figured out, what problems I encountered and how I achieved a few things whilst checking out the latest platform-targeting in the Delphi product line. Environment setup First things typically come first, so top of the agenda was setting up the development environment to work on iOS projects. This was straightforward enough. The online documentation (to be honest I don’t install the help – I just use Embo’s docwiki site) covers the setup quite thoroughly. There’s a general run-through and then also in the iOS tutorials page there are links to detailed setup for the Mac and setup for Windows. To develop apps for Mac (OS X) or for iDevices (iOS) requires the use of a Mac – Apple make this a requirement as they supply some necessary tools for parts of the job (such as signing the app or simulating an iDevice) and those come with Apple’s Xcode and only run on a Mac. There’s no real need to dash out and buy a hugely over-priced MacBook Pro unless you have spare cash at your disposal; a Mac Mini is more than adequate and much more sensibly priced. Delphi or RAD Studio will run on a Windows machine, and a helper app called PAServer (the Platform Assistant) runs on the Mac to: liaise with any Mac tools that are required automate the iPhone/iPad Simulator when running iOS apps against the simulator act as a remote debugger when debugging a Mac or iOS application (either on a device or in the simulator) My first attempt at iOS development had my development environment (Delphi XE4) on a Windows laptop, talking across my network to the Mac Mini. This actually worked just fine, though the deployment step took about 10-20 seconds each time, sending the app files and the debug symbols across the network. Hardly a long time, but it got annoying when I kept needing to make small changes and see their effect. I ended up settling on a Windows virtual machine running on the Mac Mini via VMWare Fusion and installed Delphi XE4 in that. This made the deployment step joyfully rapid. I also then had the luxury of working directly with the Mac Mini, or working remotely on my laptop using VNC. I can have one session connected to the Windows virtual machine (VMWare Fusion acts can have each virtual machine optionally act as a VNC server) and another session talking to the Mac itself to see apps running in the simulator. I should point out I don’t have any iDevices – all my apps are just tested in the simulator and that’s that for the time being. To build iOS apps for the device and the simulator the IDE makes use of two of the five Delphi compilers shipped in RAD Studio XE4 (or Delphi XE4 with the mobile add-on), which are the latter two in this compiler list: dcc32 – Embarcadero Delphi for Win32 compiler version 25.0 – your regular Win32 Delphi, the latest version updated over many versions since Delphi 2 dcc64 – Embarcadero Delphi for Win64 compiler version 25.0 – the 64-bit Windows targeting compiler dccosx – Embarcadero Delphi for Mac OS X compiler version 25.0 – the Delphi compiler that generates 32-bit OS X apps dccios32 – Embarcadero Delphi Next Generation for iPhone Simulator compiler version 25.0 – the NextGen Delphi compiler that builds Intel executables that run in the iOS simulator dcciosarm - Embarcadero Delphi Next Generation for iPhone compiler version 25.0 – the NextGen Delphi compiler that builds ARM executables that run on iOS devices Simple FireMonkey apps To check that FireMonkey behaves basically the same as VCL I created a FireMonkey mobile application and threw some code on the form. It did as expected, and I noted the pervasive StyleLookup property that lets you customise all the controls. For example with a button there are pre-defined styles to make the button look like the various buttons that commonly crop up in iOS applications. This style system helps you put together a UI that will fit in with other apps in the world of iOS. This is an important issue. When you build an iOS app you’ll be creating a UI specifically for the mobile devices – laid out to look appropriate on an iPhone and/or iPad. Apple are very specific about how UIs on their OSs should look and have comprehensive User Experience guidelines both for OS X and for iOS. You should digest these guidelines and take note of how existing applications look to ensure your app doesn’t stick out like a sore thumb. The UI should be carefully designed for the target platform. <soapbox>Consequently, the repeated platitude we hear from the bods at Embo about building an app once and recompiling it for different platforms should be taken for what it is: marketing fluff. Sure, back-end code could follow that ideal, but anything tightly related to the UI will doubtless need to be re-implemented for each target platform. You owe it to your users to respect them enough to do the right thing with your app’s UI.</soapbox> All that notwithstanding, it was a breeze to build a simple iPhone app and have it run in the simulator. Seemed very much akin to building a VCL application at the basic level I was working at, which was quite encouraging. Compiler changes If you’re looking to share a bunch of existing code with an iOS Delphi application you should remember that the iOS compiler is a next generation Delphi compiler, with a few language changes in. I gave a list of the changes (including proposed changes currently represented by warnings) in the compiler in a previous blog post here. The removal of some of the string types and some of the other obvious changes in it might make it more difficult than you expect to pull in a lot of old code, but obviously your mileage will vary on this one. If you want to write new code that will be shared across platforms, the fact that the next-gen compiler employs ARC for all Delphi objects (not just strings, dynamic arrays and interfaces) means that the shared code will need to call Free, which is a no-op on iOS. iOS-only code can forget all about calling Free, which is nice. Certainly what I hear from clients I work with is that their primary goal for the iOS compiler is to build some small standalone applications that will, via some connectivity option or other, perhaps connection to a web service or DataSnap server, present some representation of a portion of an existing desktop application to users, or provide reports and stats from an existing system to management types. That seems like a very achievable and sensible plan to me. New dependency keyword A new keyword that slipped in under the radar in the NextGen ARM compiler is dependency. This is really a convenience that precludes the need to tweak the options to get certain apps to work. Specifically this keyword lets you tell the linker of additional libraries to link in when declaring an external library function. So, for example, the MIDAS static link library midas.a has a dependency on the Standard C++ library libstdc++.dylib. A dylib on a Mac can be dynamically loaded at runtime or statically linked. Apple decrees that iOS apps cannot use any custom dynamic libraries, so any library code must be statically linked into the app. This means that any app that uses the MIDAS library must statically link the Standard C++ library in as well. Without the dependency keyword this would involve modifying the ARM linker options. This could be done by going into the project options (Ctrl+Shift+F11) and doing either of these: selecting Delphi Compiler, Compiling in the options tree, then selecting Other options, Additional options to pass to the compiler and entering a suitable portion of a dcciosarm.exe comand-line like: --linker-option:"-L $(BDSLIB)\$(Platform)\$(Config) -lstdc++" selecting Delphi Compiler, Linking in the options tree, then selecting Options passed to the LD linker and entering: -L $(BDSLIB)\$(Platform)\$(Config) -lstdc++ However, dependency means you can forget all that and write your import declaration like this one, from DataSnap.DSIntf.pas: {$IF DEFINED(IOS) and DEFINED(CPUARM)}function DllGetDataSnapClassObject(const [REF] CLSID,  [REF] IID: TGUID; var Obj): HResult; cdecl;  external 'libmidas.a' name 'DllGetDataSnapClassObject'  dependency 'stdc++';{$ENDIF IOS and CPUARM} This approach is used more widely for the InterBase DBExpress client code in Data.DbxInterbase.pas. Here we find a variety of imported functions coming from libsqlib.a, which have a dependency on both Standard C++ and also libibtogo.dylib. So there are a whole bunch of declarations like: function DBXBase_Close(  Handle: TDBXCommonHandle): TDBXErrorCode; cdecl;  external 'libsqlib.a' name 'DBXBase_Close'  dependency 'ibtogo', 'stdc++'; FireMonkey versus CocoaTouch If you spend some time browsing through the FireMonkey and iOS-specific RTL source you’ll become familiar (at one level or another) with the relationship between FireMonkey and the iOS Objective-C API. Very similar to how the VCL presents nice components, but those components are built on the Windows UI infrastructure of windows and window handles and how VCL applications operate by participating in the regular Windows message processing behaviour, FireMonkey iOS applications also immerse themselves in the regular iOS infrastructure. What this means is that a FireMonkey form is based on an Objective-C UIView or, more specifically, a GLKView in the case of a GPU-backed form. The application start-up is done through a call to UIApplicationMain and there is an application delegate (UIApplicationDelegate protocol implementation) used to deal with when the app starts, goes to the background, comes back to the foreground and terminates. Here and there you might find it useful to call upon some iOS APIs, which requires a heads-up on some basics. The following sections endeavour to give you such a heads-up. Working with NSStrings Objective-C uses NSString objects where Delphi uses strings. If you need to pass a string to an iOS API that expects an NSString you can use the NSStr function in iOSapi.Foundation.pas to translate it over. You can also do the reverse by borrowing (ok, copying) the NSStrToStr function that is (inexplicably) tucked away in the implementation section of FMX.MediaLibrary.iOS.pas. [Update: Note that this function turns the NSString to UTF8 before turning it back to a Delphi string. This is a bit of a round trip, and any characters outside UTF8-space get rather mangled. You might benefit from looking at Chris Rolliston’s approach to the same problem.] Additionally, any time you are presented with a UTF8 string from an Objective-C method (which would be represented as type _PAnsiChr), such as the UTF8String method of NSString or the systemVersion method of a UIDevice, you can turn it into a Delphi string with UTF8ToString. Delphi’s representation of Objective-C objects Much as Delphi's classes all stem from TObject, Objective-C classes all have a common ancestor of NSObject. The large number of classes in the full tree are split into branches of classes called frameworks. For example UIKit is the framework containing all the basic UI-related stuff and MapKit wraps up all the mapping stuff. Delphi represents these Objective-C classes by interfaces. For example, NSObject is declared in iOSapi.CocoaTypes.pas and contains declarations of the instance methods of an Objective-C object of type NSObject. Where Delphi has an interface for an Objective-C class's instance methods there is also another interface for all the class methods. In the case of NSObject it's called NSObjectClass. In order to make use of these interfaces a helper class is defined alongside the instance interface and class interface for the Objective-C type. The helper class is a generic class that inherits from TOCGenericImport<C,T> and wraps up the process of importing the Objective-C class into Delphi. For NSObject the helper class is TNSObject and gives you a means to create an Objective-C object of type NSObject and also wrap up an object id for such an Objective-C object into an NSObject interface reference. That sets out the pattern of types used to represent imported Objective-C objects. In Objective-C constructing an object is a two stage process. The memory is allocated by a call to the class alloc method and then the returned object is initialised through a call to a class initialiser, such as the default init or maybe a custom one. Various classes have custom initialisers, for example controls have one called initWithFrame. We may be more familiar with the one-stop construction achieved by calling a Delphi class constructor, such as Create, but of course behind the scenes the same two steps have to occur - the memory for the instance is allocated and then the body of Create initialises that instance. Let's take an example of creating an alert view - basically an iOS message box. Clearly in a FireMonkey project you would just use ShowMessage or MessageDlg, which will work out how to do all this on iOS platform, but for the sake of example let's follow it through. The alert view is represented in iOS by UIAlertView, so iOSapi.UIKit.pas defines interfaces UIAlertView and UIAlertViewClass as well as class TUIAlertView. If you want to construct an instance of UIAlertView using alloc and the default init initialiser then a call to TUIAlertView.Create will do the job and return an interface reference to a UIAlertView. You can then tailor the alert view by calling its setTitle, setMessage and addButtonWithTitle methods and display it by calling show. Something like this: var  alertView: UIAlertView;...  alertView := TUIAlertView.Create;  alertView.setTitle(NSStr('Delphi for CocoaTouch'));  alertView.setMessage(NSStr('Hello world'));  alertView.setCancelButtonIndex(    alertView.addButtonWithTitle(NSStr('OK')));  alertView.show;  alertView.release; However if you want to use a custom initialiser you can allocate an uninitialised instance by calling the helper class's Alloc method and then call the custom intialiser on that. However the custom intialiser will return an actual Objective-C object (as opposed to an interface that represents it), which is represented as a raw pointer. This pointer can be considered the Objective-C object id. To turn this object id back into a usable Delphi interface reference you feed it into the helper class's Wrap method (just be careful with Wrap as it does not check for nil being passed in and so will happily crash if given the chance - see QC 115791). So we could rewrite the above like this: var  alertView: UIAlertView;...  alertView := TUIAlertView.Alloc;  alertView := TUIAlertView.Wrap(alertView.initWithTitle(    NSStr('Delphi for CocoaTouch'), //title    NSStr('Hello world'), //message    nil, //delegate    NSStr('OK'), //cancel button caption    nil)); //other button captions  alertView.show;  alertView.release; So that shows how to create a new instance of an existing Objective-C class and call instance methods. To call class methods you use the OCClass property. The UIDevice iOS class has a currentDevice read-only property that is documented to return a UIDevice instance that represents the current device. Similarly UIScreen has a mainScreen read-only property that returns a UIScreen instance that represents the main screen (i.e. not an external screen). var  currentDevice: UIDevice;  mainScreen: UIScreen;  iOSversionStr, screenDimensionsStr: string;...  currentDevice := TUIDevice.Wrap(    TUIDevice.OCClass.currentDevice);  iOSversionStr := UTF8ToString(    currentDevice.systemVersion.UTF8String);  mainScreen := TUIScreen.Wrap(TUIScreen.OCClass.mainScreen);  screenDimensionsStr := Format('%d x %d',    [Round(mainScreen.bounds.size.width),     Round(mainScreen.bounds.size.height)]); From a given interface reference to an Objective-C object, obj, you can access its object id (the pointer to the actual Objective-C object) using this: (obj as ILocalObject).GetObjectID Objective-C properties Objective-C objects offer various properties just like Delphi objects do. These are implemented with getter and setter functions as you'd expect. However if building a Delphi iOS app you should know that all the Delphi interfaces representing Objective-C classes don't have these properties brought through. Instead you'll need to call the setter procedure (e.g. setFrame() for a UIView object's frame property or setStatusBarHidden() for the UIApplication class statusBarHidden property) or getter function (e.g. frame() for the frame property or isStatusBarHidden() for the statusBarHidden property. Yeah, as you may notice there the property getter either has the same name as the property or uses an is prefix... You can read the formal documentation on property accessor naming on Apple's site here. Objective-C method names As explained in various places on the Arpanet (or Internet as we now call it), such as this method naming post from Ry's Objective-C tutorial, Objective-C has an interesting approach to method naming. The parameter names become part of the method name to aid self-description and to minimise opportunities for ambiguity. Let's have a look at some example methods defined in the UIApplicationDelegate protocol. Firstly the method that triggers after the application has started up: (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions This is a function method that returns a Boolean and takes two arguments, a reference to a UIApplication and a reference to an NSDictionary. To the person implementing the method the arguments are called application and launchOptions but the arguments are described in the full method name, which is formed from all items that have colon suffixes. The Objective-C method name is application:didFinishLaunchingWithOptions: and this differentiates it from other methods in the same protocol, such as application:shouldSaveApplicationState: and application:willChangeStatusBarFrame:. Problems start cropping up over on the Delphi side when you try to translate these methods to a Delphi representation. Here are a selection of methods from this protocol that we might wish to translate: (BOOL)application:(UIApplication *)application  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions(BOOL)application:(UIApplication *)application  shouldSaveApplicationState:(NSCoder *)coder(void)application:(UIApplication *)application  willChangeStatusBarFrame:(CGRect)newStatusBarFrame Now here is the best we can do in Delphi to translate them over accurately: function application(application: UIApplication;  didFinishLaunchingWithOptions:NSDictionary): Boolean; overload;function application(application: UIApplication;  shouldSaveApplicationState: NSCoder): Boolean; overload;procedure application(application: UIApplication;  willChangeStatusBarFrame: CGRect); overload; You'll notice each method has the same name and so requires overloading. But we're okay so far as each overload has a unique signature. Let's add in some more methods: (BOOL)application:(UIApplication *)application  shouldRestoreApplicationState:(NSCoder *)coder(void)application:(UIApplication *)application  didChangeStatusBarFrame:(CGRect)oldStatusBarFrame You can probably see the problem rearing its head now. When we translate these into additional methods in a Delphi UIApplicationDelegate interface the compiler won't accept the overloads as we have the same signatures as already defined: function application(application: UIApplication;  shouldRestoreApplicationState: NSCoder): Boolean; overload;procedure application(application: UIApplication;  didChangeStatusBarFrame: CGRect); overload; So this leads to the realisation that the general case is that we cannot adequately represent any given Objective-C class or protocol by using a Delphi interface. You can do some of it, but as soon as matching signatures come along this approach falls down. If you hunt out the UIApplicationDelegate interface in iOSapi.UIKit.pas you'll see a number of the methods commented out for this exact reason. This puts a bit of a downer on the whole affair until you find out that given enough desire you can work around this limitation of Delphi's method representations and set things up manually. In fact that's exactly what FireMonkey does in order to set up an application delegate on iOS application start-up. It uses low-level Objective-C Runtime routines to set up Delphi routines to implement given Objective-C methods. If you look in FMX.Platform.iOS.pas and locate TPlatformCocoaTouch.Create you can see this being done. It's a bit of a faff, but does allow Delphi to work with any Objective-C objects. I've used the approach myself in a couple of test applications and can confirm that it's workable, but really it's not entirely productive to do so. I plan to write more on the subject at a later point, but for now I'll leave the FireMonkey source as an adequate reference. [Update: apparently I’d rather overlooked the fact that this issue had already been acknowledged by the Embo devs and a neat workaround exists – ah well, you live and learn. Indeed this neat workaround is used to work around the problem in the RTL, for example in the CLLocationManagerDelegate interface. This is achieved using the handy [MethodName()] attribute through which you can map an arbitrarily named Delphi method to a specifically named Objective-C method. Thanks to Embo’s Darren Kosinski for pointing me to this] ARC and Delphi and Objective-C When Delphi first arrived it supported the string type. A string is really a pointer to a data structure that is automatically memory-managed for you. This memory management includes reference counting to cater for when strings are passed into subroutine calls and assigned to variables. When nothing references a string any longer the code generated by the compiler ensures all the memory occupied by the string data structure is freed. When interfaces were added to Delphi 3 we again enjoyed reference counted memory management. The compiler worked out when to call the _AddRef and _Release methods on interface references based on assignments, parameter passing and scope and if _Release caused the internal reference count to reach 0 the object destroyed itself. With the NextGen Delphi compiler the programmer is afforded the luxury of automatic reference counting (ARC) for all objects, as detailed in this Dr Dobbs article by Embo's JT and Marco Cantù. The compiler will identify where to make calls to TObject's __ObjAddRef and __ObjRelease for you. Again, when the internal reference count gets to 0 the object destroys itself. Hence there is no longer a need to worry about calling Free and wrapping construction and destruction code up in a pair inside a try/finally statement. That said, it doesn't matter if you do call Free as in the NextGen compiler TObject.Free simply sets the object reference to nil, hastening the decrement of the object reference. When you program iOS apps in Objective-C you are also blessed with ARC. Just as with Delphi it's a compiler thing - the compiler works out where it's appropriate to make calls to retain and release to ensure the internal reference counts will drop to 0 when a given object is no longer used by anything. So the Delphi (NextGen) compiler does ARC against all Delphi objects and the Objective-C compiler does ARC against all Objective-C objects, but what about Objective-C objects in a Delphi program? Unfortunately there is no ARC for the iOS objects represented by the import wrapper class and the interfaces discussed above. When dealing with iOS objects manually you will need to call retain and release yourself at the correct points. Allocating an iOS object starts the reference count off at 1; calling release will drop it to 0 and have the object destroy itself. Apple’s Instruments app A really useful tool supplied as part of Xcode (or possibly just shipped a part of OS X, I’m not positive) is Instruments. If you read up on Instruments you’ll see that this can help identify memory leaks in your OS X or iOS apps. I've been using it to check on iOS object leaks in FireMonkey applications and also in apps written in Delphi that use no FireMonkey business at all. It's been quite illuminating as I've happened upon a couple of simple shortcomings in the FireMonkey code. The principle I've used is to have all the code that does stuff I want to leak-check in secondary forms launched from a main form. In the case of FireMonkey I'm just using regular forms and launching them with ShowModal. I launch the app in the iOS simulator and then launch Instruments and choose the Leaks mode. Next I use the Choose Target dropdown and from the Attach to Process submenu I select my app process from the System list. Pressing the Record button then starts tracking object and memory allocations. For any given iOS object type you can see how many instances still exist, look at a list of them all and for any instance see the allocation and all the retain/release calls. Going through this process with a simple FireMonkey app that launched a secondary form showed that a UIView and various other helper objects were being allocated each time the form was displayed but not freed when it was closed. Tracking the problem eventually yielded some fixes to the FireMonkey source that resolve the problem, as documented in QC 115914. In short you need to: copy FMX.Platform.iOS.pas from $(BDS)\source\fmx change TPlatformCocoaTouch.DestroyWindow to be:procedure TPlatformCocoaTouch.DestroyWindow(  const AForm: TCommonCustomForm);begin  if Assigned(AForm.Handle) then  begin    WindowHandleToPlatform(AForm.Handle).View.      removeFromSuperview;    WindowHandleToPlatform(AForm.Handle).View.release;  end;end; in TPlatformCocoaTouch.ShowWindowModal change the finally part of the try/finally statement to:finally  BackView.removeFromSuperview;  BackView.release;end; Further experimentation showed that the iOS implementation of the message box routines (ShowMessage, MessageDlg and InputQuery) were also leaking objects; in this case UIAlertView references. QC 115966 contains the report and a proposed source fix. As above you change a local copy of FMX.Platform.iOS.pas. This time you change TPlatformCocoaTouch.MessageDialog. At the end of it add this statement: AlertView.release; Now in TPlatformCocoaTouch.InputQuery, imediately after the assignment: Result := Delegate.Result = mrOk add in the statement: AlertView.release; Accessing the Objective-C shared application object iOS apps often need access to the Objective-C shared application object (a singleton UIApplication object that represents the running application). One example would be when using a TWebBrowser object you can indicate to the user that network activity is taking place as the web page is brought down by using a property of the application object to control the iDevice's network activity icon on the status bar. The browser object's OnDidStartLoad event marks the start if the page download and OnDidFinishLoad or OnDidFailLoadWithError tell you when it's over. The application object has a networkActivityIndicatorVisible property that controls the status bar icon. In iOS you retrieve the shared application object by using the sharedApplication class function of the UIApplication class. Here is how you could build a helper function to expose the shared Objective-C application object. Note that a function just like this is implemented in (although not exposed from) both these iOS FireMonkey units: FMX.MediaLibrary.iOS.pas and FMS.Pickers.iOS. uses  iOSapi.UIKit;function GetSharedApplication: UIApplication;begin  Result := TUIApplication.Wrap(    TUIApplication.OCClass.sharedApplication);end; Given this function you could write event handlers for a web browser component like this: procedure TBrowserForm.WebBrowserDidStartLoad(ASender: TObject);begin  GetSharedApplication.setNetworkActivityIndicatorVisible(True);end;procedure TBrowserForm.WebBrowserDidFinishLoad(  ASender: TObject);begin  GetSharedApplication.setNetworkActivityIndicatorVisible(    False);end;procedure TBrowserForm.WebBrowserDidFailLoadWithError(  ASender: TObject);begin  GetSharedApplication.setNetworkActivityIndicatorVisible(True);  ShowMessage('Web page failed to load for an unknown reason');end; In this case the failure event handler cannot tell the user what the failure is as the NSError object given the equivalent iOS event handler is not surfaced to FireMonkey, even in some abstract manner. I've reported this to Quality Central as QC 115652. Logging to the OS X Console app It is common in iOS apps to emit logging statements that are picked up by OS X’s Console application using the NSLog API. This is a global function, not a method, and takes an NSString, but because it is outside the scope of the Delphi helper objects and interfaces it expects a PNSString (a pointer to an NSString) - an Objective-C object id for the string in question. To make it easy to turn a Delphi string into a PNSString you can build a helper function like this: uses  iOSapi.Foundation, Macapi.ObjectiveC;...function PNSStr(const AStr: String): PNSString;begin  Result := (NSStr(AStr) as ILocalObject).GetObjectIDend; While you are at it you could build a more usable Log function: procedure Log(const AStr: String); overload;procedure Log(const AStr: String; const Args: array of const); overload;...procedure Log(const AStr: String);begin{$IFDEF IOS}  NSLog(PNSStr(AStr));{$ELSE}  {$MESSAGE WARN 'Only currently implemented for iOS'}{$ENDIF}end;procedure Log(const AStr: String; const Args: array of const);begin  Log(Format(AStr, Args))end; Numeric type definitions For the most part you'll not bump into this being an issue, but the initial release of XE4 has NSInteger and NSUInteger both incorrectly defined in iOSapi.CocoaTypes.pas. NSInteger is defined to be Integer and NSUInteger to be LongWord, which are both always 32-bits regardless of the underlying platform. The Apple documentation for NSInteger and NSUInteger clearly states that on 32-bit platforms the types are 32 bits and on 64-bit platforms they are 64 bits. It would be rare to find these wrong definitions a problem, but I did bump into it as an issue when implementing a C calling convention (cdecl) routine that was called by Objective-C and returned an NSInteger. When the stack was cleared up by the Objective-C side the differing size of the return value meant the function's return address was in "the wrong place" and so the app immediately crashed. I sorted this in the project by defining local versions of the types that were correct. This has been reported as QC 115789. Debug source stepping The keener among us Delphi users like to step through the RTL and VCL or FMX source. With iOS apps the installation neglects to add one of the key iOS RTL directories to the browsing path in the initial XE4 release. This results in various iOS units not being found when trying to step through the source. The issue has been reported on QC, and I submitted a duplicate report before learning of that initial post. To fix the problem go to Tools, Options..., Delphi Options, Library. Now add $(BDS)\source\rtl\ios to the Browsing path † the reason for the use of typically is that you can actually build a regular CocoaTouch application using Delphi for iOS if you really want to. I've done this myself with a few little apps, working through a variety of technical stumbling blocks along the way. I'm in the process of writing up my findings on the subject, so I'll hopefully blog about an article on the subject in the near future.
Read More

RAD Studio XE4 World Tour – Canadian Dates

In case you've missed it, Embarcadero's Rad Studio XE4's launch tour will be in Montreal and Toronto on June 5th and 6th. Montreal, QC Wednesday, June 5, 2013 @ 6:00-8:00PM Hôtel Europa Register for Montreal Toronto, ON Thursday, June 6, 2013 @ 6:00-8:00PM Northern District Library Register for Toronto Welcome to this RAD Studio event focusing on iOS development.RAD Studio is the
Read More

XE Plus Pack – Release 12 (XE4 Support)

Release 12 of XE Plus Pack is now available for download which includes XE4 support. Users can download the required version from the download page. To try XE4 Plus Pack download the trial version. Users of XE2 Plus Pack and XE3 Plus Pack can use their existing registration details to unlock XE4 Plus Pack. New in Release 12 (for all) Smart Desktops Allows you to synchronize your desktops between computers and installations. This is just the first part of the Smart Desktop feature, with additional features being added in future releases. http://www.jed-software.com/help/SmartDesktops/SmartDesktops.html New in Release 12 (for XE4 only) - Component editor for the TTabControl FireMonkey component that allows you to switch between pages using the form designer context menu, or a link at the bottom of the object inspector.
Read More

Konopka Answers The FireMonkey Question At Code Rage 7

I did not attend Code Rage 7 but I just learned that Ray Konopka is working on a set of FireMonkey tools. He has not published a date as to when this tool set will be available but I'm glad to hear he's working on one. Here is the Code Rage 7 video that loads at 36 minutes and 2 seconds right where the FireMonkey question gets asked:Ray Answers The FireMonkey Question At Code Rage 7Semper Fi,Gunny Mike
Read More

More APNS info (in pictures)

A little bit of clarification on my APNS blog post(s) comment threads…
Deployment tab – notice IDE maintained file UNCHECKED – your file – CHECKED – remote name – Entitlements.plist:

Provisioning tab (specify the first two, hit Load ID):

Version Info tab:

Anders.entitlements file:
<?xml version=”1.0″ encoding=”UTF-8″?>
<plist version=”1.0″>
Share […] … Read More

Read More

XE4 Upgrade Decision

I'm currently using Delphi 2010 Professional and it's time to make that upgrade decision . . . again. The first decision I had to make was should I upgrade to Rad Studio XE4 or Delphi XE4. I've decided to upgrade to Delphi XE4. Now I have to decide which version of Delphi XE4 should I go with, Professional Upgrade ($494.10) or the Enterprise Upgrade ($1,349.10).  That's a difference of $855. So I decided to study the Delphi XE4 Feature Matrix.The Professional version has three different Optional features:1 Requires purchase of Mobile Add-On Pack for Professional2 Requires purchase of FireDAC Client/Server Pack for Professional3 Requires purchase of Mobile Add-On Pack for Professional for use with mobile apps. Requires purchase of FireDAC Client/Server Pack for Professional for use in Windows and Mac apps.Each one of Optional features requires a separate purchase:1. Mobile Add-On Pack for Professional ($494.10)2. FireDAC Client/Server Pack for Professional ($399.00)3. Both of the above ($848.10)For me, Chances are I'd have to purchase the above tems if I went with XE4 Professional. However, the above items are included in the Enterprise version of XE4. So that makes the difference a whopping $6.90.With XE4 Enterprise you also get Additional UML MODELINGdbExpress drivers available for 64-bit Windows InterBase, Firebird, Oracle, MySQL, SQL Anywhere, Informix, and SQLitedbExpress drivers available for OS X InterBase, Firebird, Oracle, MySQL, SQL Anywhere, Informix, and SQLiteTSQLMonitor support for SQLiteDataSnap Mobile Connector support for latest versions of iOS, Android and BlackBerrySeveral dbExpress server connectivity versionsDataSnap capabilityA couple additional BizSnap piecesSome IntraWeb piecesSo, given my track record for slow upgrades it looks like the best choice for me is the upgrade to Delphi XE4 Enterprise.Note: The prices quoted came from embarcadero's website store on 05/19/2013. Semper Fi,Gunny Mike
Read More

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. Tweet This! Share this on del.icio.us Digg this! Share this on Reddit Get Shareaholic
Read More

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: Apple URL Schemes Misc URL Schemes from AKOSMA Wiki Tweet This! Share this on del.icio.us Digg this! Share this on Reddit Get Shareaholic
Read More

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. Tweet This! Share this on del.icio.us Digg this! Share this on Reddit Get Shareaholic
Read More