RestKit ,一個用於更好支持RESTful風格服務器接口的iOS庫

簡介

RestKit 是一個用於更好支持RESTful風格服務器接口的iOS庫,可直接將聯網獲取的json/xml數據轉換爲iOS對象.ios

  • 項目主頁: RestKitgit

  • 最新示例: 點擊下載github

  • 注意: 若是沒法直接運行示例根目錄的工程,可嘗試分別運行 Examples 文件夾下的各個子工程,此時你須要給每一個子工程都經過 CocoaPods 安裝一次 RestKit.objective-c

快速入門

使用環境

  • ARCsql

  • iOS 5.1.1 +數據庫

安裝

經過 CocoaPods 安裝

pod 'RestKit'

# 測試和搜索是可選的組件
pod 'RestKit/Testing'
pod 'RestKit/Search'

使用

在須要的地方,引入頭文件:json

/* 若是使用CoreData,必定要在引入RestKit前引入CoreData.RestKit中有一些預編譯宏是基於CoreData是否已經引入;不提早引入CoreData,RestKit中CoreData相關的功能就沒法正常使用. */
#import <CoreData/CoreData.h>
#import <RestKit/RestKit.h>

/* Testing 和 Search 是可選的. */
#import <RestKit/Testing.h>
#import <RestKit/Search.h>

如下示例展現了RestKit的基本用法,涉及到網絡請求的部分已轉由iOS122的測試服務器提供模擬數據.示例代碼複製到Xcode中,可直接執行.建議本身新建工程,經過CocoaPods安裝RestKit測試.bash

對象請求

/**
 *  定義數據模型: Article
 */
@interface Article : NSObject
@property (nonatomic, copy) NSString * title;
@property (nonatomic, copy) NSString * author;
@property (nonatomic, copy) NSString * body;
@end
// 從/vitural/articles/1234.json獲取一篇文章的信息,並把它映射到一個數據模型對象中.
// JSON 內容: {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}}

RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任何 2xx 狀態.
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:articleID" keyPath:@"article" statusCodes:statusCodes];
    
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://dev-test.ios122.com/vitural/articles/1234.json"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
    Article *article = [result firstObject];
    NSLog(@"Mapped the article: %@", article);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    NSLog(@"Failed with error: %@", [error localizedDescription]);
}];
[operation start];

管理對象請求

/* 須要額外引入頭文件:#import "RKManagedObjectRequestOperation.h". */
    
// 從 /vitural/articles/888.json 獲取文章和文章標籤,並存放到Core Data實體中.
// JSON  數據相似: {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!", "categories": [{"id": 1, "name": "Core Data"]}
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSError *error = nil;
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
    RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
}
    
// 若是改了實體結構,注意刪除手機或模擬器對應路徑的數據庫
// 文章和標籤,要設置 1 對 多的關聯!
    
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RestKit.sqlite"]; // 此處要和本身的CoreData數據庫的名字一致.
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
}
[managedObjectStore createManagedObjectContexts];
    
/* 要在Core Data中預約義相關實體. */
RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:@"Category" inManagedObjectStore:managedObjectStore];
[categoryMapping addAttributeMappingsFromDictionary:@{ @"id": @"categoryID", @"name": @"name" }];
RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore];
[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
[articleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"categories" toKeyPath:@"categories" withMapping:categoryMapping]];
    
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任何 2xx的狀態碼
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:articleID" keyPath:@"article" statusCodes:statusCodes];
    
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://dev-test.ios122.com/vitural/articles/888.json"]];
    
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
operation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
operation.managedObjectCache = managedObjectStore.managedObjectCache;
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
    NSLog(@"Mapped the article: %@", [result firstObject]);
    
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    NSLog(@"Failed with error: %@", [error localizedDescription]);
}];
NSOperationQueue *operationQueue = [NSOperationQueue new];
[operationQueue addOperation:operation];

把網絡請求的錯誤信息映射一個到 NSError

// 獲取 /vitural/articles/error.json,返回報頭 422 (Unprocessable Entity)
// JSON 內容: {"errors": "Some Error Has Occurred"}

// 你能夠將錯誤映射到任何類,可是一般使用`RKErrorMessage`就夠了.
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
//  包含錯誤信息的鍵對應的值,映射到iOS類的錯誤信息相關的屬性中.
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]];

NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError);
// 任意報頭狀態碼爲 4xx 的返回值.
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:statusCodes];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://dev-test.ios122.com/vitural/articles/error.json"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@ [errorDescriptor]];
[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) {
    // 映射到的iOS錯誤類的`description`方法用來做爲localizedDescription的值
    NSLog(@"Loaded this error: %@", [error localizedDescription]);
    
    // 你能夠經過`NSError`的`userInfo`獲取映射後的iOS類的對象.
    RKErrorMessage *errorMessage =  [[error.userInfo objectForKey:RKObjectMapperErrorObjectsKey] firstObject];
    
    NSLog(@"%@", errorMessage);
}];

[operation start];

在對象管理器上集中配置.

// 設置文章或請求出錯時的響應描述.
// 成功時的JSON相似於: {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}}
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任意 2xx 狀態碼.

RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:articleID" keyPath:@"article" statusCodes:statusCodes];

// 出錯時返回的JSON相似: {"errors": "Some Error Has Occurred"}
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
// 包含錯誤信息的鍵對應的值,映射到iOS類的錯誤信息相關的屬性中.

[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]];
NSIndexSet *errorStatusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError);
// 任意報頭狀態碼爲 4xx 的返回值.
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:errorStatusCodes];

// 把響應描述添加到管理器上.
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];
[manager addResponseDescriptorsFromArray:@[articleDescriptor, errorDescriptor ]];

// 注意,此處所用的接口已在服務器端設置爲隨機返回正確或錯誤的信息,以便於測試.
[manager getObject: nil path:@"/vitural/articles/555.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    // 處理請求成功獲取的文章.
    Article *article = [mappingResult firstObject];
    NSLog(@"Mapped the article: %@", article);

} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    // 處理錯誤信息.
    NSLog(@"%@", error.localizedDescription);
}];

在對象管理器中整合CoreData

/* 配置管理器. */
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];
[RKObjectManager setSharedManager: manager];
    
/* 將管理器與CoreData整合到一塊兒. */
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
    
NSError * error = nil;
    
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
    RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
}
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RestKit.sqlite"]; // 此處要和本身的CoreData數據庫的名字一致.
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
}
[managedObjectStore createManagedObjectContexts];
    
manager.managedObjectStore = managedObjectStore;
    
/* 將網絡請求的數據存儲到CoreData, 要在Core Data中預約義相關實體. */
RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:@"Category" inManagedObjectStore:manager.managedObjectStore];
[categoryMapping addAttributeMappingsFromDictionary:@{ @"id": @"categoryID", @"name": @"name" }];
RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:manager.managedObjectStore];
[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
[articleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"categories" toKeyPath:@"categories" withMapping:categoryMapping]];
    
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任何 2xx的狀態碼
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:articleID" keyPath:@"article" statusCodes:statusCodes];
    
[manager addResponseDescriptor: responseDescriptor];
[manager getObject: nil path:@"/vitural/articles/888.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    // 處理請求成功獲取的文章.
    NSLog(@"Mapped the article: %@", [mappingResult firstObject]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    // 處理錯誤信息.
    NSLog(@"%@", error.localizedDescription);
}];

從一個地址獲取一組數據

// 設置文章或請求出錯時的響應描述.
    // 成功時的JSON相似於: [{"article":{"title":"My Article 1","author":"Blake 1","body":"Very cool!! 1"}},{"article":{"title":"My Article 2","author":"Blake 2","body":"Very cool!! 2"}},{"article":{"title":"My Article 3","author":"Blake 3","body":"Very cool!! 3"}},{"article":{"title":"My Article 4","author":"Blake 4","body":"Very cool!! 4"}}]
    RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
    [mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
    NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任意 2xx 狀態碼.
    
    RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/vitural/articles" keyPath:@"article" statusCodes:statusCodes];
    
    // 出錯時返回的JSON相似: {"errors": "Some Error Has Occurred"}
    RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
    // 包含錯誤信息的鍵對應的值,映射到iOS類的錯誤信息相關的屬性中.
    
    [errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]];
    NSIndexSet *errorStatusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError);
    // 任意報頭狀態碼爲 4xx 的返回值.
    RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:errorStatusCodes];
    
    // 把響應描述添加到管理器上.
    RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];
    [manager addResponseDescriptorsFromArray:@[articleDescriptor, errorDescriptor ]];

    [manager getObjectsAtPath:@"/vitural/articles" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        // 處理請求成功獲取的文章.
        NSArray * articles = [mappingResult array];
        
        [articles enumerateObjectsUsingBlock:^(Article * article, NSUInteger idx, BOOL *stop) {
            NSLog(@"Mapped the article: %@", article);
        }];
        
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        // 處理錯誤信息.
        NSLog(@"%@", error.localizedDescription);
    }];

使用隊列管理對象請求

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://dev-test.ios122.com/vitural/articles/1234.json"]];

    RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
    [mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
    NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任意 2xx 狀態碼.

    RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/1234.json" keyPath:@"article" statusCodes:statusCodes];

RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[articleDescriptor]];

[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
    Article *article = [result firstObject];
    NSLog(@"Mapped the article: %@", article);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    NSLog(@"Failed with error: %@", [error localizedDescription]);
}];

[manager enqueueObjectRequestOperation:operation]; // 有了這句,就不須要再調用[operation start] 來發起請求了.
[manager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodAny matchingPathPattern:@"/vitural/articles/:articleID\\.json"];

新建,更新 與 刪除對象.

RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[Article class]];
[responseMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任何 2xx 狀態碼
RKResponseDescriptor *articlesDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodAny pathPattern:@"/vitural/articles" keyPath:@"article" statusCodes:statusCodes];

RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:id" keyPath:@"article" statusCodes:statusCodes];

RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];

[requestMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];

// 將 Article 序列化爲NSMutableDictionary ,並以 `article`爲鍵.
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[Article class] rootKeyPath:@"article" method:RKRequestMethodAny];

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];
[manager addRequestDescriptor:requestDescriptor];
[manager addResponseDescriptor:articlesDescriptor];
[manager addResponseDescriptor:articleDescriptor];

Article *article = [Article new];
article.title = @"Introduction to RestKit";
article.body = @"This is some text.";
article.author = @"Blake";

// POST 建立對象.
[manager postObject: article path:@"/vitural/articles" parameters: nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    /* 這個接口服務器的暫時的邏輯是:把POST過去的數據,原樣返回,以確認POST請求成功.*/
        Article *article = [mappingResult firstObject];
        NSLog(@"Mapped the article: %@", article);
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        NSLog(@"Failed with error: %@", [error localizedDescription]);
    }];

// PACTH 更新對象.
article.body = @"New Body";
[manager patchObject:article path:@"/vitural/articles/1234" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    /* 這個接口服務器的暫時的邏輯是:把PACTH過去的數據,原樣返回,以確認PATCH請求成功.*/

    Article *article = [mappingResult firstObject];
    NSLog(@"Mapped the article: %@", article);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    NSLog(@"Failed with error: %@", [error localizedDescription]);
}];

// DELETE 刪除對象.
/* DELETE 操做會影響上面兩個接口,最好單獨操做. */
//    [manager deleteObject:article path:@"/vitural/articles/1234" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
//        /* 這個接口服務器的暫時的邏輯是:把DELTE過去的數據,article字段設爲空,以確認DELETE請求成功.*/
//
//        Article *article = [mappingResult firstObject];
//        NSLog(@"Mapped the article: %@", article);
//    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
//        NSLog(@"Failed with error: %@", [error localizedDescription]);
//    }];

日誌設置

//  記錄全部HTTP請求的請求和相應.
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
    
// 記錄Core Data 的調試信息.
RKLogConfigureByName("RestKit/CoreData", RKLogLevelDebug);
    
// 記錄block的調用.
RKLogWithLevelWhileExecutingBlock(RKLogLevelTrace, ^{
    // 自定義日誌信息.
    
});

配置路由

路由,提供了URL無關的網絡請求調用方式.它是爲了在類/某個名字/某個實體聯繫 與 某個URL創建某種關聯,以便再操做某個對象時,只須要告訴RestKit這個對象自己的某些屬性就能夠直接發送網絡請求,而沒必要每次都去手動拼接 URL.服務器

/* 設置共享的對象管理器. */
    RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];
    [RKObjectManager setSharedManager: manager];
    
    /* 將管理器與CoreData整合到一塊兒. */
    NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
    
    NSError * error = nil;
    
    BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
    if (! success) {
        RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
    }
    NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RestKit.sqlite"]; // 此處要和本身的CoreData數據庫的名字一致.
    NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
    if (! persistentStore) {
        RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
    }
    [managedObjectStore createManagedObjectContexts];
    manager.managedObjectStore = managedObjectStore;

    
    // 響應描述,老是必須的.
    RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
    
    [mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
    
    NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任意 2xx 狀態碼.
    
    RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:articleID" keyPath:@"article" statusCodes:statusCodes]; // articleID 應爲 Article 類的一個屬性.
    [manager addResponseDescriptor: articleDescriptor];
    
    /* 類的路由.配置後,操做某個類時,會自動向這個類對應的地址發送請求. */
    [manager.router.routeSet addRoute:[RKRoute routeWithClass:[Article class] pathPattern:@"/vitural/articles/:articleID\\.json" method:RKRequestMethodGET]];
    
    /*  發起請求. */
    Article * article = [[Article alloc] init];
    article.articleID = @"888"; // articleId 屬性必須給,以拼接地址路由中缺乏的部分.
    
    // 由於配置了路由,因此此處沒必要再傳 path 參數.
    [manager getObject: article path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        // 處理請求成功獲取的文章.
        NSLog(@"Mapped the article: %@", [mappingResult firstObject]);
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        // 處理錯誤信息.
        NSLog(@"%@", error.localizedDescription);
    }];

    
    /* 關係路由: 使用CoreData實體間關係命名的路由.*/
    /* 僅在測試CoreData關係路由時,才須要把下面一段的代碼註釋打開. */
//    RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:@"Category" inManagedObjectStore:manager.managedObjectStore];
//    
//    [categoryMapping addAttributeMappingsFromDictionary:@{ @"id": @"categoryID", @"name": @"name" }];
//    RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:manager.managedObjectStore];
//    [articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
//    [articleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"categories" toKeyPath:@"categories" withMapping:categoryMapping]];
//    
//    NSIndexSet *coreDataStatusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任何 2xx的狀態碼
//    RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:articleID" keyPath:@"article" statusCodes:coreDataStatusCodes];
//    
//    [manager addResponseDescriptor: responseDescriptor];
    
    [manager.router.routeSet addRoute:[RKRoute routeWithRelationshipName:@"categories" objectClass:[Article class] pathPattern:@"/vitural/articles/:articleID\\.json" method:RKRequestMethodGET]];
    
    [manager getObjectsAtPathForRelationship:@"categories" ofObject:article parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        
        // 處理請求成功獲取的文章.
        NSLog(@"Mapped the article: %@", [mappingResult firstObject]);
        
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        
        // 處理錯誤信息.
        NSLog(@"%@", error.localizedDescription);
    }];

    /* 被命名的路由,能夠根據路由名字發起相關請求. */
    [manager.router.routeSet addRoute:[RKRoute routeWithName:@"article_review" pathPattern:@"/vitural/articles/:articleID\\.json" method:RKRequestMethodGET]];
    
    [manager getObjectsAtPathForRouteNamed: @"article_review" object:article parameters: nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        // 處理請求成功獲取的文章.
        NSLog(@"Mapped the article: %@", [mappingResult firstObject]);
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        // 處理錯誤信息.
        NSLog(@"%@", error.localizedDescription);
    }];

POST 新建一個含有文件附件的對象.

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];
    [RKObjectManager setSharedManager: manager];
    
    /* 響應描述,老是必須的. */
    RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
    
    [mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
    
    NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // 任意 2xx 狀態碼.
    
    RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/vitural/articles/:articleID" keyPath:@"article" statusCodes:statusCodes]; // articleID 應爲 Article 類的一個屬性.
    [manager addResponseDescriptor: articleDescriptor];
    
    /* 類的路由.配置後,操做某個類時,會自動向這個類對應的地址發送請求. */
    [manager.router.routeSet addRoute:[RKRoute routeWithClass:[Article class] pathPattern:@"/vitural/articles/:articleID\\.json" method:RKRequestMethodPOST]];
    
    Article *article = [[Article alloc]init];
    article.articleID = @"666";
    
    UIImage *image = [UIImage imageNamed:@"test.jpg"]; // 工程中要確實存在一張名爲 test.jpg 的照片.
    
    // 序列化對象屬性,以添加附件.
    NSMutableURLRequest *request = [[RKObjectManager sharedManager] multipartFormRequestWithObject:article method:RKRequestMethodPOST path:nil parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileData:UIImagePNGRepresentation(image)
                                    name:@"myImg" // 這個字段要和服務器取文件的字段一致.
                                fileName:@"photo.jpg"
                                mimeType:@"image/jpeg"];
    }];
    
    RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:request success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        /* 服務器端接口目前自定義的邏輯是: 成功後,會返回圖片上傳後的服務器地址. */
        NSLog(@"Mapped the article: %@", [mappingResult firstObject]);
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        NSLog(@"%@", error.localizedDescription);
    }];
    
    [[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation]; // 注意:要用enqueued,不要使用 started方法.

以隊列方式批量處理對像請求.

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://dev-test.ios122.com"]];
    
    Article * articleA = [[Article alloc] init];
    articleA.articleID = @"888";
    
    Article * articleB = [[Article alloc] init];
    articleB.articleID = @"1234";
    
    Article * articleC = [[Article alloc] init];
    articleC.articleID = @"555";
    
    /* 以隊列方式,發送多個請求. */
    
    [manager.router.routeSet addRoute:[RKRoute routeWithClass:[Article class] pathPattern:@"/vitural/articles/:articleID\\.json" method:RKRequestMethodGET]];
    
    RKRoute * route = [RKRoute routeWithClass:[Article class] pathPattern:@"/vitural/articles/:articleID\\.json" method:RKRequestMethodPOST];

    [manager enqueueBatchOfObjectRequestOperationsWithRoute:route
                                                    objects:@[articleA, articleB, articleC]
                                                   progress:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
                                                       NSLog(@"完成了 %lu 個操做", (unsigned long)numberOfFinishedOperations);
                                                   } completion:^ (NSArray *operations) {
                                                       NSLog(@"全部的文章都已獲取!");
                                                   }];

製做一個種子數據庫.

能夠將一個JSON文件轉化爲一個數據庫,用於初始化應用.網絡

NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
    NSError *error = nil;
    BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
    if (! success) {
        RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
    }
    
    NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RestKit.sqlite"]; // 此處要和本身的CoreData數據庫的名字一致.

    NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
    if (! persistentStore) {
        RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
    }
    [managedObjectStore createManagedObjectContexts];
    
    RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore];
    [articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
    
    NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MySeedDatabase.sqlite"]; // 這個數據庫文件沒必要存在,用來充當應用的初始數據庫.
    RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectStore.managedObjectModel storePath:seedPath];
    
    //  使用 RKEntityMapping 從工程文件 "articles.json" 導入數據.
    // JSON 相似於: {"articles": [ {"title": "Article 1", "body": "Text", "author": "Blake" ]}

    error = nil;
    
    NSBundle *mainBundle = [NSBundle mainBundle];
    [importer importObjectsFromItemAtPath:[mainBundle pathForResource:@"articles" ofType:@"json"] // 工程中要有這個文件.
                              withMapping:articleMapping
                                  keyPath:@"articles"
                                    error:&error];
    
    success = [importer finishImporting:&error];
    
    if (success) {
        [importer logSeedingInfo];
    }

給實體添加索引並檢索

// 要額外添加頭文件: #import <RestKit/Search.h>

NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSError *error = nil;
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
    RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
}
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
}
[managedObjectStore createManagedObjectContexts];
[managedObjectStore addSearchIndexingToEntityForName:@"Article" onAttributes:@[ @"title", @"body" ]];
[managedObjectStore addInMemoryPersistentStore:nil];
[managedObjectStore createManagedObjectContexts];
[managedObjectStore startIndexingPersistentStoreManagedObjectContext];

Article *article1 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
article1.title = @"First Article";
article1.body = "This should match search";

Article *article2 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
article2.title = @"Second Article";
article2.body = "Does not";

BOOL success = [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:nil];

RKSearchPredicate *predicate = [RKSearchPredicate searchPredicateWithText:@"Match" type:NSAndPredicateType];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
fetchRequest.predicate = predicate;

// Contains article1 due to body text containing 'match'
NSArray *matches = [managedObjectStore.mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:nil];
NSLog(@"Found the matching articles: %@", matches);

對映射進行單元測試

// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}}
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];

NSDictionary *article = @{ @"article": @{ @"title": @"My Title", @"body": @"The article body", @"author": @"Blake" } };
RKMappingTest *mappingTest = [[RKMappingTest alloc] initWithMapping:mapping sourceObject:article destinationObject:nil];

[mappingTest expectMappingFromKeyPath:@"title" toKeyPath:@"title" value:@"My Title"];
[mappingTest performMapping];
[mappingTest verify];
相關文章
相關標籤/搜索