iOS App with Parse.com as RESTful Backend

5,120 views

Published on

Published in: Technology, Education
0 Comments
16 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,120
On SlideShare
0
From Embeds
0
Number of Embeds
267
Actions
Shares
0
Downloads
0
Comments
0
Likes
16
Embeds 0
No embeds

No notes for slide

iOS App with Parse.com as RESTful Backend

  1. 1. Stefano Zanetti § DevCampParse.comiOS App with Parse.com as RESTful Backend
  2. 2. DevCampStefano Zanetti Apple iOS DeveloperSuperpartes 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. 3. DevCampWhat is Parse.com?The perfect cloud for your apps.Parse allows your team to focus on creating agreat user experience and forget servermaintenance and complex infrastructure.
  4. 4. DevCampWhat does this mean?• Backend for apps and websites• Database NoSQL (schemaless: if you need to storesomething, 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
  5. 5. DevCampWho can you it?
  6. 6. DevCampHow much?BasicBasicBasic ProProPro EnterpriseEnterpriseEnterpriseGreat 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 featuresFREEFREEFREE $199/month$199/month$199/month contact Parsecontact Parsecontact ParseRequest Pushes Burst limit Request Pushes Burst limit Request Pushes Burst limit1 milion/month1 milion/month20/second15 milion/month5 milion/month40/secondcontactParse
  7. 7. DevCampFeatures
  8. 8. DevCampMore features
  9. 9. DevCampApp Settings
  10. 10. DevCampWhere?http://www.parse.com
  11. 11. DevCampDashboard
  12. 12. DevCampGeneral
  13. 13. DevCampApplication Keys
  14. 14. DevCampPush Notifications
  15. 15. DevCampWeb Hosting
  16. 16. DevCampAdministrative Tools
  17. 17. DevCampData Browser
  18. 18. DevCampAnalytics
  19. 19. DevCampPush Notifications Status
  20. 20. DevCampSend push
  21. 21. DevCampDemo
  22. 22. DevCampGet started
  23. 23. DevCampSDK• Quick start:• https://www.parse.com/docs• Download from official site:• https://www.parse.com/docs/downloads/• CocoaPods:• pod Parse, ~> 1.2.9
  24. 24. DevCampQuick start
  25. 25. DevCampQuick start[ParsesetApplicationId:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"clientKey:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"];1.Download the Sample Project2.Xcode 4.6+ and iOS targetting 4.3+3.Open project and uncomment the first line ofapplication:didFinishLaunchingWithOptions: in theapplication delegate file:4.Compile and run
  26. 26. DevCampCreate & Save an ObjectPFObject *testObject = [PFObjectobjectWithClassName:@"TestObject"];[testObject setObject:@"bar" forKey:@"foo"];[testObject save];5.Copy and paste next code somewhere in theproject6.Compile and run
  27. 27. DevCampYeah!!You saved your first object
  28. 28. DevCampWhich 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 then6.0)• Social.framework (optional if iOS targetting is less than 6.0)• Accounts.framework (optional if iOS targetting is less than 6.0)If youre targeting iOS versions less than 5.0, youll need to add the "-fobjc-arc" flag to the "Other Linker Flags" entry in your target build settings.
  29. 29. DevCampPFObject
  30. 30. DevCampSaving/Updating ObjectsPFObject *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. 31. DevCampCheck Data Browser• You dont have to configure or set up a new Class• You dont need to specify a key for the object you are savingParse automatically fills 3 field:• objectId• createdAt• updatedAtobjectId: "xWMyZ4YEGZ", title: "New post", message: "This is myfirst message", visible: false, createdAt:"2011-06-10T18:33:42Z",updatedAt:"2011-06-10T18:33:42Z"
  32. 32. DevCampRetriving DataUsing PFQuery you can retrive a PFObjectPFQuery *query = [PFQuery queryWithClassName:@"Post"];PFObject *post = [query getObjectWithId:@"xWMyZ4YEGZ"];NSString *postTitle = [post objectForKey:@"title"];BOOL visible = [[post objectForKey:@"visible"] boolValue];
  33. 33. DevCampNote!!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 thelatest data that is in the Parse Cloud, you can call therefresh method like so:[myObject refresh];
  34. 34. DevCampSaving in backgroundJust call saveInBackground method[post saveInBackground];
  35. 35. DevCampBlocksIf you want to run code when operation is completed youcan 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. 36. DevCampCallbacks// 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:selfselector:@selector(saveCallback:error:)];
  37. 37. DevCampLoad in backgroundPFQuery *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. 38. DevCampLoad 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. 39. DevCampSaving Objects OfflineJust call saveEventually method and system store the updateon the device until a network connection is available[post saveEventually];
  40. 40. DevCampSaving Counter ObjectsThe “likes” field is a counter:[post incrementKey:@"likes"];[post saveInBackground];or[post incrementKey:@"likes" byAmount:3];[post saveInBackground];
  41. 41. DevCampSaving Array Objects• addObject:forKey: and addObjectsFromArray:forKey: append the givenobjects to the end of an array field.• addUniqueObject:forKey: and addUniqueObjectsFromArray:forKey: add onlythe given objects which arent already contained in an array field to thatfield.The position of the insert is not guaranteed.• removeObject:forKey: and removeObjectsInArray:forKey: remove allinstances of each given object from an array field.[post addUniqueObjectsFromArray:[NSArrayarrayWithObjects:@"stefano", @"massimo", nil] forKey:@"users"];[post saveInBackground];
  42. 42. DevCampDelete ObjectsTo 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];
  43. 43. DevCampDemo
  44. 44. DevCampRelational Data
  45. 45. DevCampOne-To-Many Relationship// Create the postPFObject *myPost = [PFObject objectWithClassName:@"Post"];[myPost setObject:@"Im Hungry" forKey:@"title"];[myPost setObject:@"Where should we go for lunch?" forKey:@"content"]; // Create the commentPFObject *myComment = [PFObject objectWithClassName:@"Comment"];[myComment setObject:@"Lets 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. 46. DevCampOne-To-Many RelationshipYou can also link objects using just their objectIds like so:// Add a relation between the Post with objectId "1zEcyElZ80" andthe comment[myComment setObject:[PFObjectobjectWithoutDataWithClassName:@"Post" objectId:@"1zEcyElZ80"]              forKey:@"parent"];
  47. 47. DevCampOne-To-Many RelationshipBy default, when fetching an object, relatedPFObjects are not fetched:PFObject *post = [fetchedComment objectForKey:@"parent"];[post fetchIfNeededInBackgroundWithBlock:^(PFObject *object,NSError *error) {  NSString *title = [post objectForKey:@"title"];}];
  48. 48. DevCampMany-To-Many RelationshipA 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. 49. DevCampMany-To-Many RelationshipBy default, the list of objects in this relationare 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. 50. DevCampMany-To-Many RelationshipIf you want only a subset of the Posts you can addextra constraints to the PFQuery returned by queryPFQuery *query = [relation query];// Add other query constraints.
  51. 51. DevCampData types
  52. 52. DevCampWhat 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 nestNSDictionary and NSArray objects to store more structured data within a single PFObject.
  53. 53. DevCampPFQuery
  54. 54. DevCampBasic QueriesPFQuery *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 aNSArray of matching PFObjects using either findObjectsInBackgroundWithBlock: orfindObjectsInBackgroundWithTarget:selector:
  55. 55. DevCampBasic 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. 56. DevCampNSPredicateNSPredicate *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. 57. DevCampQuery Constraints[query whereKey:@"playerName" notEqualTo:@"Michael Yabuti"];[query whereKey:@"playerAge" greaterThan:[NSNumber numberWithInt:18]];query.limit = 10; // limit to at most 10 resultsquery.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. 58. DevCampConstraints on Array// Finds scores from anyone who is neither Jonathan, Dario, norShawnNSArray *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. 59. DevCampConstraints 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 keysarray 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 keys array value containseach of the values 2, 3, and 4 with the following:
  60. 60. DevCampCheck particular key// Finds objects that have the score set[query whereKeyExists:@"score"]; // Finds objects that dont have the score set[query whereKeyDoesNotExist:@"score"];If you want to retrieve objects that have a particular key set or not:
  61. 61. DevCampMatches KeyPFQuery *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 awinning record}];You can use the whereKey:matchesKey:inQuery: method to get objectswhere a key matches the value of a key in a set of objects resulting fromanother query. (use whereKey:doesNotMatchKey:inQuery: to get objectswhere a key does not match)
  62. 62. DevCampRestrict the returned fieldsPFQuery *query = [PFQuery queryWithClassName:@"GameScore"];[query selectKeys:@[@"playerName", @"score"]];NSArray *results = [query findObjects];The remaining fields can be fetched later by calling one of thefetchIfNeeded 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. 63. DevCampQueries on string value// Finds barbecue sauces that start with "Big Daddys".PFQuery *query = [PFQuery queryWithClassName:@"BarbecueSauce"];[query whereKey:@"name" hasPrefix:@"Big Daddys"];
  64. 64. DevCampRelational 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. 65. DevCampMatches QueryPFQuery *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 PFObjectthat match a different query, you can use whereKey:matchesQuery: (orwhereKey:notMatchQuery:)Note that the default limit of 100 and maximum limit of 1000apply to the inner query as well.
  66. 66. DevCampInclude KeyPFQuery *query = [PFQuery queryWithClassName:@"Comment"];// Retrieve the most recent ones[query orderByDescending:@"createdAt"];// Only retrieve the last tenquery.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 useincludeKey: method:
  67. 67. DevCampInclude Key[query includeKey:@"post.author"];You can also do multi level includes using dot notation:
  68. 68. DevCampCaching Policyquery.cachePolicy = kPFCachePolicyNetworkElseCache;The default query behavior doesnt use the cache, but you can enablecaching by setting query.cachePolicy.• kPFCachePolicyIgnoreCache: is the default cache policy.• kPFCachePolicyCacheOnly :The query only loads from the cache, ignoring the network. If there areno cached results, that causes a PFError.• kPFCachePolicyNetworkOnly:The query does not load from the cache, but it will save results tothe cache.• kPFCachePolicyCacheElseNetwork:The query first tries to load from the cache, but if that fails, itloads 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 thatfails, 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 thenetwork. In this case, the callback will actually be called twice - first with the cached results, then with thenetwork results. Since it returns two results at different times, this cache policy cannot be usedsynchronously with findObjects.
  69. 69. DevCampControl the cache’s behaviorBOOL 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. 70. DevCampCounting ObjectsPFQuery *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 notneed to retrieve the objects that match, you can use countObjects instead offindObjects.
  71. 71. DevCampCompound QueriesPFQuery *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:[NSArrayarrayWithObjects: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 useorQueryWithSubqueries: method.
  72. 72. DevCampSubclasses
  73. 73. DevCampSubclassing PFObject1.Declare a subclass which conforms to the PFSubclassing protocol.2.Implement the class method parseClassName.This is the string you wouldpass to initWithClassName: and makes all future class name referencesunnecessary.3.Import PFObject+Subclass in your .m file.This implements all methods inPFSubclassing beyond parseClassName.4.Call [YourClass registerSubclass] in your ApplicationDelegate beforeParse setApplicationId:clientKey:.
  74. 74. DevCampExample 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 *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  [Armor registerSubclass];  [Parse setApplicationId:parseAppId clientKey:parseClientKey];}
  75. 75. DevCampProperty & 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. 76. DevCampQueryPFQuery *query = [Armor query];[query whereKey:@"rupees"lessThanOrEqualTo:PFUser.currentUser.rupees];[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError*error) {  if (!error) {    Armor *firstArmor = [objects objectAtIndex:0];    // ...  }}];
  77. 77. DevCampPFFile
  78. 78. DevCampWhy PFFile?PFFile lets you store application files in the cloud that would otherwise betoo large or cumbersome to fit into a regular PFObject. (up to 10 megabytes)
  79. 79. DevCampSaving a file on the cloudThen you can associate a PFFile onto a PFObject just like any other piece ofdata:NSData *data = [@"Working at Parse is great!"dataUsingEncoding:NSUTF8StringEncoding];PFFile *file = [PFFile fileWithName:@"resume.txt" data:data];[file saveInBackground];PFObject *jobApplication = [PFObjectobjectWithClassName:@"JobApplication"][jobApplication setObject:@"Joe Smith" forKey:@"applicantName"];[jobApplication setObject:file       forKey:@"applicantResumeFile"];[jobApplication saveInBackground];
  80. 80. DevCampUpload / DownloadNSData *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 between0 and 100.}];Use saveInBackgroundWithBlock:progressBlock: andgetDataInBackgroundWithBlock:progressBlock:
  81. 81. DevCampPFUser
  82. 82. DevCampSignUp / SignInPFUser *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. 83. DevCampCurrent UserPFUser *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:
  84. 84. DevCampPFACL
  85. 85. DevCampSecurityTo limit access to some users you have many possibility:• ACLWithUser:• setReadAccess:forUser: or setWriteAccess:forUser:• setPublicReadAccess: or setPublicWriteAccess:• setDefaultACL:withAccessForCurrentUser:
  86. 86. DevCampACL methodsPFObject *groupMessage = [PFObject objectWithClassName:@"Message"];PFACL *groupACL = [PFACL ACL];     // userList is an NSArray with the users we are sending thismessage 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. 87. DevCampDefault ACLTo help ensure that your users data is secure by default, youcan 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];
  88. 88. DevCampPFRole
  89. 89. DevCampGrouping usersRoles provide a logical way of grouping users with common access privilegesto your Parse data:• Administrator• User• Guest• ...
  90. 90. DevCampCreate Role// By specifying no write privileges for the ACL, we can ensure the rolecannot 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. 91. DevCampSecurity for ObjectsPFRole *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. 92. DevCampSecurity for ObjectsPFRole *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. 93. DevCampHierarchyPFRole *administrators = /* Your "Administrators" role */;PFRole *moderators = /* Your "Moderators" role */;[moderators.roles addObject:administrators];[moderators saveInBackground];Any user with Administrator privileges should also be granted thepermissions of any Moderator:
  94. 94. DevCampBest practise[PFUser enableAutomaticUser];PFACL *defaultACL = [PFACL ACL];// Optionally enable public read access while disabling publicwrite 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
  95. 95. DevCampDemo
  96. 96. DevCampPFPush
  97. 97. DevCampPush notitification- (void)application:(UIApplication *)application        didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{    // Store the deviceToken in the current Installation and save it toParse.    PFInstallation *currentInstallation = [PFInstallationcurrentInstallation];    [currentInstallation setDeviceTokenFromData:deviceToken];    [currentInstallation saveInBackground];}Every Parse application installed on a device registered for pushnotifications has an associated Installation object.The Installation object iswhere you store all the data needed to target push notifications.
  98. 98. DevCampInstallationWhile it is possible to modify a PFInstallation just like you would a PFObject, there are several specialfields that help manage and target devices.• badge:The current value of the icon badge for iOS apps. Changing this value on the PFInstallationwill update the badge value on the app icon. Changes should be saved to the server so that theywill 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 synchronizedevery 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 installations client application. In iOS, this is the BundleIdentifier(readonly).
  99. 99. DevCampChannels// When users indicate they are pragmamark fans, we subscribe themto that channel.PFInstallation *currentInstallation = [PFInstallationcurrentInstallation];// When users indicate they are no longer Giants fans, weunsubscribe 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 canlater be sent to these subscribers.
  100. 100. DevCampSending 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. 101. DevCampSending Pushes to queries// Create our Installation queryPFQuery *pushQuery = [PFInstallation query];[pushQuery whereKey:@"local" equalTo:@"IT"]; // Send push notification to queryPFPush *push = [[PFPush alloc] init];[push setQuery:pushQuery]; // Set our Installation query[push setMessage:@"Ancora pochi giorni per registrarsi alDevCamp"];[push sendPushInBackground];
  102. 102. DevCampCustomizing• alert: the notifications message.• badge: (iOS only) the value indicated in the top right corner of the app icon.This can beset 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 abackground download.• action: (Android only) the Intent should be fired when the push is received. If not titleor alert values are specified, the Intent will be fired but no notification will appear tothe user.• title: (Android & Windows 8 only) the value displayed in the Android system tray orWindows toast notification.
  103. 103. DevCampCustomizing example// Create date object for tomorrowNSDateComponents *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 datePFPush *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. 104. DevCampReceiving pushes- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  . . .  // Extract the notification data  NSDictionary *notificationPayload =launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; }- (void)application:(UIApplication *)applicationdidReceiveRemoteNotification:(NSDictionary *)userInfo {  // Create empty photo object  NSString *photoId = [userInfo objectForKey:@"p"];}
  105. 105. DevCampClearing the badge- (void)applicationDidBecomeActive:(UIApplication *)application {  PFInstallation *currentInstallation = [PFInstallationcurrentInstallation];  if (currentInstallation.badge != 0) {    currentInstallation.badge = 0;    [currentInstallation saveEventually];  }  // ...}
  106. 106. DevCampDemo
  107. 107. DevCamp• Parse.com• NSScreencast.com• http://www.raywenderlich.com/19341/how-to-easily-create-a-web-backend-for-your-apps-with-parseLink
  108. 108. DevCampDomande?facebook.com/pragmamarkfacebook.com/groups/pragmamark@pragmamarkorghttp://pragmamark.org
  109. 109. DevCampNSLog(@”Thank you!”);stefano.zanetti@pragmamark.org

×