Skip to content

Upgrading from v0.10.x to v0.20.0

mygz edited this page Jun 20, 2013 · 33 revisions

Using AFNetworking

One of the big changes is that the custom networking code has been dropped and replaced by the widely used AFNetworking library. This means RKClient and related classes are no longer part of RestKit.

Delegates

The delegate protocols RKRequestDelegate and RKObjectLoaderDelegate have been removed from the project in favor of block based approaches. The most common, required methods of these protocols such as request:didLoadResponse:, request:didLoadError:, objectLoader:didLoadObjects:, and objectLoader:didLoadError: have been replaced with completion blocks on the AFHTTPRequestOperation and RKObjectRequestOperation classes. In general, these completion blocks are specified as a pair of success and failure blocks:

RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; 
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
    // This is the success block
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    // This is the failure block
}];
[operation start];

See the API Docs for more information.

Aside from the basic success/failure scenarios, AFNetworking exposes many common tasks via the AFHTTPURLConnection class, which is the superclass of AFHTTPRequestOperation and implements the NSURLConnectionDelegate and NSURLConnectionDataDelegate protocols. You can utilize these blocks and subclassing strategies to accomplish all other tasks that were previously done via RKRequest or RKObjectLoader.

Additional detail about the specific interactions between RestKit, AFNetworking, and NSURLConnection are explored in detail in the AFNetworking Integration guide.

HTTP Headers

in 0.10:

RKObjectManager* objectManager = [RKObjectManager managerWithBaseURLString:url];
[objectManager.client setValue:@"foobar" forHTTPHeaderField:@"X-Custom-Header"];

in 0.20:

    RKObjectManager* objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:url]];
    [objectManager.HTTPClient setDefaultHeader:@"X-Custom-Header" value:@"foobar"];

Invalidate Cache

in 0.10:

    RKObjectManager *objectManager = [RKObjectManager sharedManager];
    [objectManager.client.requestCache invalidateAll];

in 0.20:

    [[NSURLCache sharedURLCache] removeAllCachedResponses];

Activity indicator

in 0.10:

    RKObjectManager* objectManager = [RKObjectManager managerWithBaseURLString:url];
    objectManager.client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;

in 0.20:

    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;

Network Reachability Alert

In 0.10:

objectManager.client.serviceUnavailableAlertEnabled = YES;

In 0.20:

[objectManager.HTTPClient setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    if (status == AFNetworkReachabilityStatusNotReachable) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No network connection"
                                                        message:@"You must be connected to the internet to use this app."
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
        [alert show];
    }
}];

Adding routes to an object manager's route set

in 0.10:

    [objectManager.router 
        routeClass:[Activity class] 
        toResourcePath:@"/activity/:identifier"] ;
    [objectManager.router 
        routeClass:[Activity class] 
        toResourcePath:@"/activity" 
        forMethod:RKRequestMethodPOST] ;

in 0.20:

    [objectManager.router.routeSet addRoute:[RKRoute 
        routeWithClass:[Activity class] 
        pathPattern:@"/activity/:identifier" 
        method:RKRequestMethodGET]] ;
    [objectManager.router.routeSet addRoute:[RKRoute 
        routeWithClass:[Activity class] 
        pathPattern:@"/activity" 
        method:RKRequestMethodPOST]] ;

POSTing objects with file uploads

The sample code assumes you've registered a POST route for your object in the object manager's route set. See "Adding routes to an object manager's route set" above.

in 0.10:

    RKObjectManager *mgr = [RKObjectManager sharedManager];
    [mgr postObject:obj usingBlock:^(RKObjectLoader *loader) {
        RKParams* params = [RKParams params];
        [params setValue:obj.name forParam:@"expense[name]"];
        [params setValue:obj.amount forParam:@"expense[amount]"];
        RKParamsAttachment *attachment = [params setData:UIImageJPEGRepresentation(obj.photo, 0.7)
                                                MIMEType:@"image/jpeg"
                                                forParam:@"expense[photo_file]"];
        attachment.fileName = @"image.jpg";
        loader.params = params;

        // What ever success handler you need.
        loader.onDidLoadObject = ^(id loaded) {
            NSLog(@"%@", loaded);
        };
    }];

in 0.20:

    // But this time assuming you registered a RKRequestDescriptor to handle
    // serializing the other fields.
    RKObjectManager *objectManager = [RKObjectManager sharedManager];
    NSMutableURLRequest *request =
    [objectManager multipartFormRequestWithObject:obj method:RKRequestMethodPOST
                                             path:nil parameters:nil
                        constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
    {
        [formData appendPartWithFileData:UIImageJPEGRepresentation(obj.photo, 0.7)
                                    name:@"expense[photo_file]"
                                fileName:@"photo.jpg"
                                mimeType:@"image/jpeg"];
    }];
    RKObjectRequestOperation *operation =
    [objectManager objectRequestOperationWithRequest:request
                                             success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
    {
        // Success handler.
        NSLog(@"%@", [mappingResult firstObject]);
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        // Error handler.
    }];

Object Requests

GET objects with a loader block

The big change is the lack of a loader object and the new more consistent callback signature with RKMappingResult wraps the results of the mapping.

In 0.10:

    [ [RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/examples" usingBlock:^(RKObjectLoader *loader) {
        loader.onDidLoadObjects = ^(NSArray *objects) {
            NSLog(@"It Worked: %@", objects);
        };
        loader.onDidFailWithError = ^(NSError *error) {
            NSLog(@"It Failed: %@", error);
        };
    }];

In 0.20:

    [RKObjectManager.sharedManager getObjectsAtPath:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
    {
        NSLog(@"It Worked: %@", [mappingResult array]);
        // Or if you're only expecting a single object:
        NSLog(@"It Worked: %@", [mappingResult firstObject]);
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        NSLog(@"It Failed: %@", error);
    }];

Serialization

Serialization has changed quite a bit since the request and response have separate mappings.

In 0.10:

    RKObjectMapping *serialization = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
    [serialization mapKeyPath:@"amount" toAttribute:@"reimbursal[amount]"];
    [serialization mapKeyPath:@"fromUserId" toAttribute:@"reimbursal[from_user_id]"];
    [serialization mapKeyPath:@"toUserId" toAttribute:@"reimbursal[to_user_id]"];
    [provider setSerializationMapping:serialization forClass:[RMReimbursal class]];

In 0.20:

    RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
    [requestMapping addAttributeMappingsFromDictionary:@{
     @"amount": @"amount",
     @"fromUserId": @"from_user_id",
     @"toUserId": @"to_user_id",
     }];
    [objectManager addRequestDescriptor:
     [RKRequestDescriptor requestDescriptorWithMapping:requestMapping
                                           objectClass:[RMReimbursal class]
                                           rootKeyPath:@"reimbursal"]];

Cancel all requests

in 0.10:

    [[RKClient sharedClient].requestQueue cancelAllRequests];

in 0.20:

    [[RKObjectManager sharedManager].operationQueue cancelAllOperations];

Core Data

TODO: summarize the changes.

Entity Mappings

In 0.10:

    // Defined elsewhere:
    RKMapping *userMapping; 
    RKManagedObjectStore *objectStore

    // The meat of it:
    RKEntityMapping* mapping = [RKEntityMapping
                             mappingForEntityForName:@"RMHousehold"
                                inManagedObjectStore:objectStore];

    mapping.primaryKeyAttribute = @"householdId";

    [mapping mapKeyPath:@"id" toAttribute:@"householdId"];
    [mapping mapKeyPath:@"display_name" toAttribute:@"displayName"];

    [mapping mapKeyPath:@"users" toRelationship:@"users"
            withMapping:userMapping];

In 0.20:

    // Defined elsewhere:
    RKMapping *userMapping;
    RKManagedObjectStore *objectStore;

    RKEntityMapping* mapping = [RKEntityMapping
                             mappingForEntityForName:@"RMHousehold"
                                inManagedObjectStore:objectStore];
    mapping.identificationAttributes = @[@"householdId"] ;

    [mapping addAttributeMappingsFromDictionary:@{
     @"id": @"householdId",
     @"display_name": @"displayName",
     }];

    RKRelationshipMapping *userRelationship =
    [RKRelationshipMapping relationshipMappingFromKeyPath:@"users"
                                                toKeyPath:@"users"
                                              withMapping:userMapping];
    [mapping addPropertyMapping:userRelationship];

RKManagedObjectMapping

In 0.10

    [RKManagedObjectMapping mappingForClass:[RMHousehold class]
                       inManagedObjectStore:[RKObjectManager sharedManager].objectStore];

In 0.20

    [RKEntityMapping mappingForEntityForName:@"RMHousehold"
                        inManagedObjectStore:[RKObjectManager sharedManager].managedObjectStore];

RKManagedObjectStore

In 0.10

RKManagedObjectStore *managedObjectStore =
[RKManagedObjectStore managedObjectStoreWithStoreFilename:storeFilename];

In 0.20

self.objectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"StoreFileName.sqlite"];
[self.objectStore addSQLitePersistentStoreAtPath:path
                          fromSeedDatabaseAtPath:nil
                               withConfiguration:nil
                                         options:@{
              NSInferMappingModelAutomaticallyOption: @YES,
        NSMigratePersistentStoresAutomaticallyOption: @YES
     }
                                           error:nil];
[self.objectStore createManagedObjectContexts];

Mapping an Object Representation Directly

RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[SomeClass class]];
[mapping addAttributeMappingsFromDictionary:@{ @"id": @"someClassID", @"name": @"name" }];
    
NSDictionary *objectRepresentation = @{ @"id": @(12345), @"name": @"Some Name" };
SomeClass *someObject = [SomeClass new];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:objectRepresentation destinationObject:someObject mapping:mapping];
RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new];
operation.dataSource = dataSource;
[operation start];

Miscellaneous

In 0.10

NSString *directory = [RKDirectory applicationDataDirectory];

In 0.20

NSString *directory = RKApplicationDataDirectory();