SlideShare ist ein Scribd-Unternehmen logo
1 von 109
Stefano Zanetti § DevCamp
Parse.com
iOS App with Parse.com as RESTful Backend
DevCamp
Stefano Zanetti
 Apple iOS Developer
Superpartes Innovation Campus & H-Farm
 Co-founder di
# Pragma Mark ― www.pragmamark.org
 [tt] @Doh__
[in] Stefano Zanetti
[fb] stefano.znt
[email] zanetti.stefano@gmail.com
DevCamp
What is Parse.com?
The perfect cloud for your apps.
Parse allows your team to focus on creating a
great user experience and forget server
maintenance and complex infrastructure.
DevCamp
What does this mean?
• Backend for apps and websites
• Database NoSQL (schemaless: if you need to store
something, store key/value data without prepare any table)
• Store your app’s data in the cloud
• Parse automatically creates RESTful API for you
• Push notification
• Social
• Hosting
• Cloud code
DevCamp
Who can you it?
DevCamp
How much?
BasicBasicBasic ProProPro EnterpriseEnterpriseEnterprise
Great for developer to get startedGreat for developer to get startedGreat for developer to get started For Production applicationsFor Production applicationsFor Production applications For advanced featuresFor advanced featuresFor advanced features
FREEFREEFREE $199/month$199/month$199/month contact Parsecontact Parsecontact Parse
Request Pushes Burst limit Request Pushes Burst limit Request Pushes Burst limit
1 milion/
month
1 milion/
month
20/second
15 milion/
month
5 milion/
month
40/second
contact
Parse
DevCamp
Features
DevCamp
More features
DevCamp
App Settings
DevCamp
Where?
http://www.parse.com
DevCamp
Dashboard
DevCamp
General
DevCamp
Application Keys
DevCamp
Push Notifications
DevCamp
Web Hosting
DevCamp
Administrative Tools
DevCamp
Data Browser
DevCamp
Analytics
DevCamp
Push Notifications Status
DevCamp
Send push
DevCamp
Demo
DevCamp
Get started
DevCamp
SDK
• Quick start:
• https://www.parse.com/docs
• Download from official site:
• https://www.parse.com/docs/downloads/
• CocoaPods:
• pod 'Parse', '~> 1.2.9'
DevCamp
Quick start
DevCamp
Quick start
[Parse
setApplicationId:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
clientKey:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"];
1.Download the Sample Project
2.Xcode 4.6+ and iOS targetting 4.3+
3.Open project and uncomment the first line of
application:didFinishLaunchingWithOptions: in the
application delegate file:
4.Compile and run
DevCamp
Create & Save an Object
PFObject *testObject = [PFObject
objectWithClassName:@"TestObject"];
[testObject setObject:@"bar" forKey:@"foo"];
[testObject save];
5.Copy and paste next code somewhere in the
project
6.Compile and run
DevCamp
Yeah!!
You saved your first object
DevCamp
Which libraries Parse needs?
• AudioToolbox.framework
• CFNetwork.framework
• CoreGraphics.framework
• CoreLocation.framework
• libz.1.1.3.dylib
• MobileCoreServices.framework
• QuartzCore.framework
• Security.framework
• StoreKit.framework
• SystemConfiguration.framework
• AdSupport.framework (optional if iOS targetting is than then
6.0)
• Social.framework (optional if iOS targetting is less than 6.0)
• Accounts.framework (optional if iOS targetting is less than 6.0)
If you're targeting iOS versions less than 5.0, you'll need to add the "-fobjc-
arc" flag to the "Other Linker Flags" entry in your target build settings.
DevCamp
PFObject
DevCamp
Saving/Updating Objects
PFObject *post = [PFObject objectWithClassName:@"Post"];
[post setObject:@"New post" forKey:@"title"];
[post setObject:@"This is my first message" forKey:@"message"];
[post setObject:[NSNumber numberWithBool:NO] forKey:@"visible"];
[post save];
• PFObject contains key-value pairs of JSON-
compatible data.
• This data is schemaless
• Interface is similar to NSMutableDictionary
DevCamp
Check Data Browser
• You don't have to configure or set up a new Class
• You don't need to specify a key for the object you are saving
Parse automatically fills 3 field:
• objectId
• createdAt
• updatedAt
objectId: "xWMyZ4YEGZ", title: "New post", message: "This is my
first message", visible: false, createdAt:"2011-06-10T18:33:42Z",
updatedAt:"2011-06-10T18:33:42Z"
DevCamp
Retriving Data
Using PFQuery you can retrive a PFObject
PFQuery *query = [PFQuery queryWithClassName:@"Post"];
PFObject *post = [query getObjectWithId:@"xWMyZ4YEGZ"];
NSString *postTitle = [post objectForKey:@"title"];
BOOL visible = [[post objectForKey:@"visible"] boolValue];
DevCamp
Note!!
The three special values are provided as properties:
NSString *objectId = post.objectId;
NSDate *updatedAt = post.updatedAt;
NSDate *createdAt = post.createdAt;
If you need to refresh an object you already have with the
latest data that is in the Parse Cloud, you can call the
refresh method like so:
[myObject refresh];
DevCamp
Saving in background
Just call saveInBackground method
[post saveInBackground];
DevCamp
Blocks
If you want to run code when operation is completed you
can use blocks (iOS 4.0+) or callbacks methods.
[post saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  if (!error) {
    // The Post saved successfully.
  } else {
    // There was an error saving the Post.
  }
}];
DevCamp
Callbacks
// First set up a callback.
- (void)saveCallback:(NSNumber *)result error:(NSError *)error {
  if (!error) {
    // The Post saved successfully.
  } else {
    // There was an error saving the Post.
  }
}
 
// Then, elsewhere in your code...
[post saveInBackgroundWithTarget:self
selector:@selector(saveCallback:error:)];
DevCamp
Load in background
PFQuery *query = [PFQuery queryWithClassName:@"Post"];
[query getObjectInBackgroundWithId:@"xWMyZ4YEGZ"
                             block:^(PFObject *post, NSError
*error) {
  if (!error) {
    // The get request succeeded. Log the score
    NSLog(@"The title is: %d", [[post objectForKey:@"title"]
intValue]);
  } else {
    // Log details of our failure
    NSLog(@"Error: %@ %@", error, [error userInfo]);
  }
}];
With Blocks
DevCamp
Load in background
// First set up a callback.
- (void)getCallback:(PFObject *)post error:(NSError *)error {
  if (!error) {
    // The get request succeeded. Log the score
    NSLog(@"The title is: %d", [[post objectForKey:@"title"] intValue]);
  } else {
    // Log details of our failure
    NSLog(@"Error: %@ %@", error, [error userInfo]);
  }
}
 
// Then, elsewhere in your code...
PFQuery *query = [PFQuery queryWithClassName:@"Post"];
[query getObjectInBackgroundWithId:@"xWMyZ4YEGZ"
                            target:self
                          selector:@selector(getCallback:error:)];
With CallBacks
DevCamp
Saving Objects Offline
Just call saveEventually method and system store the update
on the device until a network connection is available
[post saveEventually];
DevCamp
Saving Counter Objects
The “likes” field is a counter:
[post incrementKey:@"likes"];
[post saveInBackground];
or
[post incrementKey:@"likes" byAmount:3];
[post saveInBackground];
DevCamp
Saving Array Objects
• addObject:forKey: and addObjectsFromArray:forKey: append the given
objects to the end of an array field.
• addUniqueObject:forKey: and addUniqueObjectsFromArray:forKey: add only
the given objects which aren't already contained in an array field to that
field.The position of the insert is not guaranteed.
• removeObject:forKey: and removeObjectsInArray:forKey: remove all
instances of each given object from an array field.
[post addUniqueObjectsFromArray:[NSArray
arrayWithObjects:@"stefano", @"massimo", nil] forKey:@"users"];
[post saveInBackground];
DevCamp
Delete Objects
To delete an object from the cloud:
[myObject deleteInBackground];
To delete e single field from an Object:
// After this, the visilble field will be empty
[myObject removeObjectForKey:@"visible"];
 
// Saves the field deletion to the Parse Cloud
[myObject saveInBackground];
DevCamp
Demo
DevCamp
Relational Data
DevCamp
One-To-Many Relationship
// Create the post
PFObject *myPost = [PFObject objectWithClassName:@"Post"];
[myPost setObject:@"I'm Hungry" forKey:@"title"];
[myPost setObject:@"Where should we go for lunch?" forKey:@"content"];
 
// Create the comment
PFObject *myComment = [PFObject objectWithClassName:@"Comment"];
[myComment setObject:@"Let's do Sushirrito." forKey:@"content"];
 
// Add a relation between the Post and Comment
[myComment setObject:myPost forKey:@"parent"];
 
// This will save both myPost and myComment
[myComment saveInBackground];
You can link objects:
DevCamp
One-To-Many Relationship
You can also link objects using just their objectIds like so:
// Add a relation between the Post with objectId "1zEcyElZ80" and
the comment
[myComment setObject:[PFObject
objectWithoutDataWithClassName:@"Post" objectId:@"1zEcyElZ80"]
              forKey:@"parent"];
DevCamp
One-To-Many Relationship
By default, when fetching an object, related
PFObjects are not fetched:
PFObject *post = [fetchedComment objectForKey:@"parent"];
[post fetchIfNeededInBackgroundWithBlock:^(PFObject *object,
NSError *error) {
  NSString *title = [post objectForKey:@"title"];
}];
DevCamp
Many-To-Many Relationship
A User may have many Posts that they might like.
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationforKey:@"likes"];
[relation addObject:post];
[user saveInBackground];
Add relation:
[relation removeObject:post];
Remove relation:
DevCamp
Many-To-Many Relationship
By default, the list of objects in this relation
are not downloaded
[[relation query] findObjectsInBackgroundWithBlock:^(NSArray
*objects, NSError *error) {
  if (error) {
     // There was an error
  } else {
    // objects has all the Posts the current user liked.
  }
}];
DevCamp
Many-To-Many Relationship
If you want only a subset of the Posts you can add
extra constraints to the PFQuery returned by query
PFQuery *query = [relation query];
// Add other query constraints.
DevCamp
Data types
DevCamp
What types are supported?
NSNumber *number = [NSNumber numberWithInt:42];
NSString *string = [NSString stringWithFormat:@"the number is %i", number];
NSDate *date = [NSDate date];
NSData *data = [@"foo" dataUsingEncoding:NSUTF8StringEncoding];
NSArray *array = [NSArray arrayWithObjects:string, number, nil];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:number, @"number",
                                                                      string, @"string",
                                                                      nil];
NSNull *null = [NSNull null];
 
PFObject *bigObject = [PFObject objectWithClassName:@"BigObject"];
[bigObject setObject:number    forKey:@"myNumber"];
[bigObject setObject:string    forKey:@"myString"];
[bigObject setObject:date      forKey:@"myDate"];
[bigObject setObject:data      forKey:@"myData"];
[bigObject setObject:array     forKey:@"myArray"];
[bigObject setObject:dictionary forKey:@"myDictionary"];
[bigObject setObject:null      forKey:@"myNull"];
[bigObject saveInBackground];
Are supported: NSString, NSNumber, NSDate, NSData, and NSNull.You can nest
NSDictionary and NSArray objects to store more structured data within a single PFObject.
DevCamp
PFQuery
DevCamp
Basic Queries
PFQuery *query = [PFQuery queryWithClassName:@"Post"];
[query whereKey:@"title" equalTo:@"pragmamark"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError
*error) {
  if (!error) {
    // The find succeeded.
    NSLog(@"Successfully retrieved %d scores.", objects.count);
  } else {
    // Log details of the failure
    NSLog(@"Error: %@ %@", error, [error userInfo]);
  }
}];
The general pattern is to create a PFQuery, put conditions on it, and then retrieve a
NSArray of matching PFObjects using either findObjectsInBackgroundWithBlock: or
findObjectsInBackgroundWithTarget:selector:
DevCamp
Basic Queries
// Only use this code if you are already running it in a background
// thread, or for testing purposes!
PFQuery *query = [PFQuery queryWithClassName:@"Post"];
[query whereKey:@"title" equalTo:@"pragmamark"];
NSArray* scoreArray = [query findObjects];
If you are already in a background thread:
DevCamp
NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:
                          @"title = 'pragmamark'"];
PFQuery *query = [PFQuery queryWithClassName:@"Post" predicate:predicate];
These features are supported:
• Simple comparisons such as =, !=, <, >, <=, >=, and BETWEEN with a key and a constant.
• Containment predicates, such as x IN {1, 2, 3}.
• Key-existence predicates, such as x IN SELF.
• BEGINSWITH expressions.
• Compound predicates with AND, OR, and NOT.
• Sub-queries with "key IN %@", subquery.
The following types of predicates are not supported:
• Aggregate operations, such as ANY, SOME,ALL, or NONE.
• Regular expressions, such as LIKE, MATCHES, CONTAINS, or ENDSWITH.
• Predicates comparing one key to another.
• Complex predicates with many ORed clauses.
DevCamp
Query Constraints
[query whereKey:@"playerName" notEqualTo:@"Michael Yabuti"];
[query whereKey:@"playerAge" greaterThan:[NSNumber numberWithInt:18]];
query.limit = 10; // limit to at most 10 results
query.skip = 10; // skip the first 10 results
// Sorts the results in ascending order by the score field
[query orderByAscending:@"score"];
 
// Sorts the results in descending order by the score field
[query orderByDescending:@"score"];
// Restricts to wins < 50
[query whereKey:@"wins" lessThan:[NSNumber numberWithInt:50]];
 
// Restricts to wins <= 50
[query whereKey:@"wins" lessThanOrEqualTo:[NSNumber numberWithInt:50]];
 
// Restricts to wins > 50
[query whereKey:@"wins" greaterThan:[NSNumber numberWithInt:50]];
 
// Restricts to wins >= 50
[query whereKey:@"wins" greaterThanOrEqualTo:[NSNumber numberWithInt:50]];
DevCamp
Constraints on Array
// Finds scores from anyone who is neither Jonathan, Dario, nor
Shawn
NSArray *names = [NSArray arrayWithObjects:@"Jonathan Walsh",
                                           @"Dario Wunsch",
                                           @"Shawn Simon",
                                           nil];
[query whereKey:@"playerName" notContainedIn:names];
or
[query whereKey:@"playerName" containedIn:names];
If you want to retrieve objects matching several different values
DevCamp
Constraints on Array
// Find objects where the array in arrayKey contains 2.
[query whereKey:@"arrayKey" equalTo:[NSNumber numberWithInt:2]];
For keys with an array type, you can find objects where the key's
array value contains 2 by:
// Find objects where the array in arrayKey contains each of the
// elements 2, 3, and 4.
[query whereKey:@"arrayKey" containsAllObjectsInArray:@[@2, @3,
@4]];
You can also find objects where the key's array value contains
each of the values 2, 3, and 4 with the following:
DevCamp
Check particular key
// Finds objects that have the score set
[query whereKeyExists:@"score"];
 
// Finds objects that don't have the score set
[query whereKeyDoesNotExist:@"score"];
If you want to retrieve objects that have a particular key set or not:
DevCamp
Matches Key
PFQuery *teamQuery = [PFQuery queryWithClassName:@"Team"];
[teamQuery whereKey:@"winPct" greaterThan:[NSNumber withDouble:
0.5]];
PFQuery *userQuery = [PFQuery queryForUser];
[userQuery whereKey:@"hometown" matchesKey:@"city"
inQuery:teamQuery];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *results,
NSError *error) {
    // results will contain users with a hometown team with a
winning record
}];
You can use the whereKey:matchesKey:inQuery: method to get objects
where a key matches the value of a key in a set of objects resulting from
another query. (use whereKey:doesNotMatchKey:inQuery: to get objects
where a key does not match)
DevCamp
Restrict the returned fields
PFQuery *query = [PFQuery queryWithClassName:@"GameScore"];
[query selectKeys:@[@"playerName", @"score"]];
NSArray *results = [query findObjects];
The remaining fields can be fetched later by calling one of the
fetchIfNeeded variants on the returned objects:
PFObject *object = (PFObject*)[results objectAtIndex:0];
[object fetchIfNeededInBackgroundWithBlock:^(PFObject *object,
NSError *error) {
  // all fields of the object will now be available here.
}];
DevCamp
Queries on string value
// Finds barbecue sauces that start with "Big Daddy's".
PFQuery *query = [PFQuery queryWithClassName:@"BarbecueSauce"];
[query whereKey:@"name" hasPrefix:@"Big Daddy's"];
DevCamp
Relational queries
// Assume PFObject *myPost was previously created.
PFQuery *query = [PFQuery queryWithClassName:@"Comment"];
[query whereKey:@"post" equalTo:myPost];
 
[query findObjectsInBackgroundWithBlock:^(NSArray *comments,
NSError *error) {
    // comments now contains the comments for myPost
}];
If you want to retrieve objects where a field matches a particular PFObject,
you can use whereKey:equalTo: just like for other data types.
[query whereKey:@"post"
        equalTo:[PFObject objectWithoutDataWithClassName:@"Post"
objectId:@"1zEcyElZ80"]];
DevCamp
Matches Query
PFQuery *innerQuery = [PFQuery queryWithClassName:@"Post"];
[innerQuery whereKeyExists:@"image"];
PFQuery *query = [PFQuery queryWithClassName:@"Comment"];
[query whereKey:@"post" matchesQuery:innerQuery];
[query findObjectsInBackgroundWithBlock:^(NSArray *comments,
NSError *error) {
    // comments now contains the comments for posts with images
}];
If you want to retrieve objects where a field contains (or not) a PFObject
that match a different query, you can use whereKey:matchesQuery: (or
whereKey:notMatchQuery:)
Note that the default limit of 100 and maximum limit of 1000
apply to the inner query as well.
DevCamp
Include Key
PFQuery *query = [PFQuery queryWithClassName:@"Comment"];
// Retrieve the most recent ones
[query orderByDescending:@"createdAt"];
// Only retrieve the last ten
query.limit = [NSNumber numberWithInt:10];
// Include the post data with each comment
[query includeKey:@"post"];
 
[query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) {
    // Comments now contains the last ten comments, and the "post" field
    // has been populated. For example:
    for (PFObject *comment in comments) {
         // This does not require a network access.
         PFObject *post = [comment objectForKey:@"post"];
         NSLog(@"retrieved related post: %@", post);
    }
}];
If you want to return multiple types of related objects in one query use
includeKey: method:
DevCamp
Include Key
[query includeKey:@"post.author"];
You can also do multi level includes using dot notation:
DevCamp
Caching Policy
query.cachePolicy = kPFCachePolicyNetworkElseCache;
The default query behavior doesn't use the cache, but you can enable
caching by setting query.cachePolicy.
• kPFCachePolicyIgnoreCache: is the default cache policy.
• kPFCachePolicyCacheOnly :The query only loads from the cache, ignoring the network. If there are
no cached results, that causes a PFError.
• kPFCachePolicyNetworkOnly:The query does not load from the cache, but it will save results to
the cache.
• kPFCachePolicyCacheElseNetwork:The query first tries to load from the cache, but if that fails, it
loads results from the network. If neither cache nor network succeed, there is a PFError.
• kPFCachePolicyNetworkElseCache:The query first tries to load from the network, but if that
fails, it loads results from the cache. If neither network nor cache succeed, there is a PFError.
• kPFCachePolicyCacheThenNetwork:The query first loads from the cache, then loads from the
network. In this case, the callback will actually be called twice - first with the cached results, then with the
network results. Since it returns two results at different times, this cache policy cannot be used
synchronously with findObjects.
DevCamp
Control the cache’s behavior
BOOL isInCache = [query hasCachedResult];
Check to see if there is a cached result for the query with:
[query clearCachedResult];
Remove any cached results for a query with:
[PFQuery clearAllCachedResults];
Remove cached results for queries with:
query.maxCacheAge = 60 * 60 * 24;  // One day, in seconds.
Control the maximum age of a cached result with:
DevCamp
Counting Objects
PFQuery *query = [PFQuery queryWithClassName:@"GameScore"];
[query whereKey:@"playername" equalTo:@"Sean Plott"];
[query countObjectsInBackgroundWithBlock:^(int count, NSError
*error) {
  if (!error) {
    // The count request succeeded. Log the count
    NSLog(@"Sean has played %d games", count);
  } else {
    // The request failed
  }
}];
If you just need to count how many objects match a query, but you do not
need to retrieve the objects that match, you can use countObjects instead of
findObjects.
DevCamp
Compound Queries
PFQuery *lotsOfWins = [PFQuery queryWithClassName:@"Player"];
[lotsOfWins whereKey:@"wins" greaterThan:[NSNumber numberWithInt:
150]];
 
PFQuery *fewWins = [PFQuery queryWithClassName:@"Player"];
[fewWins whereKey:@"wins" lessThan:[NSNumber numberWithInt:5]];
PFQuery *query = [PFQuery orQueryWithSubqueries:[NSArray
arrayWithObjects:fewWins,lotsOfWins,nil]];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError
*error) {
  // results contains players with lots of wins or only a few wins.
  }];
If you want to find objects that match one of several queries, you can use
orQueryWithSubqueries: method.
DevCamp
Subclasses
DevCamp
Subclassing PFObject
1.Declare a subclass which conforms to the PFSubclassing protocol.
2.Implement the class method parseClassName.This is the string you would
pass to initWithClassName: and makes all future class name references
unnecessary.
3.Import PFObject+Subclass in your .m file.This implements all methods in
PFSubclassing beyond parseClassName.
4.Call [YourClass registerSubclass] in your ApplicationDelegate before
Parse setApplicationId:clientKey:.
DevCamp
Example of Subclassing
// Armor.h
@interface Armor : PFObject<PFSubclassing>
+ (NSString *)parseClassName;
@end
 
// Armor.m
// Import this header to let Armor know that PFObject privately provides most
// of the methods for PFSubclassing.
#import <Parse/PFObject+Subclass.h>
 
@implementation Armor
+ (NSString *)parseClassName {
  return @"Armor";
}
@end
 
// AppDelegate.m
#import <Parse/Parse.h>
#import "Armor.h"
 
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [Armor registerSubclass];
  [Parse setApplicationId:parseAppId clientKey:parseClientKey];
}
DevCamp
Property & methods
// Armor.h
@interface Armor : PFObject<PFSubclassing>
+ (NSString *)parseClassName;
@property (retain) NSString *displayName;
@end
 
// Armor.m
@dynamic displayName;
@dynamic iconFile;
 
- (UIImageView *)iconView {
  PFImageView *view = [[PFImageView alloc]
initWithImage:kPlaceholderImage];
  view.file = self.iconFile;
  [view loadInBackground];
  return [view autorelease];
}
DevCamp
Query
PFQuery *query = [Armor query];
[query whereKey:@"rupees"
lessThanOrEqualTo:PFUser.currentUser.rupees];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError
*error) {
  if (!error) {
    Armor *firstArmor = [objects objectAtIndex:0];
    // ...
  }
}];
DevCamp
PFFile
DevCamp
Why PFFile?
PFFile lets you store application files in the cloud that would otherwise be
too large or cumbersome to fit into a regular PFObject. (up to 10 megabytes)
DevCamp
Saving a file on the cloud
Then you can associate a PFFile onto a PFObject just like any other piece of
data:
NSData *data = [@"Working at Parse is great!"
dataUsingEncoding:NSUTF8StringEncoding];
PFFile *file = [PFFile fileWithName:@"resume.txt" data:data];
[file saveInBackground];
PFObject *jobApplication = [PFObject
objectWithClassName:@"JobApplication"]
[jobApplication setObject:@"Joe Smith" forKey:@"applicantName"];
[jobApplication setObject:file       
forKey:@"applicantResumeFile"];
[jobApplication saveInBackground];
DevCamp
Upload / Download
NSData *data = [@"Working at Parse is great!"
dataUsingEncoding:NSUTF8StringEncoding];
PFFile *file = [PFFile fileWithName:@"resume.txt" data:data];
[file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
  // Handle success or failure here ...
} progressBlock:^(int percentDone) {
  // Update your progress spinner here. percentDone will be between
0 and 100.
}];
Use saveInBackgroundWithBlock:progressBlock: and
getDataInBackgroundWithBlock:progressBlock:
DevCamp
PFUser
DevCamp
SignUp / SignIn
PFUser *user = [PFUser user];
    user.username = @"my name";
    user.password = @"my pass";
    user.email = @"email@example.com";
 
    // other fields can be set just like with PFObject
    [user setObject:@"415-392-0202" forKey:@"phone"];
 
    [user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
      if (!error) {
          // Hooray! Let them use the app now.
      } else {
          NSString *errorString = [[error userInfo] objectForKey:@"error"];
          // Show the errorString somewhere and let the user try again.
      }
    }];
[PFUser logInWithUsernameInBackground:@"myname" password:@"mypass"
  block:^(PFUser *user, NSError *error) {
    if (user) {
        // Do stuff after successful login.
    } else {
        // The login failed. Check error to see why.
    }
}]
DevCamp
Current User
PFUser *currentUser = [PFUser currentUser];
To get the current logged user you use the cached currentUser object:
[PFUser logOut];
You can clear the current user by logging them out:
DevCamp
PFACL
DevCamp
Security
To limit access to some users you have many possibility:
• ACLWithUser:
• setReadAccess:forUser: or setWriteAccess:forUser:
• setPublicReadAccess: or setPublicWriteAccess:
• setDefaultACL:withAccessForCurrentUser:
DevCamp
ACL methods
PFObject *groupMessage = [PFObject objectWithClassName:@"Message"];
PFACL *groupACL = [PFACL ACL];
     
// userList is an NSArray with the users we are sending this
message to.
for (PFUser *user in userList) {
    [groupACL setReadAccess:YES forUser:user];
    [groupACL setWriteAccess:YES forUser:user];
}
groupMessage.ACL = [PFACL ACLWithUser:[PFUser currentUser]]; 
[groupACL setPublicReadAccess:YES];
groupMessage.ACL = groupACL;
[groupMessage saveInBackground];
DevCamp
Default ACL
To help ensure that your users' data is secure by default, you
can set a default ACL:
// data is visible to the world (readonly)
PFACL *defaultACL = [PFACL ACL];
[defaultACL setPublicReadAccess:YES];
[PFACL setDefaultACL:defaultACL withAccessForCurrentUser:YES];
// data is only accessible by the user itself
[PFACL setDefaultACL:[PFACL ACL] withAccessForCurrentUser:YES];
DevCamp
PFRole
DevCamp
Grouping users
Roles provide a logical way of grouping users with common access privileges
to your Parse data:
• Administrator
• User
• Guest
• ...
DevCamp
Create Role
// By specifying no write privileges for the ACL, we can ensure the role
cannot be altered.
PFACL *roleACL = [PFACL ACL];
[roleACL setPublicReadAccess:YES];
PFRole *role = [PFRole roleWithName:@"Administrator" acl:roleACL];
[role saveInBackground];
PFRole *role = [PFRole roleWithName:roleName acl:roleACL];
for (PFUser *user in usersToAddToRole) {
  [role.users addObject:user];
}
[role saveInBackground];
DevCamp
Security for Objects
PFRole *moderators = /* Query for some PFRole */;
PFObject *wallPost = [PFObject objectWithClassName:@"WallPost"];
PFACL *postACL = [PFACL ACL];
[postACL setWriteAccess:YES forRole:moderators];
wallPost.ACL = postACL;
[wallPost saveInBackground];
DevCamp
Security for Objects
PFRole *moderators = /* Query for some PFRole */;
PFObject *wallPost = [PFObject objectWithClassName:@"WallPost"];
PFACL *postACL = [PFACL ACL];
[postACL setWriteAccess:YES forRole:moderators];
wallPost.ACL = postACL;
[wallPost saveInBackground];
[postACL setWriteAccess:YES forRoleWithName:@"Moderators"];
DevCamp
Hierarchy
PFRole *administrators = /* Your "Administrators" role */;
PFRole *moderators = /* Your "Moderators" role */;
[moderators.roles addObject:administrators];
[moderators saveInBackground];
Any user with Administrator privileges should also be granted the
permissions of any Moderator:
DevCamp
Best practise
[PFUser enableAutomaticUser];
PFACL *defaultACL = [PFACL ACL];
// Optionally enable public read access while disabling public
write access.
// [defaultACL setPublicReadAccess:YES];
[PFACL setDefaultACL:defaultACL withAccessForCurrentUser:YES];
• restrict access to data as much as possible
• specify a default ACL based upon the current user
DevCamp
Demo
DevCamp
PFPush
DevCamp
Push notitification
- (void)application:(UIApplication *)application
        didRegisterForRemoteNotificationsWithDeviceToken:(NSData
*)deviceToken
{
    // Store the deviceToken in the current Installation and save it to
Parse.
    PFInstallation *currentInstallation = [PFInstallation
currentInstallation];
    [currentInstallation setDeviceTokenFromData:deviceToken];
    [currentInstallation saveInBackground];
}
Every Parse application installed on a device registered for push
notifications has an associated Installation object.The Installation object is
where you store all the data needed to target push notifications.
DevCamp
Installation
While it is possible to modify a PFInstallation just like you would a PFObject, there are several special
fields that help manage and target devices.
• badge:The current value of the icon badge for iOS apps. Changing this value on the PFInstallation
will update the badge value on the app icon. Changes should be saved to the server so that they
will be used for future badge-increment push notifications.
• channels:An array of the channels to which a device is currently subscribed.
• timeZone:The current time zone where the target device is located.This value is synchronized
every time anInstallation object is saved from the device (readonly).
• deviceType:The type of device, "ios", "android", "winrt", "winphone", or "dotnet"(readonly).
• installationId: Unique Id for the device used by Parse (readonly).
• deviceToken:The Apple generated token used for iOS devices (readonly).
• channelUris:The Microsoft-generated push URIs for Windows devices (readonly).
• appName:The display name of the client application to which this installation belongs (readonly).
• appVersion:The version string of the client application to which this installation belongs
(readonly).
• parseVersion:The version of the Parse SDK which this installation uses (readonly).
• appIdentifier:A unique identifier for this installation's client application. In iOS, this is the Bundle
Identifier(readonly).
DevCamp
Channels
// When users indicate they are pragmamark fans, we subscribe them
to that channel.
PFInstallation *currentInstallation = [PFInstallation
currentInstallation];
// When users indicate they are no longer Giants fans, we
unsubscribe them.
// [currentInstallation removeObject:@”pragmamark”
forKey:@”channels”];
[currentInstallation addUniqueObject:@"pragmamark"
forKey:@"channels"];
[currentInstallation saveInBackground];
This allows you to use a publisher-subscriber model for sending pushes.
Devices start by subscribing to one or more channels, and notifications can
later be sent to these subscribers.
DevCamp
Sending Pushes to channel
// Send a notification to all devices subscribed to the "Giants"
channel.
PFPush *push = [[PFPush alloc] init];
[push setChannel:@"pragmamark"];
// [push setChannels:@[@”pragmamark”, @”devcamp”]];
[push setMessage:@"PragmaDevCamp is coming!!"];
[push sendPushInBackground];
DevCamp
Sending Pushes to queries
// Create our Installation query
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:@"local" equalTo:@"IT"];
 
// Send push notification to query
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery]; // Set our Installation query
[push setMessage:@"Ancora pochi giorni per registrarsi al
DevCamp"];
[push sendPushInBackground];
DevCamp
Customizing
• alert: the notification's message.
• badge: (iOS only) the value indicated in the top right corner of the app icon.This can be
set to a value or toIncrement in order to increment the current value by 1.
• sound: (iOS only) the name of a sound file in the application bundle.
• content-available: (iOS only) if you are using Newsstand, set this value to 1 to trigger a
background download.
• action: (Android only) the Intent should be fired when the push is received. If not title
or alert values are specified, the Intent will be fired but no notification will appear to
the user.
• title: (Android & Windows 8 only) the value displayed in the Android system tray or
Windows toast notification.
DevCamp
Customizing example
// Create date object for tomorrow
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setYear:2013];
[comps setMonth:5];
[comps setDay:30];
NSCalendar *gregorian =
  [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:comps];
 
// Send push notification with expiration date
PFPush *push = [[PFPush alloc] init];
[push expireAtDate:date];
// [push expireAfterTimeInterval: 60 * 60 * 24 * 7] - 1 week
[push setQuery:everyoneQuery];
[push setMessage:@"Season tickets on sale until May 30th"];
[push sendPushInBackground];
DevCamp
Receiving pushes
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  . . .
  // Extract the notification data
  NSDictionary *notificationPayload =
launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
 
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
  // Create empty photo object
  NSString *photoId = [userInfo objectForKey:@"p"];
}
DevCamp
Clearing the badge
- (void)applicationDidBecomeActive:(UIApplication *)application {
  PFInstallation *currentInstallation = [PFInstallation
currentInstallation];
  if (currentInstallation.badge != 0) {
    currentInstallation.badge = 0;
    [currentInstallation saveEventually];
  }
  // ...
}
DevCamp
Demo
DevCamp
• Parse.com
• NSScreencast.com
• http://www.raywenderlich.com/19341/how-to-
easily-create-a-web-backend-for-your-apps-with-
parse
Link
DevCamp
Domande?
facebook.com/pragmamark
facebook.com/groups/pragmamark
@pragmamarkorg
http://pragmamark.org
DevCamp
NSLog(@”Thank you!”);
stefano.zanetti@pragmamark.org

Weitere ähnliche Inhalte

Was ist angesagt?

Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackIgnacio Martín
 
Composable and streamable Play apps
Composable and streamable Play appsComposable and streamable Play apps
Composable and streamable Play appsYevgeniy Brikman
 
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Jesus Manuel Olivas
 
You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)andrewnacin
 
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...Sencha
 
Building Content Types with Dexterity
Building Content Types with DexterityBuilding Content Types with Dexterity
Building Content Types with DexterityDavid Glick
 
Aligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsAligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsMatthew Beale
 
Even faster django
Even faster djangoEven faster django
Even faster djangoGage Tseng
 
深入淺出 MVC
深入淺出 MVC深入淺出 MVC
深入淺出 MVCJace Ju
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to TornadoGavin Roy
 
Extending eZ Platform 2.x with Symfony and React
Extending eZ Platform 2.x with Symfony and ReactExtending eZ Platform 2.x with Symfony and React
Extending eZ Platform 2.x with Symfony and ReactPiotr Nalepa
 
Always up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPIAlways up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPIGOG.com dev team
 
You Don't Know Query - WordCamp Portland 2011
You Don't Know Query - WordCamp Portland 2011You Don't Know Query - WordCamp Portland 2011
You Don't Know Query - WordCamp Portland 2011andrewnacin
 
Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Kris Wallsmith
 
Building a Dynamic Website Using Django
Building a Dynamic Website Using DjangoBuilding a Dynamic Website Using Django
Building a Dynamic Website Using DjangoNathan Eror
 
Becoming A Drupal Master Builder
Becoming A Drupal Master BuilderBecoming A Drupal Master Builder
Becoming A Drupal Master BuilderPhilip Norton
 

Was ist angesagt? (20)

Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and Webpack
 
Composable and streamable Play apps
Composable and streamable Play appsComposable and streamable Play apps
Composable and streamable Play apps
 
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...
 
You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)
 
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
 
Django Heresies
Django HeresiesDjango Heresies
Django Heresies
 
Building Content Types with Dexterity
Building Content Types with DexterityBuilding Content Types with Dexterity
Building Content Types with Dexterity
 
Aligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsAligning Ember.js with Web Standards
Aligning Ember.js with Web Standards
 
Even faster django
Even faster djangoEven faster django
Even faster django
 
CodeIgniter 3.0
CodeIgniter 3.0CodeIgniter 3.0
CodeIgniter 3.0
 
WebGUI Developers Workshop
WebGUI Developers WorkshopWebGUI Developers Workshop
WebGUI Developers Workshop
 
深入淺出 MVC
深入淺出 MVC深入淺出 MVC
深入淺出 MVC
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
 
Extending eZ Platform 2.x with Symfony and React
Extending eZ Platform 2.x with Symfony and ReactExtending eZ Platform 2.x with Symfony and React
Extending eZ Platform 2.x with Symfony and React
 
Always up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPIAlways up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPI
 
You Don't Know Query - WordCamp Portland 2011
You Don't Know Query - WordCamp Portland 2011You Don't Know Query - WordCamp Portland 2011
You Don't Know Query - WordCamp Portland 2011
 
Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)
 
The JavaFX Ecosystem
The JavaFX EcosystemThe JavaFX Ecosystem
The JavaFX Ecosystem
 
Building a Dynamic Website Using Django
Building a Dynamic Website Using DjangoBuilding a Dynamic Website Using Django
Building a Dynamic Website Using Django
 
Becoming A Drupal Master Builder
Becoming A Drupal Master BuilderBecoming A Drupal Master Builder
Becoming A Drupal Master Builder
 

Andere mochten auch

Biblioteca La PeñA Arborizadora Alta
Biblioteca La PeñA Arborizadora AltaBiblioteca La PeñA Arborizadora Alta
Biblioteca La PeñA Arborizadora AltaCésar Bernal
 
3 1-0-le monde economique-perspectives 2016 p16-22
3 1-0-le monde economique-perspectives 2016 p16-223 1-0-le monde economique-perspectives 2016 p16-22
3 1-0-le monde economique-perspectives 2016 p16-22Muriel Favarger Ripert
 
Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...
Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...
Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...fernandodelosriosb
 
Pc+world+digital+ +dic+2012
Pc+world+digital+ +dic+2012Pc+world+digital+ +dic+2012
Pc+world+digital+ +dic+2012Koffe Revolution
 
Cuentos De Calleja En La BNE
Cuentos De Calleja En La BNE
Cuentos De Calleja En La BNE
Cuentos De Calleja En La BNE badzeal7581
 
Social Branding Event Folien
Social Branding Event FolienSocial Branding Event Folien
Social Branding Event FolienMarketingNatives
 
Planeación 16 20-enero-2012
Planeación  16 20-enero-2012Planeación  16 20-enero-2012
Planeación 16 20-enero-2012Beto Moreno
 
Utm trabajo investigacion emprendimiento empresarial
Utm trabajo investigacion emprendimiento empresarialUtm trabajo investigacion emprendimiento empresarial
Utm trabajo investigacion emprendimiento empresarialarasanb2012
 
Sobrecarga de la Información
Sobrecarga de la InformaciónSobrecarga de la Información
Sobrecarga de la InformaciónAlexis Cano
 
Uve De Gowin 3º Medio
Uve De Gowin 3º MedioUve De Gowin 3º Medio
Uve De Gowin 3º Medioabustamante
 
Instrucciones de recarga_hp
Instrucciones de recarga_hpInstrucciones de recarga_hp
Instrucciones de recarga_hpJorge Flores
 
2 Aplicaciones prácticas de software libre
2 Aplicaciones prácticas de software libre2 Aplicaciones prácticas de software libre
2 Aplicaciones prácticas de software libreOpen Xarxes coop. v.
 
Manual double-sided - safety
Manual   double-sided - safetyManual   double-sided - safety
Manual double-sided - safetyKevin Davison
 
Präsentation 15 11_2010
Präsentation 15 11_2010Präsentation 15 11_2010
Präsentation 15 11_2010Annette Mueller
 
UN HUESITO MUY FILOSO y PELIGROSO
UN HUESITO MUY FILOSO y PELIGROSOUN HUESITO MUY FILOSO y PELIGROSO
UN HUESITO MUY FILOSO y PELIGROSOMariaam Salazar
 
ITMP Design Thinking Summit Graz 2016
ITMP Design Thinking Summit Graz 2016ITMP Design Thinking Summit Graz 2016
ITMP Design Thinking Summit Graz 2016ITMP
 
What's New in the PeopleSoft 9.2 Accounts Payable Module?
What's New in the PeopleSoft 9.2 Accounts Payable Module?What's New in the PeopleSoft 9.2 Accounts Payable Module?
What's New in the PeopleSoft 9.2 Accounts Payable Module?NERUG
 

Andere mochten auch (20)

Biblioteca La PeñA Arborizadora Alta
Biblioteca La PeñA Arborizadora AltaBiblioteca La PeñA Arborizadora Alta
Biblioteca La PeñA Arborizadora Alta
 
3 1-0-le monde economique-perspectives 2016 p16-22
3 1-0-le monde economique-perspectives 2016 p16-223 1-0-le monde economique-perspectives 2016 p16-22
3 1-0-le monde economique-perspectives 2016 p16-22
 
Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...
Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...
Proyecto "Mujeres a través de la historia" (Proyecto Currículo Integrado de l...
 
Pc+world+digital+ +dic+2012
Pc+world+digital+ +dic+2012Pc+world+digital+ +dic+2012
Pc+world+digital+ +dic+2012
 
Cuentos De Calleja En La BNE
Cuentos De Calleja En La BNE
Cuentos De Calleja En La BNE
Cuentos De Calleja En La BNE
 
Social Branding Event Folien
Social Branding Event FolienSocial Branding Event Folien
Social Branding Event Folien
 
Dot netspain 2016
Dot netspain 2016Dot netspain 2016
Dot netspain 2016
 
Planeación 16 20-enero-2012
Planeación  16 20-enero-2012Planeación  16 20-enero-2012
Planeación 16 20-enero-2012
 
Utm trabajo investigacion emprendimiento empresarial
Utm trabajo investigacion emprendimiento empresarialUtm trabajo investigacion emprendimiento empresarial
Utm trabajo investigacion emprendimiento empresarial
 
Sobrecarga de la Información
Sobrecarga de la InformaciónSobrecarga de la Información
Sobrecarga de la Información
 
Uve De Gowin 3º Medio
Uve De Gowin 3º MedioUve De Gowin 3º Medio
Uve De Gowin 3º Medio
 
Instrucciones de recarga_hp
Instrucciones de recarga_hpInstrucciones de recarga_hp
Instrucciones de recarga_hp
 
2 Aplicaciones prácticas de software libre
2 Aplicaciones prácticas de software libre2 Aplicaciones prácticas de software libre
2 Aplicaciones prácticas de software libre
 
Revision ch 3
Revision ch 3Revision ch 3
Revision ch 3
 
Manual double-sided - safety
Manual   double-sided - safetyManual   double-sided - safety
Manual double-sided - safety
 
Espirometria
EspirometriaEspirometria
Espirometria
 
Präsentation 15 11_2010
Präsentation 15 11_2010Präsentation 15 11_2010
Präsentation 15 11_2010
 
UN HUESITO MUY FILOSO y PELIGROSO
UN HUESITO MUY FILOSO y PELIGROSOUN HUESITO MUY FILOSO y PELIGROSO
UN HUESITO MUY FILOSO y PELIGROSO
 
ITMP Design Thinking Summit Graz 2016
ITMP Design Thinking Summit Graz 2016ITMP Design Thinking Summit Graz 2016
ITMP Design Thinking Summit Graz 2016
 
What's New in the PeopleSoft 9.2 Accounts Payable Module?
What's New in the PeopleSoft 9.2 Accounts Payable Module?What's New in the PeopleSoft 9.2 Accounts Payable Module?
What's New in the PeopleSoft 9.2 Accounts Payable Module?
 

Ähnlich wie iOS App with Parse.com as RESTful Backend

FI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsFI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsPetr Dvorak
 
MFF UK - Introduction to iOS
MFF UK - Introduction to iOSMFF UK - Introduction to iOS
MFF UK - Introduction to iOSPetr Dvorak
 
Using RequireJS with CakePHP
Using RequireJS with CakePHPUsing RequireJS with CakePHP
Using RequireJS with CakePHPStephen Young
 
Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Satoshi Asano
 
Parse London Meetup - Cloud Code Tips & Tricks
Parse London Meetup - Cloud Code Tips & TricksParse London Meetup - Cloud Code Tips & Tricks
Parse London Meetup - Cloud Code Tips & TricksHector Ramos
 
Developing iOS REST Applications
Developing iOS REST ApplicationsDeveloping iOS REST Applications
Developing iOS REST Applicationslmrei
 
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...SPTechCon
 
Node.js Patterns for Discerning Developers
Node.js Patterns for Discerning DevelopersNode.js Patterns for Discerning Developers
Node.js Patterns for Discerning Developerscacois
 
Parsing in ios to create an app
Parsing in ios to create an appParsing in ios to create an app
Parsing in ios to create an appHeaderLabs .
 
solving little problems
solving little problemssolving little problems
solving little problemsAustin Ziegler
 
第一次用Parse就深入淺出
第一次用Parse就深入淺出第一次用Parse就深入淺出
第一次用Parse就深入淺出Ymow Wu
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexyananelson
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress DevelopmentAdam Tomat
 
Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCAWhymca
 
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...smn-automate
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Matthew Groves
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLAll Things Open
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)Beau Lebens
 

Ähnlich wie iOS App with Parse.com as RESTful Backend (20)

FI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsFI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS Basics
 
MFF UK - Introduction to iOS
MFF UK - Introduction to iOSMFF UK - Introduction to iOS
MFF UK - Introduction to iOS
 
What's Parse
What's ParseWhat's Parse
What's Parse
 
Using RequireJS with CakePHP
Using RequireJS with CakePHPUsing RequireJS with CakePHP
Using RequireJS with CakePHP
 
Webエンジニアから見たiOS5
Webエンジニアから見たiOS5Webエンジニアから見たiOS5
Webエンジニアから見たiOS5
 
Parse London Meetup - Cloud Code Tips & Tricks
Parse London Meetup - Cloud Code Tips & TricksParse London Meetup - Cloud Code Tips & Tricks
Parse London Meetup - Cloud Code Tips & Tricks
 
Developing iOS REST Applications
Developing iOS REST ApplicationsDeveloping iOS REST Applications
Developing iOS REST Applications
 
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
 
Node.js Patterns for Discerning Developers
Node.js Patterns for Discerning DevelopersNode.js Patterns for Discerning Developers
Node.js Patterns for Discerning Developers
 
Parsing in ios to create an app
Parsing in ios to create an appParsing in ios to create an app
Parsing in ios to create an app
 
Real World MVC
Real World MVCReal World MVC
Real World MVC
 
solving little problems
solving little problemssolving little problems
solving little problems
 
第一次用Parse就深入淺出
第一次用Parse就深入淺出第一次用Parse就深入淺出
第一次用Parse就深入淺出
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexy
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCA
 
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 
Full Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQLFull Stack Development with Node.js and NoSQL
Full Stack Development with Node.js and NoSQL
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)
 

Kürzlich hochgeladen

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 

Kürzlich hochgeladen (20)

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 

iOS App with Parse.com as RESTful Backend

  • 1. Stefano Zanetti § DevCamp Parse.com iOS App with Parse.com as RESTful Backend
  • 2. DevCamp Stefano Zanetti  Apple iOS Developer Superpartes Innovation Campus & H-Farm  Co-founder di # Pragma Mark ― www.pragmamark.org  [tt] @Doh__ [in] Stefano Zanetti [fb] stefano.znt [email] zanetti.stefano@gmail.com
  • 3. DevCamp What is Parse.com? The perfect cloud for your apps. Parse allows your team to focus on creating a great user experience and forget server maintenance and complex infrastructure.
  • 4. DevCamp What does this mean? • Backend for apps and websites • Database NoSQL (schemaless: if you need to store something, store key/value data without prepare any table) • Store your app’s data in the cloud • Parse automatically creates RESTful API for you • Push notification • Social • Hosting • Cloud code
  • 6. DevCamp How much? BasicBasicBasic ProProPro EnterpriseEnterpriseEnterprise Great for developer to get startedGreat for developer to get startedGreat for developer to get started For Production applicationsFor Production applicationsFor Production applications For advanced featuresFor advanced featuresFor advanced features FREEFREEFREE $199/month$199/month$199/month contact Parsecontact Parsecontact Parse Request Pushes Burst limit Request Pushes Burst limit Request Pushes Burst limit 1 milion/ month 1 milion/ month 20/second 15 milion/ month 5 milion/ month 40/second contact Parse
  • 23. DevCamp SDK • Quick start: • https://www.parse.com/docs • Download from official site: • https://www.parse.com/docs/downloads/ • CocoaPods: • pod 'Parse', '~> 1.2.9'
  • 25. DevCamp Quick start [Parse setApplicationId:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" clientKey:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]; 1.Download the Sample Project 2.Xcode 4.6+ and iOS targetting 4.3+ 3.Open project and uncomment the first line of application:didFinishLaunchingWithOptions: in the application delegate file: 4.Compile and run
  • 26. DevCamp Create & Save an Object PFObject *testObject = [PFObject objectWithClassName:@"TestObject"]; [testObject setObject:@"bar" forKey:@"foo"]; [testObject save]; 5.Copy and paste next code somewhere in the project 6.Compile and run
  • 28. DevCamp Which libraries Parse needs? • AudioToolbox.framework • CFNetwork.framework • CoreGraphics.framework • CoreLocation.framework • libz.1.1.3.dylib • MobileCoreServices.framework • QuartzCore.framework • Security.framework • StoreKit.framework • SystemConfiguration.framework • AdSupport.framework (optional if iOS targetting is than then 6.0) • Social.framework (optional if iOS targetting is less than 6.0) • Accounts.framework (optional if iOS targetting is less than 6.0) If you're targeting iOS versions less than 5.0, you'll need to add the "-fobjc- arc" flag to the "Other Linker Flags" entry in your target build settings.
  • 30. DevCamp Saving/Updating Objects PFObject *post = [PFObject objectWithClassName:@"Post"]; [post setObject:@"New post" forKey:@"title"]; [post setObject:@"This is my first message" forKey:@"message"]; [post setObject:[NSNumber numberWithBool:NO] forKey:@"visible"]; [post save]; • PFObject contains key-value pairs of JSON- compatible data. • This data is schemaless • Interface is similar to NSMutableDictionary
  • 31. DevCamp Check Data Browser • You don't have to configure or set up a new Class • You don't need to specify a key for the object you are saving Parse automatically fills 3 field: • objectId • createdAt • updatedAt objectId: "xWMyZ4YEGZ", title: "New post", message: "This is my first message", visible: false, createdAt:"2011-06-10T18:33:42Z", updatedAt:"2011-06-10T18:33:42Z"
  • 32. DevCamp Retriving Data Using PFQuery you can retrive a PFObject PFQuery *query = [PFQuery queryWithClassName:@"Post"]; PFObject *post = [query getObjectWithId:@"xWMyZ4YEGZ"]; NSString *postTitle = [post objectForKey:@"title"]; BOOL visible = [[post objectForKey:@"visible"] boolValue];
  • 33. DevCamp Note!! The three special values are provided as properties: NSString *objectId = post.objectId; NSDate *updatedAt = post.updatedAt; NSDate *createdAt = post.createdAt; If you need to refresh an object you already have with the latest data that is in the Parse Cloud, you can call the refresh method like so: [myObject refresh];
  • 34. DevCamp Saving in background Just call saveInBackground method [post saveInBackground];
  • 35. DevCamp Blocks If you want to run code when operation is completed you can use blocks (iOS 4.0+) or callbacks methods. [post saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {   if (!error) {     // The Post saved successfully.   } else {     // There was an error saving the Post.   } }];
  • 36. DevCamp Callbacks // First set up a callback. - (void)saveCallback:(NSNumber *)result error:(NSError *)error {   if (!error) {     // The Post saved successfully.   } else {     // There was an error saving the Post.   } }   // Then, elsewhere in your code... [post saveInBackgroundWithTarget:self selector:@selector(saveCallback:error:)];
  • 37. DevCamp Load in background PFQuery *query = [PFQuery queryWithClassName:@"Post"]; [query getObjectInBackgroundWithId:@"xWMyZ4YEGZ"                              block:^(PFObject *post, NSError *error) {   if (!error) {     // The get request succeeded. Log the score     NSLog(@"The title is: %d", [[post objectForKey:@"title"] intValue]);   } else {     // Log details of our failure     NSLog(@"Error: %@ %@", error, [error userInfo]);   } }]; With Blocks
  • 38. DevCamp Load in background // First set up a callback. - (void)getCallback:(PFObject *)post error:(NSError *)error {   if (!error) {     // The get request succeeded. Log the score     NSLog(@"The title is: %d", [[post objectForKey:@"title"] intValue]);   } else {     // Log details of our failure     NSLog(@"Error: %@ %@", error, [error userInfo]);   } }   // Then, elsewhere in your code... PFQuery *query = [PFQuery queryWithClassName:@"Post"]; [query getObjectInBackgroundWithId:@"xWMyZ4YEGZ"                             target:self                           selector:@selector(getCallback:error:)]; With CallBacks
  • 39. DevCamp Saving Objects Offline Just call saveEventually method and system store the update on the device until a network connection is available [post saveEventually];
  • 40. DevCamp Saving Counter Objects The “likes” field is a counter: [post incrementKey:@"likes"]; [post saveInBackground]; or [post incrementKey:@"likes" byAmount:3]; [post saveInBackground];
  • 41. DevCamp Saving Array Objects • addObject:forKey: and addObjectsFromArray:forKey: append the given objects to the end of an array field. • addUniqueObject:forKey: and addUniqueObjectsFromArray:forKey: add only the given objects which aren't already contained in an array field to that field.The position of the insert is not guaranteed. • removeObject:forKey: and removeObjectsInArray:forKey: remove all instances of each given object from an array field. [post addUniqueObjectsFromArray:[NSArray arrayWithObjects:@"stefano", @"massimo", nil] forKey:@"users"]; [post saveInBackground];
  • 42. DevCamp Delete Objects To delete an object from the cloud: [myObject deleteInBackground]; To delete e single field from an Object: // After this, the visilble field will be empty [myObject removeObjectForKey:@"visible"];   // Saves the field deletion to the Parse Cloud [myObject saveInBackground];
  • 45. DevCamp One-To-Many Relationship // Create the post PFObject *myPost = [PFObject objectWithClassName:@"Post"]; [myPost setObject:@"I'm Hungry" forKey:@"title"]; [myPost setObject:@"Where should we go for lunch?" forKey:@"content"];   // Create the comment PFObject *myComment = [PFObject objectWithClassName:@"Comment"]; [myComment setObject:@"Let's do Sushirrito." forKey:@"content"];   // Add a relation between the Post and Comment [myComment setObject:myPost forKey:@"parent"];   // This will save both myPost and myComment [myComment saveInBackground]; You can link objects:
  • 46. DevCamp One-To-Many Relationship You can also link objects using just their objectIds like so: // Add a relation between the Post with objectId "1zEcyElZ80" and the comment [myComment setObject:[PFObject objectWithoutDataWithClassName:@"Post" objectId:@"1zEcyElZ80"]               forKey:@"parent"];
  • 47. DevCamp One-To-Many Relationship By default, when fetching an object, related PFObjects are not fetched: PFObject *post = [fetchedComment objectForKey:@"parent"]; [post fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {   NSString *title = [post objectForKey:@"title"]; }];
  • 48. DevCamp Many-To-Many Relationship A User may have many Posts that they might like. PFUser *user = [PFUser currentUser]; PFRelation *relation = [user relationforKey:@"likes"]; [relation addObject:post]; [user saveInBackground]; Add relation: [relation removeObject:post]; Remove relation:
  • 49. DevCamp Many-To-Many Relationship By default, the list of objects in this relation are not downloaded [[relation query] findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {   if (error) {      // There was an error   } else {     // objects has all the Posts the current user liked.   } }];
  • 50. DevCamp Many-To-Many Relationship If you want only a subset of the Posts you can add extra constraints to the PFQuery returned by query PFQuery *query = [relation query]; // Add other query constraints.
  • 52. DevCamp What types are supported? NSNumber *number = [NSNumber numberWithInt:42]; NSString *string = [NSString stringWithFormat:@"the number is %i", number]; NSDate *date = [NSDate date]; NSData *data = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; NSArray *array = [NSArray arrayWithObjects:string, number, nil]; NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:number, @"number",                                                                       string, @"string",                                                                       nil]; NSNull *null = [NSNull null];   PFObject *bigObject = [PFObject objectWithClassName:@"BigObject"]; [bigObject setObject:number    forKey:@"myNumber"]; [bigObject setObject:string    forKey:@"myString"]; [bigObject setObject:date      forKey:@"myDate"]; [bigObject setObject:data      forKey:@"myData"]; [bigObject setObject:array     forKey:@"myArray"]; [bigObject setObject:dictionary forKey:@"myDictionary"]; [bigObject setObject:null      forKey:@"myNull"]; [bigObject saveInBackground]; Are supported: NSString, NSNumber, NSDate, NSData, and NSNull.You can nest NSDictionary and NSArray objects to store more structured data within a single PFObject.
  • 54. DevCamp Basic Queries PFQuery *query = [PFQuery queryWithClassName:@"Post"]; [query whereKey:@"title" equalTo:@"pragmamark"]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {   if (!error) {     // The find succeeded.     NSLog(@"Successfully retrieved %d scores.", objects.count);   } else {     // Log details of the failure     NSLog(@"Error: %@ %@", error, [error userInfo]);   } }]; The general pattern is to create a PFQuery, put conditions on it, and then retrieve a NSArray of matching PFObjects using either findObjectsInBackgroundWithBlock: or findObjectsInBackgroundWithTarget:selector:
  • 55. DevCamp Basic Queries // Only use this code if you are already running it in a background // thread, or for testing purposes! PFQuery *query = [PFQuery queryWithClassName:@"Post"]; [query whereKey:@"title" equalTo:@"pragmamark"]; NSArray* scoreArray = [query findObjects]; If you are already in a background thread:
  • 56. DevCamp NSPredicate NSPredicate *predicate = [NSPredicate predicateWithFormat:                           @"title = 'pragmamark'"]; PFQuery *query = [PFQuery queryWithClassName:@"Post" predicate:predicate]; These features are supported: • Simple comparisons such as =, !=, <, >, <=, >=, and BETWEEN with a key and a constant. • Containment predicates, such as x IN {1, 2, 3}. • Key-existence predicates, such as x IN SELF. • BEGINSWITH expressions. • Compound predicates with AND, OR, and NOT. • Sub-queries with "key IN %@", subquery. The following types of predicates are not supported: • Aggregate operations, such as ANY, SOME,ALL, or NONE. • Regular expressions, such as LIKE, MATCHES, CONTAINS, or ENDSWITH. • Predicates comparing one key to another. • Complex predicates with many ORed clauses.
  • 57. DevCamp Query Constraints [query whereKey:@"playerName" notEqualTo:@"Michael Yabuti"]; [query whereKey:@"playerAge" greaterThan:[NSNumber numberWithInt:18]]; query.limit = 10; // limit to at most 10 results query.skip = 10; // skip the first 10 results // Sorts the results in ascending order by the score field [query orderByAscending:@"score"];   // Sorts the results in descending order by the score field [query orderByDescending:@"score"]; // Restricts to wins < 50 [query whereKey:@"wins" lessThan:[NSNumber numberWithInt:50]];   // Restricts to wins <= 50 [query whereKey:@"wins" lessThanOrEqualTo:[NSNumber numberWithInt:50]];   // Restricts to wins > 50 [query whereKey:@"wins" greaterThan:[NSNumber numberWithInt:50]];   // Restricts to wins >= 50 [query whereKey:@"wins" greaterThanOrEqualTo:[NSNumber numberWithInt:50]];
  • 58. DevCamp Constraints on Array // Finds scores from anyone who is neither Jonathan, Dario, nor Shawn NSArray *names = [NSArray arrayWithObjects:@"Jonathan Walsh",                                            @"Dario Wunsch",                                            @"Shawn Simon",                                            nil]; [query whereKey:@"playerName" notContainedIn:names]; or [query whereKey:@"playerName" containedIn:names]; If you want to retrieve objects matching several different values
  • 59. DevCamp Constraints on Array // Find objects where the array in arrayKey contains 2. [query whereKey:@"arrayKey" equalTo:[NSNumber numberWithInt:2]]; For keys with an array type, you can find objects where the key's array value contains 2 by: // Find objects where the array in arrayKey contains each of the // elements 2, 3, and 4. [query whereKey:@"arrayKey" containsAllObjectsInArray:@[@2, @3, @4]]; You can also find objects where the key's array value contains each of the values 2, 3, and 4 with the following:
  • 60. DevCamp Check particular key // Finds objects that have the score set [query whereKeyExists:@"score"];   // Finds objects that don't have the score set [query whereKeyDoesNotExist:@"score"]; If you want to retrieve objects that have a particular key set or not:
  • 61. DevCamp Matches Key PFQuery *teamQuery = [PFQuery queryWithClassName:@"Team"]; [teamQuery whereKey:@"winPct" greaterThan:[NSNumber withDouble: 0.5]]; PFQuery *userQuery = [PFQuery queryForUser]; [userQuery whereKey:@"hometown" matchesKey:@"city" inQuery:teamQuery]; [userQuery findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {     // results will contain users with a hometown team with a winning record }]; You can use the whereKey:matchesKey:inQuery: method to get objects where a key matches the value of a key in a set of objects resulting from another query. (use whereKey:doesNotMatchKey:inQuery: to get objects where a key does not match)
  • 62. DevCamp Restrict the returned fields PFQuery *query = [PFQuery queryWithClassName:@"GameScore"]; [query selectKeys:@[@"playerName", @"score"]]; NSArray *results = [query findObjects]; The remaining fields can be fetched later by calling one of the fetchIfNeeded variants on the returned objects: PFObject *object = (PFObject*)[results objectAtIndex:0]; [object fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {   // all fields of the object will now be available here. }];
  • 63. DevCamp Queries on string value // Finds barbecue sauces that start with "Big Daddy's". PFQuery *query = [PFQuery queryWithClassName:@"BarbecueSauce"]; [query whereKey:@"name" hasPrefix:@"Big Daddy's"];
  • 64. DevCamp Relational queries // Assume PFObject *myPost was previously created. PFQuery *query = [PFQuery queryWithClassName:@"Comment"]; [query whereKey:@"post" equalTo:myPost];   [query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) {     // comments now contains the comments for myPost }]; If you want to retrieve objects where a field matches a particular PFObject, you can use whereKey:equalTo: just like for other data types. [query whereKey:@"post"         equalTo:[PFObject objectWithoutDataWithClassName:@"Post" objectId:@"1zEcyElZ80"]];
  • 65. DevCamp Matches Query PFQuery *innerQuery = [PFQuery queryWithClassName:@"Post"]; [innerQuery whereKeyExists:@"image"]; PFQuery *query = [PFQuery queryWithClassName:@"Comment"]; [query whereKey:@"post" matchesQuery:innerQuery]; [query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) {     // comments now contains the comments for posts with images }]; If you want to retrieve objects where a field contains (or not) a PFObject that match a different query, you can use whereKey:matchesQuery: (or whereKey:notMatchQuery:) Note that the default limit of 100 and maximum limit of 1000 apply to the inner query as well.
  • 66. DevCamp Include Key PFQuery *query = [PFQuery queryWithClassName:@"Comment"]; // Retrieve the most recent ones [query orderByDescending:@"createdAt"]; // Only retrieve the last ten query.limit = [NSNumber numberWithInt:10]; // Include the post data with each comment [query includeKey:@"post"];   [query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) {     // Comments now contains the last ten comments, and the "post" field     // has been populated. For example:     for (PFObject *comment in comments) {          // This does not require a network access.          PFObject *post = [comment objectForKey:@"post"];          NSLog(@"retrieved related post: %@", post);     } }]; If you want to return multiple types of related objects in one query use includeKey: method:
  • 67. DevCamp Include Key [query includeKey:@"post.author"]; You can also do multi level includes using dot notation:
  • 68. DevCamp Caching Policy query.cachePolicy = kPFCachePolicyNetworkElseCache; The default query behavior doesn't use the cache, but you can enable caching by setting query.cachePolicy. • kPFCachePolicyIgnoreCache: is the default cache policy. • kPFCachePolicyCacheOnly :The query only loads from the cache, ignoring the network. If there are no cached results, that causes a PFError. • kPFCachePolicyNetworkOnly:The query does not load from the cache, but it will save results to the cache. • kPFCachePolicyCacheElseNetwork:The query first tries to load from the cache, but if that fails, it loads results from the network. If neither cache nor network succeed, there is a PFError. • kPFCachePolicyNetworkElseCache:The query first tries to load from the network, but if that fails, it loads results from the cache. If neither network nor cache succeed, there is a PFError. • kPFCachePolicyCacheThenNetwork:The query first loads from the cache, then loads from the network. In this case, the callback will actually be called twice - first with the cached results, then with the network results. Since it returns two results at different times, this cache policy cannot be used synchronously with findObjects.
  • 69. DevCamp Control the cache’s behavior BOOL isInCache = [query hasCachedResult]; Check to see if there is a cached result for the query with: [query clearCachedResult]; Remove any cached results for a query with: [PFQuery clearAllCachedResults]; Remove cached results for queries with: query.maxCacheAge = 60 * 60 * 24;  // One day, in seconds. Control the maximum age of a cached result with:
  • 70. DevCamp Counting Objects PFQuery *query = [PFQuery queryWithClassName:@"GameScore"]; [query whereKey:@"playername" equalTo:@"Sean Plott"]; [query countObjectsInBackgroundWithBlock:^(int count, NSError *error) {   if (!error) {     // The count request succeeded. Log the count     NSLog(@"Sean has played %d games", count);   } else {     // The request failed   } }]; If you just need to count how many objects match a query, but you do not need to retrieve the objects that match, you can use countObjects instead of findObjects.
  • 71. DevCamp Compound Queries PFQuery *lotsOfWins = [PFQuery queryWithClassName:@"Player"]; [lotsOfWins whereKey:@"wins" greaterThan:[NSNumber numberWithInt: 150]];   PFQuery *fewWins = [PFQuery queryWithClassName:@"Player"]; [fewWins whereKey:@"wins" lessThan:[NSNumber numberWithInt:5]]; PFQuery *query = [PFQuery orQueryWithSubqueries:[NSArray arrayWithObjects:fewWins,lotsOfWins,nil]]; [query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {   // results contains players with lots of wins or only a few wins.   }]; If you want to find objects that match one of several queries, you can use orQueryWithSubqueries: method.
  • 73. DevCamp Subclassing PFObject 1.Declare a subclass which conforms to the PFSubclassing protocol. 2.Implement the class method parseClassName.This is the string you would pass to initWithClassName: and makes all future class name references unnecessary. 3.Import PFObject+Subclass in your .m file.This implements all methods in PFSubclassing beyond parseClassName. 4.Call [YourClass registerSubclass] in your ApplicationDelegate before Parse setApplicationId:clientKey:.
  • 74. DevCamp Example of Subclassing // Armor.h @interface Armor : PFObject<PFSubclassing> + (NSString *)parseClassName; @end   // Armor.m // Import this header to let Armor know that PFObject privately provides most // of the methods for PFSubclassing. #import <Parse/PFObject+Subclass.h>   @implementation Armor + (NSString *)parseClassName {   return @"Armor"; } @end   // AppDelegate.m #import <Parse/Parse.h> #import "Armor.h"   - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {   [Armor registerSubclass];   [Parse setApplicationId:parseAppId clientKey:parseClientKey]; }
  • 75. DevCamp Property & methods // Armor.h @interface Armor : PFObject<PFSubclassing> + (NSString *)parseClassName; @property (retain) NSString *displayName; @end   // Armor.m @dynamic displayName; @dynamic iconFile;   - (UIImageView *)iconView {   PFImageView *view = [[PFImageView alloc] initWithImage:kPlaceholderImage];   view.file = self.iconFile;   [view loadInBackground];   return [view autorelease]; }
  • 76. DevCamp Query PFQuery *query = [Armor query]; [query whereKey:@"rupees" lessThanOrEqualTo:PFUser.currentUser.rupees]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {   if (!error) {     Armor *firstArmor = [objects objectAtIndex:0];     // ...   } }];
  • 78. DevCamp Why PFFile? PFFile lets you store application files in the cloud that would otherwise be too large or cumbersome to fit into a regular PFObject. (up to 10 megabytes)
  • 79. DevCamp Saving a file on the cloud Then you can associate a PFFile onto a PFObject just like any other piece of data: NSData *data = [@"Working at Parse is great!" dataUsingEncoding:NSUTF8StringEncoding]; PFFile *file = [PFFile fileWithName:@"resume.txt" data:data]; [file saveInBackground]; PFObject *jobApplication = [PFObject objectWithClassName:@"JobApplication"] [jobApplication setObject:@"Joe Smith" forKey:@"applicantName"]; [jobApplication setObject:file        forKey:@"applicantResumeFile"]; [jobApplication saveInBackground];
  • 80. DevCamp Upload / Download NSData *data = [@"Working at Parse is great!" dataUsingEncoding:NSUTF8StringEncoding]; PFFile *file = [PFFile fileWithName:@"resume.txt" data:data]; [file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {   // Handle success or failure here ... } progressBlock:^(int percentDone) {   // Update your progress spinner here. percentDone will be between 0 and 100. }]; Use saveInBackgroundWithBlock:progressBlock: and getDataInBackgroundWithBlock:progressBlock:
  • 82. DevCamp SignUp / SignIn PFUser *user = [PFUser user];     user.username = @"my name";     user.password = @"my pass";     user.email = @"email@example.com";       // other fields can be set just like with PFObject     [user setObject:@"415-392-0202" forKey:@"phone"];       [user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {       if (!error) {           // Hooray! Let them use the app now.       } else {           NSString *errorString = [[error userInfo] objectForKey:@"error"];           // Show the errorString somewhere and let the user try again.       }     }]; [PFUser logInWithUsernameInBackground:@"myname" password:@"mypass"   block:^(PFUser *user, NSError *error) {     if (user) {         // Do stuff after successful login.     } else {         // The login failed. Check error to see why.     } }]
  • 83. DevCamp Current User PFUser *currentUser = [PFUser currentUser]; To get the current logged user you use the cached currentUser object: [PFUser logOut]; You can clear the current user by logging them out:
  • 85. DevCamp Security To limit access to some users you have many possibility: • ACLWithUser: • setReadAccess:forUser: or setWriteAccess:forUser: • setPublicReadAccess: or setPublicWriteAccess: • setDefaultACL:withAccessForCurrentUser:
  • 86. DevCamp ACL methods PFObject *groupMessage = [PFObject objectWithClassName:@"Message"]; PFACL *groupACL = [PFACL ACL];       // userList is an NSArray with the users we are sending this message to. for (PFUser *user in userList) {     [groupACL setReadAccess:YES forUser:user];     [groupACL setWriteAccess:YES forUser:user]; } groupMessage.ACL = [PFACL ACLWithUser:[PFUser currentUser]];  [groupACL setPublicReadAccess:YES]; groupMessage.ACL = groupACL; [groupMessage saveInBackground];
  • 87. DevCamp Default ACL To help ensure that your users' data is secure by default, you can set a default ACL: // data is visible to the world (readonly) PFACL *defaultACL = [PFACL ACL]; [defaultACL setPublicReadAccess:YES]; [PFACL setDefaultACL:defaultACL withAccessForCurrentUser:YES]; // data is only accessible by the user itself [PFACL setDefaultACL:[PFACL ACL] withAccessForCurrentUser:YES];
  • 89. DevCamp Grouping users Roles provide a logical way of grouping users with common access privileges to your Parse data: • Administrator • User • Guest • ...
  • 90. DevCamp Create Role // By specifying no write privileges for the ACL, we can ensure the role cannot be altered. PFACL *roleACL = [PFACL ACL]; [roleACL setPublicReadAccess:YES]; PFRole *role = [PFRole roleWithName:@"Administrator" acl:roleACL]; [role saveInBackground]; PFRole *role = [PFRole roleWithName:roleName acl:roleACL]; for (PFUser *user in usersToAddToRole) {   [role.users addObject:user]; } [role saveInBackground];
  • 91. DevCamp Security for Objects PFRole *moderators = /* Query for some PFRole */; PFObject *wallPost = [PFObject objectWithClassName:@"WallPost"]; PFACL *postACL = [PFACL ACL]; [postACL setWriteAccess:YES forRole:moderators]; wallPost.ACL = postACL; [wallPost saveInBackground];
  • 92. DevCamp Security for Objects PFRole *moderators = /* Query for some PFRole */; PFObject *wallPost = [PFObject objectWithClassName:@"WallPost"]; PFACL *postACL = [PFACL ACL]; [postACL setWriteAccess:YES forRole:moderators]; wallPost.ACL = postACL; [wallPost saveInBackground]; [postACL setWriteAccess:YES forRoleWithName:@"Moderators"];
  • 93. DevCamp Hierarchy PFRole *administrators = /* Your "Administrators" role */; PFRole *moderators = /* Your "Moderators" role */; [moderators.roles addObject:administrators]; [moderators saveInBackground]; Any user with Administrator privileges should also be granted the permissions of any Moderator:
  • 94. DevCamp Best practise [PFUser enableAutomaticUser]; PFACL *defaultACL = [PFACL ACL]; // Optionally enable public read access while disabling public write access. // [defaultACL setPublicReadAccess:YES]; [PFACL setDefaultACL:defaultACL withAccessForCurrentUser:YES]; • restrict access to data as much as possible • specify a default ACL based upon the current user
  • 97. DevCamp Push notitification - (void)application:(UIApplication *)application         didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {     // Store the deviceToken in the current Installation and save it to Parse.     PFInstallation *currentInstallation = [PFInstallation currentInstallation];     [currentInstallation setDeviceTokenFromData:deviceToken];     [currentInstallation saveInBackground]; } Every Parse application installed on a device registered for push notifications has an associated Installation object.The Installation object is where you store all the data needed to target push notifications.
  • 98. DevCamp Installation While it is possible to modify a PFInstallation just like you would a PFObject, there are several special fields that help manage and target devices. • badge:The current value of the icon badge for iOS apps. Changing this value on the PFInstallation will update the badge value on the app icon. Changes should be saved to the server so that they will be used for future badge-increment push notifications. • channels:An array of the channels to which a device is currently subscribed. • timeZone:The current time zone where the target device is located.This value is synchronized every time anInstallation object is saved from the device (readonly). • deviceType:The type of device, "ios", "android", "winrt", "winphone", or "dotnet"(readonly). • installationId: Unique Id for the device used by Parse (readonly). • deviceToken:The Apple generated token used for iOS devices (readonly). • channelUris:The Microsoft-generated push URIs for Windows devices (readonly). • appName:The display name of the client application to which this installation belongs (readonly). • appVersion:The version string of the client application to which this installation belongs (readonly). • parseVersion:The version of the Parse SDK which this installation uses (readonly). • appIdentifier:A unique identifier for this installation's client application. In iOS, this is the Bundle Identifier(readonly).
  • 99. DevCamp Channels // When users indicate they are pragmamark fans, we subscribe them to that channel. PFInstallation *currentInstallation = [PFInstallation currentInstallation]; // When users indicate they are no longer Giants fans, we unsubscribe them. // [currentInstallation removeObject:@”pragmamark” forKey:@”channels”]; [currentInstallation addUniqueObject:@"pragmamark" forKey:@"channels"]; [currentInstallation saveInBackground]; This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers.
  • 100. DevCamp Sending Pushes to channel // Send a notification to all devices subscribed to the "Giants" channel. PFPush *push = [[PFPush alloc] init]; [push setChannel:@"pragmamark"]; // [push setChannels:@[@”pragmamark”, @”devcamp”]]; [push setMessage:@"PragmaDevCamp is coming!!"]; [push sendPushInBackground];
  • 101. DevCamp Sending Pushes to queries // Create our Installation query PFQuery *pushQuery = [PFInstallation query]; [pushQuery whereKey:@"local" equalTo:@"IT"];   // Send push notification to query PFPush *push = [[PFPush alloc] init]; [push setQuery:pushQuery]; // Set our Installation query [push setMessage:@"Ancora pochi giorni per registrarsi al DevCamp"]; [push sendPushInBackground];
  • 102. DevCamp Customizing • alert: the notification's message. • badge: (iOS only) the value indicated in the top right corner of the app icon.This can be set to a value or toIncrement in order to increment the current value by 1. • sound: (iOS only) the name of a sound file in the application bundle. • content-available: (iOS only) if you are using Newsstand, set this value to 1 to trigger a background download. • action: (Android only) the Intent should be fired when the push is received. If not title or alert values are specified, the Intent will be fired but no notification will appear to the user. • title: (Android & Windows 8 only) the value displayed in the Android system tray or Windows toast notification.
  • 103. DevCamp Customizing example // Create date object for tomorrow NSDateComponents *comps = [[NSDateComponents alloc] init]; [comps setYear:2013]; [comps setMonth:5]; [comps setDay:30]; NSCalendar *gregorian =   [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDate *date = [gregorian dateFromComponents:comps];   // Send push notification with expiration date PFPush *push = [[PFPush alloc] init]; [push expireAtDate:date]; // [push expireAfterTimeInterval: 60 * 60 * 24 * 7] - 1 week [push setQuery:everyoneQuery]; [push setMessage:@"Season tickets on sale until May 30th"]; [push sendPushInBackground];
  • 104. DevCamp Receiving pushes - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {   . . .   // Extract the notification data   NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];   } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {   // Create empty photo object   NSString *photoId = [userInfo objectForKey:@"p"]; }
  • 105. DevCamp Clearing the badge - (void)applicationDidBecomeActive:(UIApplication *)application {   PFInstallation *currentInstallation = [PFInstallation currentInstallation];   if (currentInstallation.badge != 0) {     currentInstallation.badge = 0;     [currentInstallation saveEventually];   }   // ... }
  • 107. DevCamp • Parse.com • NSScreencast.com • http://www.raywenderlich.com/19341/how-to- easily-create-a-web-backend-for-your-apps-with- parse Link