From c68a04cadd4dd844b61fe3b650aa9f9ea459c8af Mon Sep 17 00:00:00 2001 From: Scott Gardner Date: Thu, 27 Mar 2014 18:39:41 -0500 Subject: [PATCH] Correct grammatical and code errata --- TUTORIAL.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/TUTORIAL.md b/TUTORIAL.md index 37189da..d554fd3 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -495,7 +495,7 @@ Now, quite a bit of magic has just taken place and its worth taking a step back * Created and started an asynchronous HTTP request operation that is aware of our JSON -> model binding and capable of object mapping the response back into our `Gist` entity. * Waited for the request to complete and the app to update the UI and display our Gist objects. -Let's now work through each part of the process in depth and get acquainted the RestKit API's we've just utilized. +Let's now work through each part of the process in depth and get acquainted with the RestKit API's we've just utilized. #### Defining the Mapping @@ -503,7 +503,7 @@ All RestKit mapping operations are driven by an **object mapping**. There are se Since the `RKGist` application uses Core Data for persistence, we have created and instantiated an `RKEntityMapping`. Entity mappings are defined in terms of the Core Data entity that they will map object representations into. The designated initializer for `RKEntityMapping` is [`initWithEntity:`](http://restkit.org/api/latest/Classes/RKEntityMapping.html#//api/name/initWithEntity:), but it is common to use the convenience constructor [`mappingForEntityForName:inManagedObjectStore:`](http://restkit.org/api/latest/Classes/RKEntityMapping.html#//api/name/mappingForEntityForName:inManagedObjectStore:) to lookup the entity by name. We leveraged the shared instance accessor `[RKManagedObjectStore defaultStore]` to retrieve a reference to the managed object store we previously configured in the app delegate. We then provided the name of our entity and the managed object store instance to `mappingForEntityForName:inManagedObjectStore:` to lookup the entity by name and return a ready to use object mapping. -You may notice that thus far we have not specified a destination class for objects created by the mapping -- we've only referred to entities. This is because Core Data does not require you to define a backing model class for the entity. The mapper will happily created `NSManagedObject` instances for you -- indeed this is what we've just done within `RKGist` as we have not yet created any model classes. +You may notice that thus far we have not specified a destination class for objects created by the mapping -- we've only referred to entities. This is because Core Data does not require you to define a backing model class for the entity. The mapper will happily create `NSManagedObject` instances for you -- indeed this is what we've just done within `RKGist` as we have not yet created any model classes. Once the mapping was initialized, we invoked [`addAttributeMappingsFromDictionary:`](http://restkit.org/api/latest/Classes/RKObjectMapping.html#//api/name/addAttributeMappingsFromDictionary:) with a dictionary whose keys correspond to the names of fields in the JSON example for a gist and whose values correspond to the names of attributes defined in the `Gist` entity we configured in the Core Data managed object model. This method is actually a convenience method whose implementation is: @@ -525,7 +525,7 @@ This illustrates an important point about `RKObjectMapping` (and through inherit After creating the entity mapping for the `Gist` entity, the next block of code establishes a binding between an HTTP response and the mapping: ```objc -RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping method:RKRequestMethodAny pathPattern:@"/gists/public" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping method:RKRequestMethodGET pathPattern:@"/gists/public" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; ``` Here we are introduced to the [`RKResponseDescriptor`](http://restkit.org/api/latest/Classes/RKResponseDescriptor.html) class, which is responsible for linking the object mapping system with HTTP responses. It is important to keep in mind that the object mapping engine is completely independent of dependencies on HTTP -- it's a generalized system for describing and executing the transformation of objects across representations. HTTP just happens to be a very common transport mechanism for object representations. @@ -533,7 +533,7 @@ Here we are introduced to the [`RKResponseDescriptor`](http://restkit.org/api/la `RKResponseDescriptor` lets you describe the circumstances in which a given object mapping should be used to process an HTTP response. There are four properties available for configuration: * `pathPattern` - The path pattern is a specially formatted string that is matched against the URL from which the HTTP response was loaded. The pattern can contain colon delimited dynamic components that identify the parts of your URL that can change. For example, consider the following URL for a gist at Github: `https://api.github.com/gists/4774273`. Within this URL, `4774273` represents the ID of a particular gist. This is a dynamic component of the URL that can change from request to request, but we know that every time a response is loaded from `/gists/XXXX` that the response will contain a representation of a Gist object. We can configure the response descriptor to match this URL by configuring a path pattern that matches it: `/gists/:gistID`. The `gistID` is interpreted as a dynamic component because it is prefixed with a colon. -* `method` - The HTTP method to be used in the request. Enum options available are: RKRequestMethodPOST, RKRequestMethodPUT, RKRequestMethodDELETE, RKRequestMethodHEAD, RKRequestMethodPATCH, RKRequestMethodOPTIONS, RKRequestMethodAny +* `method` - The HTTP method to be used in the request. Enum options available are: RKRequestMethodGET, RKRequestMethodPOST, RKRequestMethodPUT, RKRequestMethodDELETE, RKRequestMethodHEAD, RKRequestMethodPATCH, RKRequestMethodOPTIONS, RKRequestMethodAny * `keyPath` - The key path identifies where in a parsed response document a given object representation may appear. Recall the previously mentioned importance of key-value coding. When a JSON or XML document is parsed, it is deserialized into an object graph structure composed of `NSArray` and `NSDictionary` objects. This object graph can be traversed using key-value coding. The key-path specified by the response descriptor tells RestKit that a given mapping applies to the subset of a deserialized response that can be obtained by executing `valueForKeyPath:`. This enables you to map different object types out of a single response or process only the subset of a response that you are interested in. * `statusCodes` - The `statusCodes` property is an [`NSIndexSet`](https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSIndexSet_Class/Reference/Reference.html) that specifies the set of HTTP response codes for which a mapping is to be applied. In a RESTful application, the HTTP response codes are used to indicate the success or failure of requests. You can configure a response descriptor to only match the HTTP response codes that you expect the server to return a given representation with. For most API interactions, you typically expect a successful response of 200 or 201, but anything in the 2xx status code class is defined as successful according to the HTTP standard. You can explicitly configure your own `NSIndexSet` specifying the status codes for your descriptor or you can use the RestKit provided helper functions such as `RKStatusCodeIndexSetForClass` to quickly construct common values (see [`RKHTTPUtilities.h`](https://github.com/RestKit/RestKit/blob/development/Code/ObjectMapping/RKHTTPUtilities.h)). The `statusCodes` property figured prominently into the configuration of error mapping, which we'll explore in detail later in the guide. @@ -594,7 +594,7 @@ Now that we've established a solid foundation with the basics of RestKit and Cor `RKObjectManager` provides a centralized interface for creating and executing object request operations that share common properties, such as a [`baseURL`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/baseURL), [required HTTP headers](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/defaultHeaders), or a Core Data [`managedObjectStore`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/managedObjectStore). It also provides support for generating URL's via the [`router`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/router), handles storage of request & response descriptors, and manages an [operation queue](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/operationQueue) for coordinating the execution of object request operations. -You'll typically interact with the object manager by asking it asynchronously perform some task on your behalf, such as performing a [`GET`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/getObject:path:parameters:success:failure:), [`POST`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/postObject:path:parameters:success:failure:), [`PUT`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/putObject:path:parameters:success:failure:), [`PATCH`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/patchObject:path:parameters:success:failure:) or [`DELETE`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/deleteObject:path:parameters:success:failure:) operation on an object or asking it to [load all object representations at a given path](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/getObjectsAtPath:parameters:success:failure:). +You'll typically interact with the object manager by asking it to asynchronously perform some task on your behalf, such as performing a [`GET`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/getObject:path:parameters:success:failure:), [`POST`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/postObject:path:parameters:success:failure:), [`PUT`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/putObject:path:parameters:success:failure:), [`PATCH`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/patchObject:path:parameters:success:failure:) or [`DELETE`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/deleteObject:path:parameters:success:failure:) operation on an object or asking it to [load all object representations at a given path](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/getObjectsAtPath:parameters:success:failure:). #### Configuring the Object Manager @@ -615,7 +615,7 @@ RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Gist @"public": @"public", @"created_at": @"createdAt"}]; -RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:@"/gists/public" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping method:RKRequestMethodGET pathPattern:@"/gists/public" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; [objectManager addResponseDescriptor:responseDescriptor]; ``` @@ -644,7 +644,7 @@ Notice that we have replaced the construction of the `RKManagedObjectRequestOper * The request URL is then used to construct an `NSURLRequest` by invoking [`[RKObjectManager requestWithObject:method:path:parameters:]`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/requestWithObject:method:path:parameters:). Any default headers configured on the manager are applied to the request. * Once the `NSURLRequest` has been constructed, the manager creates an appropriate `RKObjectRequestOperation` (or `RKManagedObjectRequestOperation`) by searching the list of registered response descriptors for all those that match the request and then instantiating the operation. If the request may produce a response that is to be persisted to Core Data (as determined by containing one or more response descriptors whose mapping is an `RKEntityMapping`), then the `managedObjectContext`, `managedObjectCache`, and `fetchRequestBlocks` properties are configured. * The object request operation then has a completion block configured by invoking [`setCompletionBlockWithSuccess:failure:`](http://restkit.org/api/latest/Classes/RKObjectRequestOperation.html#//api/name/setCompletionBlockWithSuccess:failure:) with the blocks passed in via the `success` and `failure` arguments. -* Once the operation has been constructed and configured, it is then started by invoking [`enqueueObjectRequestOperation:`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/enqueueObjectRequestOperation:) to add the operation to the managers [`operationQueue`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/operationQueue). +* Once the operation has been constructed and configured, it is then started by invoking [`enqueueObjectRequestOperation:`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/enqueueObjectRequestOperation:) to add the operation to the manager's [`operationQueue`](http://restkit.org/api/latest/Classes/RKObjectManager.html#//api/name/operationQueue). ### Completion Notification with Core Data @@ -698,7 +698,7 @@ We'll fix this by adding a [`UIRefreshControl`](http://developer.apple.com/libra Now relaunch the app. You'll notice an activity indicator is now present in the table header at launch while the controller is loading content. Once the request finishes, the spinner will dismiss and the table view will load (or you'll see an alert indicating that an error has occurred). -Note that in the above code, the call to `[RKObjectManager getObjectsAtPath:success:failure]` has migrated into a new method `loadGists` and we've replaced the previously `nil` values for the `success` and `failure` arguments with blocks. If the operation completes successfully, then the `success` block is invoked and passed an [`RKMappingResult`](http://restkit.org/api/latest/Classes/RKMappingResult.html) containing all the objects that were mapped from the response. If the operation fails due to any errors, then the `failure` block is invoked and passed an `NSError` object the cause of the failure. This error may during either HTTP transport if, for example, the server to return a 500 (Internal Server Error) response or time out before returning a response. The error may also come from the object mapping engine if, for example, no response descriptors could be found that matched the request or a Core Data validation error were encountered. +Note that in the above code, the call to `[RKObjectManager getObjectsAtPath:success:failure]` has migrated into a new method `loadGists` and we've replaced the previously `nil` values for the `success` and `failure` arguments with blocks. If the operation completes successfully, then the `success` block is invoked and passed an [`RKMappingResult`](http://restkit.org/api/latest/Classes/RKMappingResult.html) containing all the objects that were mapped from the response. If the operation fails due to any errors, then the `failure` block is invoked and passed an `NSError` object indicating the cause of the failure. This error may occur during either HTTP transport if, for example, the server to return a 500 (Internal Server Error) response or time out before returning a response. The error may also come from the object mapping engine if, for example, no response descriptors could be found that matched the request or a Core Data validation error were encountered. In both the `success` and `failure` blocks configured in the `loadGists` method we send the `self.refreshControl` property an `endRefreshing` message to stop the spinner. In the error case we pop up a simple [`UIAlertView`](http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html) to display the error to the user. @@ -755,7 +755,7 @@ Next, highlight all three of the entity names in left portion of the main editin #### Updating the Table Cells -We are going to change the style of the `UITableViewCell` objects used to draw our list of gists to display more information. To do so, first open up `MainStoryboard.storyboard` and click on the **Table View Cell** for the **Master View Controller** scene. Show the **Attributes** inspector in the **Utilities** panel by selecting the **View** > **Utilities** > **Show Attributes Inspector** (or type Apple + Option + 4). In the **Style** drop-down menu, select **Subtitle**. The prototype cell in the Interface Builder scene will update, showing a bold Title label and smaller, gray Subtitle label. +We are going to change the style of the `UITableViewCell` objects used to draw our list of gists to display more information. To do so, first open up `MainStoryboard.storyboard` and click on the **Table View Cell** for the **Master View Controller** scene. Show the **Attributes** inspector in the **Utilities** panel by selecting the **View** > **Utilities** > **Show Attributes Inspector** (or type Apple + Option + 4). In the **Style** drop-down menu, select **Subtitle**. The prototype cell in the Interface Builder scene will update, showing a larger Title label and smaller Subtitle label. Now return to `RKGMasterViewController.m` file and add an import for `RKGGist.h` at the top of the file: @@ -816,7 +816,7 @@ To understand this, we'll learn a bit more about the object mapping system and i When the `created_at` key-path is read from parsed JSON representation of a gist, it is returned as an `NSString` object containing an ISO 8601 formatted representation of the date and time that the gist was created. When RestKit goes to assign the value read from `created_at`, it performs introspection on the type of property that the value is going to be assigned to and determines that the destination class is `NSDate`. The mapper then checks for any registered transformations between the source type (`NSString`) and the destination type (`NSDate`) and performs the conversion. -For many type transformations, the process is very straightforward -- the mapper simply invokes the appropriate conversion method for transforming the value. Conversions between `NSString` and `NSDate` objects, however, face some special challenges and as such, have some special support. `NSDateFormatter` is an Apple provided class that is part of the Foundation framework. It supports the flexible transformation between `NSDate` and `NSString` objects via format strings and is both locale and time zone aware. Unfortunately, it also suffers from a few shortcomings: +For many type transformations, the process is very straightforward -- the mapper simply invokes the appropriate conversion method for transforming the value. Conversions between `NSString` and `NSDate` objects, however, face some special challenges, and as such, have some special support. `NSDateFormatter` is an Apple provided class that is part of the Foundation framework. It supports the flexible transformation between `NSDate` and `NSString` objects via format strings and is both locale and time zone aware. Unfortunately, it also suffers from a few shortcomings: * It is relatively expensive to instantiate. Doing repeated creation of transient instances is a great way to degrade performance. * It requires explicit configuration. A given instance can only parse and emit a single format at a time, so you can't just feed it an arbitrary and expect to get a valid response.