5

サーバーへのリモート検索を行うアプリに取り組んでいます。取得したデータをRestKitにデータベースに保存してもらいたい。最初にローカル検索 (現在は機能しています) を実行してから、リモート検索を行い、新しい結果でテーブル ビューを更新します。

2 つの問題があります。1. マッピングがどのように見えるか、2. json は 2 つの異なる種類のオブジェクトを含む配列を返します。

URL は次のようになります。

search.json?search=[search string]

返される JSON は次のようになります。

[
  {
    "event": {
      "id": 2,
      [...]
  },
  {
    "news": {
      "id": 16,
      [...]
  }

イベントとニュースは 2 種類のオブジェクトです。

私のアプリには、Post (抽象エンティティとスーパークラス) NewsPost (Post のサブクラス) と Event (Post のサブクラス) の 3 つのモデルがあります。

私のマッピングは次のようになります。

RKManagedObjectMapping* newsMapping = [RKManagedObjectMapping mappingForClass:[NewsPost class] inManagedObjectStore:objectManager.objectStore];   
newsMapping.primaryKeyAttribute = @"newsId";
newsMapping.rootKeyPath = @"news";
[newsMapping mapKeyPath:@"id" toAttribute:@"newsId"];

RKManagedObjectMapping *eventMapping = [RKManagedObjectMapping mappingForClass:[CalendarEvent class] inManagedObjectStore:objectManager.objectStore];
eventMapping.primaryKeyAttribute = @"calendarId";
eventMapping.rootKeyPath = @"calendars";
[eventMapping mapKeyPath:@"id" toAttribute:@"calendarId"];

// These two works. 
[objectManager.mappingProvider setObjectMapping:newsMapping forResourcePathPattern:@"/package_components/1/news"];
[objectManager.mappingProvider setObjectMapping:eventMapping forResourcePathPattern:@"/package_components/1/calendars"];

// I don't know how these should look/work. 
// Since the search word can change
[objectManager.mappingProvider setObjectMapping:eventMapping forResourcePathPattern:@"/package_components/1/search\\.json?search="];
[objectManager.mappingProvider setObjectMapping:newsMapping forResourcePathPattern:@"/package_components/1/search\\.json?search="];

私の検索コードは次のようになります (ローカル検索が機能します)。

- (void)setUpSearch
{
    if (self.searchField.text != nil) {

        [self.posts removeAllObjects];
        [self.events removeAllObjects];
        [self.news removeAllObjects];

        // Search predicates.
        // Performs local search.
        NSPredicate *contactNamePredicate = [NSPredicate predicateWithFormat:@"contactName contains[cd] %@", self.searchField.text];
        NSPredicate *contactDepartmentPredicate = [NSPredicate predicateWithFormat:@"contactDepartment contains[cd] %@", self.searchField.text];
        [...]

        NSArray *predicatesArray = [NSArray arrayWithObjects:contactNamePredicate, contactDepartmentPredicate, contactEmailPredicate, contactPhonePredicate, linkPredicate, titlePredicate, nil];

        NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicatesArray];

        self.posts = [[Post findAllWithPredicate:predicate] mutableCopy];

        if (self.posts.count != 0) {
            self.noResultsLabel.hidden = YES;
            for (int i = 0; i < self.posts.count; i++) {
                Post * post = [self.posts objectAtIndex:i];
                if (post.calendarEvent == YES) {
                    [self.events addObject:post];
                } else {
                    [self.news addObject:post];
                }
            }
        } 

        // reload the table view
        [self.tableView reloadData];

        [self performRemoteSearch];
    }
}

- (void)search
{    
    [self setUpSearch];
    [self hideKeyboard];
    [self performRemoteSearch];
}


- (void)performRemoteSearch
{
    // Should load the objects from JSON    
    // Note that the searchPath can vary depending on search text. 
    NSString *searchPath = [NSString stringWithFormat:@"/package_components/1/search.json?search=%@", self.searchField.text];
    RKObjectManager *objectManager = [RKObjectManager sharedManager];
    [objectManager loadObjectsAtResourcePath:searchPath delegate:self];
}

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects
{
    // This never gets called. 

    // Should update my arrays and then update the tableview, but it never gets called. 
    // Instead I get Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "Could not find an object mapping for keyPath: ''
}

私がどのようにすべきか、またはできるかについてのヒントは大歓迎です。

4

2 に答える 2

3

これまで管理オブジェクトを使用したことはありませんが、ここで最初に行うことは、オブジェクト マッピングとネットワーク リクエストでレストキット ログをアクティブにすることです。これにより、レストキットがサーバーから取得するものと、マッピングがどのように機能しているかを確認できます。

//This can be added in your app delegate
RKLogConfigureByName("RestKit/Network", RKLogLevelDebug);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);

次に、JSON と検索パスの変更によると、リソース パス パターンの代わりにキー パスのマッピングを使用する方が良いと思います。したがって、次の例のように、キーでマップするようにしてください。

RKObjectMapping* articleMapping = [RKObjectMapping mappingForClass:[Article class]];
[articleMapping mapKeyPath:@"title" toAttribute:@"title"];
[articleMapping mapKeyPath:@"body" toAttribute:@"body"];
[articleMapping mapKeyPath:@"author" toAttribute:@"author"];
[articleMapping mapKeyPath:@"publication_date" toAttribute:@"publicationDate"];

[[RKObjectManager sharedManager].mappingProvider setMapping:articleMapping forKeyPath:@"articles"];

そして、次のようにデータをロードします。

- (void)loadArticles {
    [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/articles" delegate:self];
}

これを行うもう 1 つの方法は、オブジェクトごとにマップすることです。そのため、RestKit はオブジェクトの種類を検出してマッピングを実行し、ユーザーは任意のパスにリクエストを送信します。

ご不明な点がございましたら、コメントを残してください。必要に応じて回答を改善できます。

于 2012-08-14T14:04:05.640 に答える
1

これまで賞金で質問に答えようとしたことはありません。最近の仕事から役に立つ答えを出してみましょう =)

1.私のマッピングはどのように見えるべきですか

あなたのコードから、すべてがかなりうまく見えます。オブジェクトのネストはありますか? サーバーにポストバックするためにシリアル化する必要がありますか?

2. json は、2 種類のオブジェクトを含む配列を返します。

あなたの属性は同じですか (つまり、イベントにはタイトルがあり、イベントには日付があります)、驚きはありませんか? そうでない場合は、使用する必要がありますdynamic nesting

リソース パス (つまり、検索パス) が異なるオブジェクト (ケース) を含むコレクションを受け取る場合はdynamic object mapping、オブジェクトをロードするために使用する必要があります。

JSON 構造を編集できるため、RestKit を活用することで作業が簡単になります。

- JSON に 2 つの異なるタイプのオブジェクトの root_key_path があることを確認します。

古い実験といくつかのグーグルから、適切な rootKeyPaths があれば、RestKit は json 出力をさまざまなオブジェクトに適切にマッピングできます。結果の JSON は、次のような大まかな構造を持つ必要があります。

{
  "news" : [
    {
      "id" : 1,
      "title" : "Mohawk guy quits"
    },
    {
      "id" : 2,
      "title" : "Obama gets mohawk"
    }
  ],
  "events" : [
    {
      "id" : 1,
      "name" : "testing"
    },
    {
      "id" : 2,
      "name" : "testing again"
    }
  ]
}

上記が100%正しいとは断言できません。API がニュースのみを返すようにして、それが機能する場合は実験してから、イベント データをミックスに追加します。

- サーバーからオブジェクトをロードする

// Make a NS dictionary and use stringByAppendingQueryParameters

NSDictionary *searchParams = [NSDictionary dictionaryWithKeysAndObjects:
                                @"query",@"myQuery", 
                                @"location",@"1.394168,103.895473",
                                nil];

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[@"/path/to/resource.json"  stringByAppendingQueryParameters:searchParams] delegate:objectLoaderDelegate];

- objectLoader Delegate で「実際の」検索を処理する

うまくいった場合、オブジェクトは Coredata エンティティにマップされているはずです。NSPredicate上記の方法を使用して、ローカル検索を実行できます。

私は、RestKit がloadObjects...サーバーからデータを取得してマップするために使用する設計パターンを好みます。残りの処理はローカルで行われます。この分離により、物事はより「アプリのように」なります。NSPredicates を使用して、他の形式の操作を行うことができます。

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { 
  // Do some processing here on the array of returned objects or cede control to a method that 
  // you've built for the search, like the above method.
}

一例として、検索のユースケースが近くのレストランである場合、現在の緯度/経度内のすべてのレストランをロードし、Coredata を使用して名前によるローカル フィルタリングを実行することはおそらく理にかなっています。あなたのサーバーはあなたを心に留めます。

お知らせください。回答をさらに改善するよう努めます。

于 2012-08-15T11:40:17.623 に答える