Integration Example

Poker Example

Let’s say you have a poker application, Texas Hold’em of course. Your users can sign in, create an account, choose an avatar, get a certain amount of in-game money, and play in tournaments against other players. In addition to the social data that already exists in a user’s record, the following list represents some of the game-specific information your app may like to collect as the player engages in various tournaments:

Let’s say that “tournaments played” is a list (plural) of objects, where each object stores the following information:

Let’s say that the “best hand” is an object that stores the following information:

Let’s say that “favorite hands” is just a list of two-character strings, representing Hold’em starting hands.

First, these fields would need to be added to your schema. Here is what that portion of the schema would look like:

...
  {
    "name": "playerName",
    "type": "string",
    "description": "the name that is displayed below the player’s avatar"
  },
  {
    "name": "avatar",
    "type": "string",
    "description": "the name of the avatar which is used to represent the player at tournament tables"
  },
  {
    "name": "bankroll",
    "type": "decimal",
    "description": "the player’s current in-game bankroll"
  },
  {
    "name": "tournamentsPlayed",
    "type": "plural",
    "description": "a list of the tournaments in which the player has competed",
    "attr_defs": [
      {
        "name": "tournamentDate",
        "type": "datetime",
        "description": "the date and time that the tournament started"
      },
      {
        "name": "tournamentSize",
        "type": "integer",
        "description": "the number of people seated in the tournament"
      },
      {
        "name": "buyIn",
        "type": "decimal",
        "description": "the buy-in for the tournament"
      },
      {
        "name": "placed",
        "type": "integer",
        "description": "where the player placed in the tournament"
      },
      {
        "name": "wonMoney",
        "type": "boolean",
        "description": "whether or not the player won any money"
      },
      {
        "name": "moneyWon",
        "type": "decimal",
        "description": "the amount of money won, if any"
      }
    ]
  },
  {
    "name": "bestHand",
    "type": "object",
    "description": "the best hand your player has ever had in a tournament",
    "attr_defs": [
      {
        "name": "hand",
        "type": "string",
        "description": "the hand"
      },
      {
        "name": "handBeat",
        "type": "string",
        "description": "the hand that was beat"
      },
      {
        "name": "datePlayed",
        "type": "date",
        "description": "the date on which the hand was played"
      },
      {
        "name": "moneyWon",
        "type": "decimal",
        "description": "the pot won on the hand"
      }
    ]
  },
  {
    "name": "favoriteHands",
    "type": "plural",
    "description": "the player’s favorite hands",
    "attr_defs": [
      {
        "name": "hand",
        "type": "string",
        "description": "the hand"
      }
    ]
  }
...

In this example, each property, or attribute, has a name, type, and description. The name and type are used to create the properties of the generated Objective-C objects. The description is used to generate the attribute’s documentation. For a mapping of schema types to Objective-C types, see JRCaptureTypes.h in the JUMP for iOS source code.

Adding the Fields to Registration

Add these fields to the database. You can do so using the entityType.addAttribute API call. (Invoked once for each attribute.) Alternatively you can download an existing schema with entityType, add the above attributes, and create a new entity type with entityType.create.

When successful, the response from Registration contains the updated schema, with your newly added attributes. Save this response as your new schema.

By convention, attributes in schemas are camelCased. Follow this convention to ensure that the attributes in the generated user record model are also camel cased.

Warning: It is safer to add new attributes to a schema than to remove existing attributes. Contact your deployment engineer before removing attributes.

After you add the new attributes, you need your new schema, which you will use to generate or regenerate the code.

Save your new schema and change into the script directory:
$ cd jump.ios/Janrain/JRCapture/Script

Run the CaptureSchemaParser.pl Perl script, passing in your schema as an argument with the -f flag.
$ ./CaptureSchemaParser.pl -f/

The script sends the output to jump.ios/Janrain/JRCapture/Classes/CaptureUserModel/Generated/, which contains the new and updated Objective-C classes. The top-level class, JRCaptureUser, now has six new properties. Likewise, your generated user model now has two new classes, JRBestHand and JRTournamentsPlayedElement.

Here are the added properties in JRCaptureUser.h, with the comments removed for readability:

@interface JRCaptureUser : JRCaptureObject
@property (nonatomic, copy) NSString *displayName;
@property (nonatomic, copy) NSString *avatar;
@property (nonatomic, copy) NSNumber *bankroll;
@property (nonatomic, copy) NSArray *tournamentsPlayed;
@property (nonatomic, retain) JRBestHand *bestHand;
@property (nonatomic, copy) JRStringArray *favoriteHands;
...
@end

Here are the properties of the JRBestHand object:

@interface JRBestHand : JRCaptureObject
@property (nonatomic, copy) NSString *hand;
@property (nonatomic, copy) NSString *handBeat;
@property (nonatomic, copy) JRDate *datePlayed;
@property (nonatomic, copy) JRDecimal *moneyWon;
...
@end

Here are the properties of the JRTournamentsPlayedElement, which is the object stored in JRCaptureUser object’s tournamentsPlayed array:

@interface JRTournamentsPlayedElement : JRCaptureObject
@property (nonatomic, copy) JRDateTime *tournamentDate;
@property (nonatomic, copy) JRInteger *placed;
@property (nonatomic, copy) JRBoolean *wonMoney;
@property (nonatomic, copy) JRDecimal *moneyWon;
...
@end

One of the great advantages of using the Registration user model generated code is how easily you can leverage an IDE’s code completion to quickly inspect and update the fields in your user record.

As shown in the image below, you can easily see the properties and types belonging to the JRBestHand object:

Notes:

Follow Generating the Registration User Model for instructions on how to add the newly generated user model classes to your Xcode project.

Using Your Code — Collecting the Basic Info

In our example poker app, let’s assume it’s the first time your player has logged in, and they are prompted to choose their display name and avatar and they are automatically given $1000 in-game money to get them going.

After the user logs in, in the delegate method captureAuthenticationDidSucceedForUser:status:, the record status of new users is set to JRCaptureRecordNewlyCreated.
Your app may display a screen that asks the user for their display name and lets them select one of your in-game avatars and when they’re done, you can award them with a starting bank.
Next, save this data to the JRCaptureUser object through the appropriate object properties:

captureUser.playerName = playerNameTextField.text;
captureUser.avatar = [avatars objectAtIndex:[avatarPicker selectedRowInComponent:0]];
captureUser.bankroll = [NSNumber numberWithDouble:1000.0];

UIAlertView *alertView =
[[UIAlertView alloc] initWithTitle:@"Welcome!"
                           message:@"You have just been awarded $1000 for joining!"
                          delegate:nil
                 cancelButtonTitle:@"Dismiss"
                 otherButtonTitles:nil];
[alertView show];

Last, update the JRCaptureUser object in Registration, and you’re done!

[captureUser updateOnCaptureForDelegate:self context:nil];

You may respond to the updateDidSucceedForObject:context: message for notification of success:

- (void)updateDidSucceedForObject:(JRCaptureObject *)object context:(NSObject *)context
{
    // Successful update
}

Similarly the updateDidFailForObject:withError:context: message is sent on failure.

Using Your Code — Updating Sub-Objects

As you can see, the JRCaptureUser class contains the property bestHand of type JRBestHand. As play progresses, your app can continually update the bestHand property, and push the updates to Registration:

- (void)maybeUpdateBestHand:(NSString *) newHand beatHand:(NSString *)beatHand
                  moneyWon:(NSNumber *) moneyWon
{
   if (compareHands(captureUser.bestHand.hand, newHand))
   {
       captureUser.bestHand.hand = newHand;
       captureUser.besthand.beatHand = beatHand;
       // ... and so on for the money won and date played
       [captureUser.bestHand updateOnCaptureForDelegate:self context:nil];
   }
}

int compareHands(NSString *a, NSString *b)
{
   // implementation omitted
}