2012-08-09 46 views
5

我正在開發一個應用程序,在其中我想對服務器進行遠程搜索。我想RestKit將檢索到的數據保存到數據庫。我首先執行本地搜索(當前有效),然後我想進行遠程搜索,然後使用新結果更新表視圖。我有兩個問題iOS,使用RestKit進行遠程服務器搜索

,1應該怎麼我的映射看起來和2 json的返回與兩種不同類型的對象的數組。

的URL看起來是這樣的:

search.json?search=[search string] 

它返回的JSON看起來是這樣的:

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

凡事件和新聞是兩種對象。

在我的應用我有三個型號,郵政(抽象的實體和超類)NewsPost(子類來郵)和事件(子類來郵)。

我的映射是這樣的:

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: '' 
} 

如何我應該還是可以做任何提示,將不勝感激。

+0

嗨,我想試試這個問題。 1.你能夠以任何方式更改JSON的格式嗎?我想知道你是否可以爲每個結果添加一個根密鑰路徑(這將大大簡化它)。 2.您正在使用NSManagedObject進行新聞和事件。您是否打算在用戶搜索時將映射保存到Coredata中? – 2012-08-15 10:18:32

+0

嗨,是的,如果需要我可以改變JSON。而且,是的,我想在用戶搜索時在本地緩存並保存結果。 – Anders 2012-08-15 10:44:42

+0

讓我知道答案是否適合你。 – 2012-08-17 06:33:19

回答

3

我沒有使用過管理對象之前,但在這裏做的第一件事是激活restkit日誌在對象映射和網絡的要求,所以你可以檢查什麼是restkit從服務器以及如何映射工作得到。

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

另一種方式做,這是通過對象映射,所以RestKit檢測對象的種類並執行映射,並向任何路徑發出請求。

如果您有任何問題,請留下評論,我可以根據需要改進我的答案。

+0

謝謝,明天我會測試它。 – Anders 2012-08-14 20:58:55

1

我從來沒有嘗試回答一個問題與前一個賞金,讓我試着給從最近的一些工作有用的答案=)

1.我的映射應該怎麼看起來像

從你的代碼,一切看起來都很好。有物體的嵌套嗎?你需要序列化發佈回服務器?

2. JSON返回與兩種不同類型的對象的數組。

是你的屬性相同(即事件有一個標題,事件有一個日期)沒有驚喜?如果不是,則必須使用dynamic nesting

如果資源路徑(即您的搜索路徑)接收到具有不同對象(您的案例)的集合,則必須使用dynamic object mapping加載對象。

由於您可以編輯JSON結構,因此可以通過利用RestKit來簡化操作。

- 確保JSON具有兩種不同類型對象的root_key_path。

從一箇舊的實驗和一些Google搜索,RestKit可以正確地映射一個JSON輸出與不同的對象,如果他們有適當的rootKeyPaths。導致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代表

如果它的工作,對象應該映射到你的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執行本地過濾。你的服務器會讓你心動。

讓我知道,我會盡力進一步改進答案。

+0

感謝您的回答,並對我遲到的回覆感到抱歉。我實際上通過使用@clopez答案並做了一些小的修改。 – Anders 2012-08-20 07:50:35