Getting Started with iOS Objective-C DataSnap Mobile Connector

From RAD Studio
Jump to: navigation, search

Go Up to Getting Started with DataSnap Mobile Connectors


This topic is a guide for getting started with generating and using the Objective-C iOS DataSnap proxy, for use with iPhone mobile development. The iOS proxy supports all the same data types that DataSnap itself supports. Special Objective-C classes have been created to wrap those DBX and Delphi types, and their usage is similar to the usage in Delphi.

When requested, the DataSnap REST server generates and dispatches the proxy class used to invoke the methods on the server. This is very similar to the proxy generation you might already be familiar with, but also includes the process of zipping up the proxy and all dependencies, and sending the zip file to the requester. For more information on this process, please see Getting Started with DataSnap Mobile Connectors.

How to Download iOS Proxy Files from the Server

To download the iOS proxy files from the server you need the proxy downloader, a simple utility that helps with asking the server for the proxy and other files needed for communication with the server. You can find the proxy downloader at:

C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\javaProxyDownloader.jar

To use the proxy downloader, you need to provide a -language parameter, which specifies the mobile platform and programming language of the requested proxy. For iOS development, use objectivec_ios81:

java -jar javaProxyDownloader.jar -language objectivec_ios81

You may optionally use any of the following command-line options:

  • -host: Specifies the port and host name or IP address to connect to. The default host is localhost with port 80. If a different name or port is needed, the name must be fully qualified with the port number included, separated by a colon (:).
  • -protocol: Specifies the connection protocol to use, either http or https. The default protocol is http.
  • -output: Specifies the folder to download the proxy files into. If not specified, the current folder is used.

For example:

java -jar javaProxyDownloader.jar -language objectivec_ios81 -protocol https -host 127.0.0.1:8080 -output output_folder

After you execute the proxy downloader, the objectivec_ios81 proxy files are copied into the specified output folder. The proxy files include:

  • A JSON library.
  • Static Objective-C source files required by the proxy.
  • DSProxy.h, the generated proxy header file.

The main files are DSProxy.h and DSProxy.m, which contain the class that encapsulates all the methods defined on the server.

Import these files into your Xcode project:

Xcodeproj.png

How to Use the DSProxy Class

The code below shows the DSProxy.h and DSProxy.m files generated by the server. The code contains a TServerMethods1 class, which encapsulates the server methods. The server has only one method (EchoString), and the Objective-C Class TServerMethods1 implements the method accordingly. The proxy generator has automatically generated all the code for connecting to the server and executing the methods. See the Objective-C code for the EchoString method below:

DSProxy.h (excluding imports)

 @interface TServerMethods1:DSAdmin{
 }

 /**
  * @param Value [in] - Type on server: string
  * @return result - Type on server: string
  */
   -(NSString *) EchoString: (NSString *) value ;
 @end

DSProxy.m

#import "DSProxy.h"

@implementation TServerMethods1
  -(id) getTServerMethods1_EchoString {
    return  [NSArray arrayWithObjects:
      [DSRESTParameterMetaData parameterWithName: @"Value" withDirection:Input withDBXType:WideStringType withTypeName:@"string"],
      [DSRESTParameterMetaData parameterWithName: @"" withDirection:ReturnValue withDBXType:WideStringType withTypeName:@"string"],
    nil];
  }

  -(id) getTServerMethods1_ReverseString {
    return  [NSArray arrayWithObjects:
      [DSRESTParameterMetaData parameterWithName: @"Value" withDirection:Input withDBXType:WideStringType withTypeName:@"string"],
      [DSRESTParameterMetaData parameterWithName: @"" withDirection:ReturnValue withDBXType:WideStringType withTypeName:@"string"],
    nil];
  }

  -(id) getTServerMethods1_VarParamTest {
    return  [NSArray arrayWithObjects:
      [DSRESTParameterMetaData parameterWithName: @"Value" withDirection:InputOutput withDBXType:WideStringType withTypeName:@"string"],
      [DSRESTParameterMetaData parameterWithName: @"" withDirection:ReturnValue withDBXType:WideStringType withTypeName:@"string"],
    nil];
  }

/**
 * @param Value [in] - Type on server: string
 * @return result - Type on server: string
 */
  -(NSString *) EchoString: (NSString *) value {

    DSRESTCommand * cmd = [[self Connection ] CreateCommand];
    cmd.RequestType =  GET;
    cmd.text= @"TServerMethods1.EchoString";
    [cmd  prepare:[self getTServerMethods1_EchoString]];

    [[[cmd.parameters objectAtIndex:0]getValue]SetAsString:value];

    [Connection execute: cmd];

    return [[[cmd.parameters objectAtIndex:1]getValue]GetAsString];
  }
@end

Using the Proxy Class

The first step to using the proxy class is to create and set up a connection to the server. Class DSRESTConnection encapsulates all the properties and methods needed for connecting to the server. Just create the connection and set up the properties in Objective-C, as shown below:

DSRestConnection * connection = [[DSRESTConnection alloc]initWithDelegate:self];
connection.Host = @"192.168.3.90";
connection.Port = 8080;
connection.protocol = @"http";

The method initWithDelegate allows you to specify the delegate object that responds to connection events. See the NSObject (NSURLConnectionDelegate) category to see the events to which it can respond.

  • The host property specifies the host name or IP address.
  • The port property specifies the port that the server is listening on.
  • The protocol property specifies the protocol to use for the connection. Specifically, http or https.
Note: If you are using https protocol, you might need to respond to the following events to inspect the certificate. See Apple documentation for further information:
  • (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
  • (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

To remotely invoke the server methods, just use Objective-C to create the proxy class, passing the connection, and then call the method:

client = [[ExampleServerMethods alloc] initWithConnection:connection];
 NSLog("%@"  ,[client EchoString: @"string to echo"]);

How to Use Heavyweight Callbacks

Heavyweight callbacks provide a way for DataSnap Servers to send nearly instantaneous notifications to REST clients. A client can register a callback for a specific topic on the server of interest; then whenever that topic is updated, the client receives a notification. This is, of course, a very simplified description of what heavyweight callbacks accomplish, but should be sufficient for the purposes of this task.

The first step towards using callbacks in your application is to create a new descendant of DBXCallback. DBXCallback has an "execute" abstract method that descendants must override. This method is executed when the server sends notifications. An example implementation of this class is shown below:

@interface MyCallBack : DBXCallback
{
}

@implementation MyCallBack

-(TJSONValue *) execute:(TJSONArray *)params{
       NSLog(@"consume [MyCallback.execute] %@ ",[params description]);
       return [[TJSONTrue alloc]init];
}

The execute method receives a TJSONArray as params that contains the data coming from the server, and might return a TJSONValue to the server. In this example, you just log a description of the parameters and return a TJSONTrue.

After implementing the callback, you need to register it on the server. The DSCallbackChannelManager class is used to accomplish this. It offers all the methods to register a callback with the server.

DSCallbackChannelManager creates a single channel between the client and the server, and all communication runs along the channel specified. Many clients can register with the same channel and receive notification that arrives on that channel. Here is the code that creates the manager:

mngr = [[DSCallbackChannelManager alloc] initWithConnection:connection
             withChannel:@"mychannel"
          withManagerID:[DSCallbackChannelManager generateManagerID]
             withDelegate:self ];

DSCallbackChannelManager needs the connection and the channel name to connect to. The initialization sets the delegate object that can respond to connection events.

After you create the channel, you can register callbacks with it. Each callback you register has to have a unique name (unique to the client channel manager) and a callback instance to use for notifications. The manager registerCallback method allows you to register these callbacks:

MyCallBack * cb =[[MyCallBack alloc]init];
[mngr registerCallback:@"mycb01" WithDBXCallBack:cb];

The example above registers a callback with the name "mycb01". Registering the callback immediately starts the communication between server and client. In the background, the DSCallbackChannelManager waits for events from the server to arrive and executes the callback each time those events fire.

The connection stays on until you close it or it is closed by the server. To stop the connection, you can unregister the callback and close the channel as shown below:

[mngr unregisterCallback:@"mycb01"];
[mngr closeClientChannel];

See Also