You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by Apache Wiki <wi...@apache.org> on 2012/02/22 07:28:40 UTC

[Thrift Wiki] Update of "ThriftUsageObjectiveC" by satoshihirano

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Thrift Wiki" for change notification.

The "ThriftUsageObjectiveC" page has been changed by satoshihirano:
http://wiki.apache.org/thrift/ThriftUsageObjectiveC?action=diff&rev1=9&rev2=10

Comment:
updated for 0.9.0

+ ## page was copied from ThriftUsageObjectiveC
+ <<TableOfContents>>
+ 
+ = Before using Thrift for Objective-C =
+ == Supported Platforms ==
+ Thrift supports the following platforms as well as other platforms.
+ 
+  * Mac OS X 10.5 or later
+  * iOS 4 or later
+ 
+ ''cocoa'' represents the above platforms. The runtime library and the generated code adapt themselves to the platforms automatically. Thus, please use ''cocoa'' for them.
+ {{{
+ % thrift --gen cocoa idl.thrift
+ }}}
+ 
+ == Installation ==
+ 
+ See [[ThriftInstallationMacOSX| this page]].
+ 
+ == Support of ARC ==
+ 
+ Since iOS 5 and Mac OS 10.7, Objective-C supports Automatic Reference Counting (ARC) in addition to the conventional object life cycle management by retain/release (non-ARC).
+ 
+ Thrift 0.8.0 does not support ARC. If you want use it within an app in ARC mode, you need to compile the thrift runtime library in non-ARC mode by [[http://stackoverflow.com/questions/6646052/how-can-i-disable-arc-for-a-single-file-in-a-project|specifying -fno-objc-arc flag]].
+ 
+ Use [[https://builds.apache.org//job/Thrift/lastSuccessfulBuild/artifact/thrift/|0.9.0-dev]] or later, if you need to use thrift in ARC mode. It supports both ARC and non-ARC. Both the runtime library and generated Objective-C code can be compiled both in ARC mode and in non-ARC mode. They automatically adapt themselves to the compilation modes without any switch.
+ {{{#!wiki note
+ '''When you modify Thrift'''
+ 
+ Use ''retain_stub'' instead of ''retain'' and use ''release_stub'' instead of ''release'' inside the runtime library. The thrift compiler should generate ''retain_stub/release_stub'' instead of ''retain/release''. [[http://svn.apache.org/viewvc/thrift/trunk/lib/cocoa/src/TObjective-C.h?view=markup|See this for detail]].
+ }}}
+ 
+ == How to Link the Runtime Library ==
+ 
+ You need to link the runtime library of Thrift with your project. The location of the runtime library: ''thrift-x.x.x/lib/cocoa/src''
+ 
+ There are two options. 
+ 
+  * If your project is small, you can add the source files of the runtime library into your project. 
+  * Otherwise, if you use Thrift within several sub projects, you must make a framework from the source files of the runtime library. Since ways of making a framework is a bit complicated and exceeds this guide, please consult other sites. We expect somebody will contribute a script that makes a framework automatically.
+ 
+ The rest of this guide assumes we directly add the runtime library into our sample project and we don't make the framework.
+ 
+ 
  = Getting started =
  
- This guide will walk you through creating an application that uses Thrift with a Java server and a client written in Objective-C.  It is assumed that you will have a basic knowledge of Objective-C and Xcode to complete this tutorial.
+ This tutorial will walk you through creating a sample project which is a bulletin board application using Thrift. It consists of an iOS client app written in Objective-C and a Java server. It is assumed that you will have a basic knowledge of Objective-C and Xcode to complete this tutorial. Note that the client runs on Mac OS with small modification.
+ 
+ {{http://staff.aist.go.jp/hirano-s/thrift/result.tiff|align=right}}
+ 
+ Acknowledgment: A part of this tutorial was borrowed from ''newacct's'' tutorial.
+ 
+ == Sample Download ==
+ 
+ You can download the sample project [[http://staff.aist.go.jp/hirano-s/thrift/myThriftApp.zip|from here]]. It includes:
+ 
+  * The whole myThriftApp project
+  * the runtime library in thrift/ directory from 0.8.0-dev (You should replace this with the latest one.)
+  * idl.thrift
+  * Server.java and BulletinBoard.java in gen-java/ directory
  
  == Requirements ==
+ 
- Make sure that your system meets the requirements as noted in ThriftRequirements
+ Make sure that your system meets the requirements as noted in ThriftRequirements.
  
-  * Thrift 0.2.0
+  * Thrift 0.9.0+ (0.8.0-dev+)
-  * Mac OS X 10.5+
+  * iOS 4+ or Mac OS X 10.5+
-  * Xcode 3.0+
+  * Xcode 4.2+
  
  The following are required for the Java server; but, not the Objective-C client.
  
   * Java 1.4+ (already installed in Mac OS X 10.5+)
   * SLF4J (available at http://www.slf4j.org/download.html)
  
- == Building Thrift cocoa as a framework ==
- It is relatively straight forward to build the thrift cocoa library sources as a framework.  As of Thrift 0.2.0 this is not done automatically.  Hopefully it will in future releases.
- 
-  1. Download Thrift 0.2.0 and install.  Follow the instructions at ThriftInstallationMacOSX to install on Mac OS X.
-  2. Download the Thrift.framework project for XCode [[attachment:ThriftFramework.zip]]
-  3. Open the Xcode project file and compile.
- 
  == Creating the Thrift file ==
- We will use the sample thrift file described on the main page of the Thrift project.
+ We will use a simple thrift IDL file, ''myThriftApp/idl.thrift''. This defines a bulletin board service. You can upload your message and date using ''add()'' method. ''get()'' method returns a list of the struct so that we demonstrate how to send/receive an array of structs in Objective-C.
  
-  * Create a new directory to contain the project sources.
-  * Create a new file called 'profile.thrift'
- 
  {{{
- struct UserProfile {
-   1: i32 uid,
+ // idl.thrift
+ struct Message {
+      1: string text,
-   2: string name,
+      2: string date
-   3: string blurb
  }
- service UserStorage {
-   void store(1: UserProfile user),
-   UserProfile retrieve(1: i32 uid)
- }
+ 
+ service BulletinBoard {
+     void add(1: Message msg),
+     list<Message> get()
- }}}
+ }}}}
   
-  * Run the thrift compiler to build project sources.
+  * Run the thrift compiler to generate the stub files (e.g. gen-cocoa/idl.h and gen-cocoa/idl.m).
  
  {{{
- thrift --gen java profile.thrift
+ thrift --gen java idl.thrift
- thrift --gen cocoa profile.thrift
+ thrift --gen cocoa idl.thrift
  }}}
+ 
+ == Create the Objective-C client app ==
+ The objective-c client is a simple app that allows the user to fill out a text field add/get them from the server.
+ 
+  * Create a new iOS single view project.
+    * Product name is ''myThriftApp''.
+    * Check to ''Use Automatic Reference Counting''
+  * Add generated files.
+    *  Right click on myThriftApp and select ''Add files to "myThirtApp"''. Choose "gen-cocoa".{{http://staff.aist.go.jp/hirano-s/thrift/add.tiff|align=right}}
+  * Add the runtime library.
+    * Right click on myThriftApp and select ''Add files to "myThirtApp"''. Choose "thrift-x.x.x/lib/cocoa/src". 
+    * rename group name from ''src'' to ''thrift''.{{http://staff.aist.go.jp/hirano-s/thrift/group.tiff|align=right}}
+  * Setup header search path in build settings.
+    * Always Search User Path: YES {{http://staff.aist.go.jp/hirano-s/thrift/path2.tiff|align=right}}
+    * Framework Search Paths: add ''$(SRCROOT)'' and ''$(inherited)'' {{http://staff.aist.go.jp/hirano-s/thrift/path.tiff|align=right}}
+ 
+ 
+  * Copy the following text to ViewController.h
+ {{{
+ #import <UIKit/UIKit.h>
+ 
+ @class BulletinBoardClient;
+ 
+ @interface ViewController : UIViewController <UITextFieldDelegate> {
+     BulletinBoardClient *server;
+ }
+ @property (strong, nonatomic) IBOutlet UITextField *textField;
+ @property (strong, nonatomic) IBOutlet UITextView *textView;
+ - (IBAction)addPressed:(id)sender;
+ @end
+ }}}
+  * Open the ViewController_iPhone.xib
+    * Place a Text Field, a Round Rect Button, and a Text View. {{http://staff.aist.go.jp/hirano-s/thrift/xib.png|align=right}}
+    * Connect the delegate of the Text Field to File's Owner. 
+    * Connect the Text Field to ''textField'' variable in ViewController.h.
+    * Connect the Button to ''addPressed:'' method in ViewController.h. Give ''add'' title to the button.
+    * Connect the Text View to ''textView'' variable in ViewController.h. Clear the content of the Text View.
+ 
+  * Copy the following code into ViewController.m
+ {{{
+ #import <TSocketClient.h>
+ #import <TBinaryProtocol.h>
+ #import "ViewController.h"
+ #import "idl.h"
+ 
+ @implementation ViewController
+ @synthesize textField;
+ @synthesize textView;
+ 
+ - (void)viewDidLoad {
+     [super viewDidLoad];
+     
+     // Talk to a server via socket, using a binary protocol
+     TSocketClient *transport = [[TSocketClient alloc] initWithHostname:@"localhost" port:7911];
+     TBinaryProtocol *protocol = [[TBinaryProtocol alloc] initWithTransport:transport strictRead:YES strictWrite:YES];
+     server = [[BulletinBoardClient alloc] initWithProtocol:protocol];
+ }
+ 
+ - (void)viewDidUnload {
+     [self setTextField:nil];
+     [self setTextView:nil];
+     [super viewDidUnload];
+ }
+ 
+ - (IBAction)addPressed:(id)sender {
+     Message *msg = [[Message alloc] init];
+     msg.text = textField.text;
+     msg.date = [[NSDate date] description];
+     
+     [server add:msg];       // send data
+     
+     NSArray *array = [server get];    // receive data
+     NSMutableString *s = [NSMutableString stringWithCapacity:1000];
+     for (Message *m in array)
+         [s appendFormat:@"%@ %@\n", m.date, m.text];
+     textView.text = s;
+ }
+ 
+ - (BOOL)textFieldShouldReturn:(UITextField*)aTextField {
+     [aTextField resignFirstResponder];
+     return YES;
+ }
+ @end
+ }}}
+ 
+  * This code creates a new transport object that connects to localhost:7911, it then creates a protocol using the strict read and strict write settings.  These are important as the java server has strictRead off and strictWrite On by default.  In the iOS app they are both off by default.  If you omit these parameters the two objects will not be able to communicate.
  
  == Creating the Java Server ==
  
   * cd into the gen-java directory
-  * make sure that your classpath is properly setup.  You will need to ensure that libthrift.jar, slf4j-api, and slf4j-simple are in your classpath.
+  * make sure that your classpath is properly setup.  You will need to ensure that ".", libthrift.jar, slf4j-api, and slf4j-simple are in your classpath.
-  * create the file UserStorageImpl.java
+  * create the file BulletinBoardImpl.java
  
  {{{
  import org.apache.thrift.TException;
- import java.util.HashMap;
+ import java.util.List;
+ import java.util.ArrayList;
  
+ class BulletinBoardImpl implements BulletinBoard.Iface {
+     private List<Message> msgs;
- class UserStorageImpl implements UserStorage.Iface {
-     private HashMap<Integer, UserProfile> profiles;
- 
-    public UserStorageImpl() {
-        profiles = new HashMap<Integer, UserProfile>();
-    }
+     
+     public BulletinBoardImpl() {
+         msgs = new ArrayList<Message>();
- 
-    @Override
-    public void store(UserProfile user) throws TException {
-        long time = System.currentTimeMillis();
-        System.out.println("store() called: " + time);
-        System.out.println("UID: " + user.uid);
-        System.out.println("Name: " + user.name);
-        System.out.println("Blurb: " + user.blurb);
-        profiles.put(new Integer(user.uid), user);
      }
- 
+     
      @Override
-     public UserProfile retrieve(int uid) throws TException {
-         return profiles.get(new Integer(uid));
+     public void add(Message msg) throws TException {
+         System.out.println("date: " + msg.date);
+         System.out.println("text: " + msg.text);
+         msgs.add(msg);
+     }
+     
+     @Override
+     public List<Message> get() throws TException {
+         return msgs;
      }
  }
  }}}
@@ -89, +221 @@

  import org.apache.thrift.protocol.TBinaryProtocol;
  import org.apache.thrift.protocol.TBinaryProtocol.Factory;
  import org.apache.thrift.server.TServer;
+ import org.apache.thrift.server.TServer.Args;
- import org.apache.thrift.server.TThreadPoolServer;
+ import org.apache.thrift.server.TSimpleServer;
+ import org.apache.thrift.transport.TServerTransport;
  import org.apache.thrift.transport.TServerSocket;
  import org.apache.thrift.transport.TTransportException;
  
  public class Server {
- 
+     
      private void start() {
          try {
+             BulletinBoard.Processor processor = new BulletinBoard.Processor(new BulletinBoardImpl());
-             TServerSocket serverTransport = new TServerSocket(7911);
+             TServerTransport serverTransport = new TServerSocket(7911);
+             TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
+             
-             UserStorage.Processor processor = new UserStorage.Processor(new UserStorageImpl());
-             Factory protFactory = new TBinaryProtocol.Factory(true, true);
- 
-             TServer server = new TThreadPoolServer(processor, serverTransport, protFactory);
- 
              System.out.println("Starting server on port 7911 ...");
              server.serve();
          } catch (TTransportException e) {
@@ -111, +243 @@

              e.printStackTrace();
          }
      }
- 
+     
      public static void main(String args[]) {
          Server srv = new Server();
          srv.start();
@@ -125, +257 @@

  javac *.java
  }}}
  
+  * This will run a server that implements the service BulletinBoard on port 7911.  The service simply stores Message structures in a List and returns the list when requested.
+ 
+ == Running ==
+ 
   * run the server
  
  {{{
  java Server
  }}}
  
-  * This will run a server that implements the service UserStorage on port 7911.  The service simply stores UserProfile structures in a HashMap and retrieves them when requested.
+  * Build and run the myThriftApp '''in the iPhone simulator'''. Since it tries to connect to localhost, you need to run it in the iPhone simulator rather than an iPhone.
+    * Put a text in the text field and push add button.
  
+ {{http://staff.aist.go.jp/hirano-s/thrift/result.tiff|align=right}}
- == Create the Objective-C client ==
- The objective-c client is a simple cocoa application that allows the user to fill out the values of a UserProfiel structure and store/retrieve them from the server.
  
+ = Objective-C specific Notes =
-  * Create a new cocoa project.
-  * Right click on the classes group and Add existing files.  Browse to the gen-cocoa directory and add the files profile.h and profile.m
-  * Change the import lines in profile.h and profile.m from:
  
+ == Method signature ==
+ When a service with multiple arguments is compiled, argument names are omitted.
- {{{
- #import <TProtocol.h>
- #import <TApplicationException.h>
- #import <TProtocolUtil.h>
- #import <TProcessor.h>
- }}}
  
- to
- 
  {{{
- #import <Thrift/TProtocol.h>
- #import <Thrift/TApplicationException.h>
- #import <Thrift/TProtocolUtil.h>
- #import <Thrift/TProcessor.h>
+ // IDL
+ service TestService {
+    void method(1: i32 value1, 2: i32 value2),
+ }
  }}}
  
-  * Copy the following text to the app delegate header file
- 
  {{{
- #import <Cocoa/Cocoa.h>
+ void method:(int)value1 :(int)value2;
+ //   [server method:24  :33];
+ }}}
  
+ 
+ == Attributes ==
+ Struct members can be accessed via attributes of an instance.
+ {{{
+ // IDL
+ struct Person {
+   1: string name,
+   2: string city,
+ }
+ }}}
+ 
+ {{{
+    Person *p = [[Person alloc] init];
+    p.name = @"HIRANO";
+    p.city = @"Tsukuba";
+ }}}
+ 
+ == Initialization ==
+ Since 0.9.0 (0.9.0-dev), initialization of struct and const is supported.
+ 
+ {{{
+ // IDL
+ struct Person {
+   1: string name = "your name",
+   2: string city = "your city",
+ }
+ 
+ const list<Person> MyFamily = [{name: "Satoshi", city: "Tsukuba"}, {name: "Akiko", city: "Tokyo"}]
+ }}}
+ 
+ == String type ==
+ 
+ ''string'' is converted into UTF-8 encoding before sending. The UTF-8 encoding is converted to NSString* after receiving. 
+ 
+ {{{#!wiki note
+ Note all language versions convert encoding automatically. For example Python does not do encoding conversion. (Thus, you need to do conversion by yourself).
+ }}}
+ 
+ 
+ == Binary type ==
+ 
+ Thrift for Objective-C supports ''binary'' type as NSData*.
+ 
+ {{{
+ // IDL
+ struct Person {
+   1: string name,
+   2: binary photo,
+ 
+ service TestService {
+    void register(1: Person person),
+ }
+ }}}
+ 
+ {{{
+    Person *p = [[Person alloc] init];
+    p.name = @"HIRANO Satoshi";
+    NSImage *image = [NSImage imageNamed:@"hirano.png"];   // load an image
+    NSData *tiffData = [image TIFFRepresentation];   // obtain data
+    p.photo = tiffData;
+    [server register:p];
+ }}}
+ 
+ 
+ == Collection types ==
+ 
+ The objective-C version supports collection types, list, set and map as NSArray, NSSet, and NSDictionary.
+ 
+ {{{
+ // IDL
+ struct TestData {
+    list<string> listData,
+    set<string> setData,
+    map<string, string> mapData,
+ }
+ }}}
+ 
+ {{{
+   TestData *t = [[TestData alloc] init];
+   t.listData = [NSArray arrayWithObjects:@"a", @"b", nil];
+   t.setData = [NSSet setWithObjects::@"e", @"f", nil];
+   t.mapData = [NSDictionary dictionaryWithObjectsAndKeys:@"name", @"HIRANO", @"city", @"Tsukuba", nil];
+ }}}
+ 
+ == Client Side Transports ==
+ 
+ You can mainly use the socket transport and the HTTP transport.
+ 
+ Here is a client side example for the socket transport.
+ {{{
- #import <Thrift/TSocketClient.h>
+ #import <TSocketClient.h>
- #import <Thrift/TBinaryProtocol.h>
+ #import <TBinaryProtocol.h>
  
+ - (void) connect {
- #import "profile.h"
- 
- @interface ThriftCocoaAppDelegate : NSObject <NSApplicationDelegate> {
-   NSWindow *window;
-   NSTextField *uid;
-   NSTextField *name;
-   NSTextField *blurb;
-   
-   TSocketClient *transport;
-   TBinaryProtocol *protocol;
-   UserStorageClient *service;
- }
- 
- @property (assign) IBOutlet NSWindow *window;
- @property (assign) IBOutlet NSTextField *uid;
- @property (assign) IBOutlet NSTextField *name;
- @property (assign) IBOutlet NSTextField *blurb;
- 
- - (IBAction)store:(id)sender; // call thrift service store function.
- - (IBAction)retrieve:(id)sender; // call thrift service retrieve function.
- 
- @end
- }}}
-  5. Open the XIB file in Interface builder and drag out 3 NSTextField objects.  Connect these to the uid, name, and blurb outlets.
-  6. Drag out 2 buttons.  Label the first as 'Store' and connect it to the store action.  Label the other as retrieve and connect it to the retrieve action.
-  7. Copy the following code into the app delegate implementation file (the .m file)
- {{{
- #import "ThriftCocoaAppDelegate.h"
- #import "profile.h"
- 
- 
- @implementation ThriftCocoaAppDelegate
- 
- @synthesize window;
- @synthesize uid;
- @synthesize name;
- @synthesize blurb;
- 
- - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
-   // Talk to a server via TCP sockets, using a binary protocol
+     // Talk to a server via socket, using a binary protocol
-   transport = [[TSocketClient alloc] initWithHostname:@"localhost" 
+     TSocketClient *transport = [[TSocketClient alloc] initWithHostname:@"localhost" port:7911];
-                                                  port:7911];
-   protocol = [[TBinaryProtocol alloc] initWithTransport:transport 
+     TBinaryProtocol *protocol = [[TBinaryProtocol alloc] initWithTransport:transport strictRead:YES strictWrite:YES];
+     server = [[BulletinBoardClient alloc] initWithProtocol:protocol];
+ }}}
+ 
+ Here is a client side example for the HTTP transport. You may use https. You can connect to Google App Engine for example.
+ {{{
+ #import <THTTPClient.h>
+ #import <TBinaryProtocol.h>
+ 
+ - (void) connect {
+     NSURL *url = [NSURL URLWithString:@"http://localhost:8082"];
+     // url = [NSURL URLWithString:@"https://myapp145454.appspot.com"];
+     
+     // Talk to a server via HTTP, using a binary protocol
+     THTTPClient *transport = [[THTTPClient alloc] initWithURL:url];
+     TBinaryProtocol *protocol = [[TBinaryProtocol alloc] 
+                                  initWithTransport:transport 
-                                              strictRead:YES 
+                                  strictRead:YES 
-                                             strictWrite:YES];
+                                  strictWrite:YES];
-   
+ 
+     server = [[TestServiceClient alloc] initWithProtocol:protocol];
+ }}}
+ 
+ == Asynchronous Client ==
+ 
+ The asynchronous operation means that an RPC call returns immediately without waiting for the completion of a server operation. It is different from the oneway operation. An asynchronous operation continues in background to wait for completion and it is possible to receive a return value. This feature plays very important role in GUI based apps. You don't want to block for long time when a user pushes a button.
+ 
+ Unlike Java version, Objective-C version does not support asynchronous operation. 
+ 
+ However, it is possible to write asynchronous operations using ''NSOperationQueue''. The basic usage of ''NSOperationQueue'' is like this. Your async block is executed in a background thread.
+ 
+ {{{
+ [asyncQueue addOperationWithBlock:^(void) {
+     // your async block is here.
+     int val = [remoteServer operation];
+ }];
+ }}}
+ 
+ There are some points to be considered.
+ 
+  * Your async blocks are done in asyncQueue, an instance of ''NSOperationQueue''.
+  * Strong objects may not be accessed from a block. Since ''self'' is also a strong object, we need to avoid to access ''self'' within an async block. We use weakSelf, a weak reference to ''self''.
+  * GUI operations must be in the main thread. For example, ''uilabel.text = @"foo"''; must be done in the main thread and you may not write it in the above async block. A block that handles GUI is added to the ''mainQueue'' which represents the main thread. We use ''weaksSelf2'' in the nested async block.
+  * Exception handling is also needed.
+ 
+ Here are the fragments of ThriftTestViewController class.
+ {{{
+ // IDL
+ service TestService {
+    i32 sum(1: i32 value1, 2: i32 value2),
+ }
+ }}}
+ 
+ {{{
+ @interface ThriftTestViewController : UIViewController {
+     IBOutlet UILabel *msg;
+ }
+ @property (nonatomic, retain) UILabel *msg;
+ @property (nonatomic, strong) TestServiceClient *server;
+ @property (nonatomic, strong) NSOperationQueue *asyncQueue;
+ @property (nonatomic, strong) NSOperationQueue *mainQueue;
+ }}}
+ 
+ {{{
+ - (void )viewDidLoad {
+     asyncQueue = [[NSOperationQueue alloc] init];
+     [asyncQueue setMaxConcurrentOperationCount:1]; // serial
+     mainQueue = [NSOperationQueue mainQueue];   // for GUI, DB
+     
+     NSURL *url = [NSURL URLWithString:@"http://localhost:8082"];
+ 
+     // Talk to a server via HTTP, using a binary protocol
+     THTTPClient *transport = [[THTTPClient alloc] initWithURL:url];
+     TBinaryProtocol *protocol = [[TBinaryProtocol alloc] 
+                                  initWithTransport:transport 
+                                  strictRead:YES 
+                                  strictWrite:YES];
-   // Use the service defined in profile.thrift
+     // Use the service defined in profile.thrift
-   service = [[UserStorageClient alloc] initWithProtocol:protocol];
+     server = [[TestServiceClient alloc] initWithProtocol:protocol];
+     NSLog(@"Client init done %@", url);
  }
  
- - (void)store:(id)sender {
-   NSLog(@"Called store.");
-   // Make an object
-   UserProfile *up = [[UserProfile alloc] initWithUid:[[uid stringValue] intValue]
-                                                 name:[name stringValue]
-                                                blurb:[blurb stringValue]];
-   
-   // call the store function on the service
-   [service store:up];
- }
  
- - (void)retrieve:(id)sender {
-   NSLog(@"Called retrieve.");
-   // Retrieve something as well
-   UserProfile *up = [service retrieve:[[uid stringValue] intValue]];
-   NSLog(@"Received User Profile: %@", up);
-   [uid setStringValue:[NSString stringWithFormat:@"%d", [up uid]]];
-   [name setStringValue:[up name]];
-   [blurb setStringValue:[up blurb]];
+ -(void)doCalc {
+     __unsafe_unretained ThriftTestViewController *weakSelf = self;
+     [asyncQueue addOperationWithBlock:^(void) {
+         __unsafe_unretained ThriftTestViewController *weakSelf2 = weakSelf;
+         @try {
+             weakSelf.msg.text = nil;
+             int result = [weakSelf.server calc:24 :32];
+             [weakSelf.mainQueue addOperationWithBlock:^(void) {
+                 weakSelf2.msg.text = [NSString stringWithFormat:@"%d", result];
+             }];
+         }
+         @catch (TException *e) {
+             NSString *errorMsg = e.description;
+             NSLog(@"Error %@", errorMsg);
+             [weakSelf.mainQueue addOperationWithBlock:^(void) {
+                 weakSelf2.msg.text = errorMsg;
+             }];
+         }
+     }];
  }
- 
- @end
  }}}
  
-  * This code creates a new transport object that connects to localhost:7911, it then creates a protocol using the strict read and strict write settings.  These are important as the java server has strictRead off and strictWrite On by default.  In the cocoa app they are both off by default.  If you omit these parameters the two objects will not be able to communicate.  We then create a UserStorage service.
-  * If the user presses the store button a new UserProfile object is created with the values in the text field and the store function is called on the service.
-  * If the user presses the retrieve button the uid is read and retrieve is called.  If a result is returned the values are unpacked into the GUI.
- 
-  * The last thing you need to do is add the Thrift framework to your project.  Right click on the Frameworks->Linked Frameworks group and add existing frameworks.  Select 'add other' and locate the compiled Thrift.framework on disk (this is under the build directory of the project you downloaded and compiled earlier).
-  * Under target right click and Add New Build Phase->New copy file build phase.  Change the destination to Frameworks and press CTRL+click and drag the Thrift.framework object to the copy files build phase.  Make sure that the Thrift.framework object is copied out of the previous area ... not moved.
- 
-  * At this point you should be able to compile the code and run it.
- 
- You can download the Xcode project for this step: [[attachment:ThriftObjectiveCClient.zip]]
-