RestKit 是一个用于更好支持RESTful风格服务器接口的iOS库,可直接将联网获取的json/xml数据转换为iOS对象.
pod 'RestKit' # 测试和搜索是可选的组件 pod 'RestKit/Testing' pod 'RestKit/Search'
在需要的地方,引入头文件:
/* 如果使用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测试.
/** * 定义数据模型: 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];
// 获取 /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); }];
/* 配置管理器. */ 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); }];
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];