zoukankan      html  css  js  c++  java
  • RestKit ,一个用于更好支持RESTful风格服务器接口的iOS库

    简介

    RestKit 是一个用于更好支持RESTful风格服务器接口的iOS库,可直接将联网获取的json/xml数据转换为iOS对象.

    • 项目主页: RestKit
    • 最新示例: 点击下载
    • 注意: 如果无法直接运行示例根目录的工程,可尝试分别运行 Examples 文件夹下的各个子工程,此时你需要给每个子工程都通过 CocoaPods 安装一次 RestKit.

    快速入门

    使用环境

    • ARC
    • iOS 5.1.1 +

    安装

    通过 CocoaPods 安装

    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];
    

    把网络请求的错误信息映射一个到 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];
    
  • 相关阅读:
    Win(Phone)10开发第(7)弹,Extended Execution
    Win(Phone)10开发第(5)弹,本地媒体服务器的一些注意事项
    Win(Phone)10开发第(4)弹,HTTP 实时流播放 m3u8
    Win(Phone)10开发第(3)弹,简单的Demo程序网络请求json解析列表显示
    Win(Phone)10开发第(2)弹,导出APPX包并签名部署
    Win(Phone)10开发第(1)弹,桌面和手机的扩展API,还我后退键
    WP8里dll类库(SDK)实现多语言多主题
    Windows Phone中解决多模块多程序集之间相互循环引用的问题一种思路
    在继承中子类自动实现单例模式
    ansible---基础
  • 原文地址:https://www.cnblogs.com/ios122/p/4807271.html
Copyright © 2011-2022 走看看