2016-05-17 1 views
1

J'ai des difficultés à configurer un mappage dynamique pour un tableau de résultats. Les objets de résultat que je souhaite mapper sont incorporés dans un «conteneur» qui décrit le type de l'objet inclus.Mappage dynamique RestKit avec des éléments imbriqués

J'ai JSON similaire à ce qui suit:

"list": { 
    "name": "" 
    "item_infos": [ 
    { 
     "type": "TaskItem", 
     "item": { 
      "id": 0 
      "title": "A Task Item", 
      "task": "..." 
     } 
     "url": "..." 
    }, 
    { 
     "type": "ReminderItem", 
     "item": { 
      "id": 0 
      "title": "A Reminder Item", 
      "reminder": "..." 
     } 
     "url": "..." 
    }] 
} 


J'aimerais mapper cela comme un objet List avec un tableau de Item s, où chaque élément peut être d'un type différent. Les différents type sont finis et connus.

class List: NSManagedObject { 
    @NSManaged var name: String 
    @NSManaged var items: NSOrderedSet 
} 

class Item: NSManagedObject { 
    @NSManaged var identifier: Int32 
    @NSManaged var title: String 

    // Each mappable `Item` is responsible for providing its own 
    // mapping object. It's overridden in the subclasses below. 
    class func responseMappingForManagedObjectStore(dos: RKManagedObjectStore) -> RKEntityMapping { ... } 
} 

class TaskItem: Item { 
    @NSManaged var task: String 
} 

class ReminderItem: Item { 
    @NSManaged var reminder: String 
} 


Comment puis-je mapper le item directement sous encastré la liste à l'aide RKDynamicMapping tout en faisant usage du champ type? J'essaie quelque chose le long de ces lignes pour la cartographie de réponse: une exception est levée

let listMapping = RKEntityMapping(forEntityForName: "List", inManagedObjectStore: store) 
responseMapping.addAttributeMappingsFromDictionary(["name": "title"]) 

let dynamicItemMapping = RKDynamicMapping() 
dynamicItemMapping.setObjectMappingForRepresentationBlock { representation in 

    let itemMapping: RKEntityMapping 

    switch representation.valueForKeyPath("type") as? String { 
    case .Some("TaskItem"):  itemMapping = TaskItem.responseMappingForManagedObjectStore(objectStore) 
    case .Some("ReminderItem"): itemMapping = ReminderItem.responseMappingForManagedObjectStore(objectStore) 
    default:     return nil 

    // This is the bit I'm failing to solve. How can I return a mapping 
    // that essentially "skips" a level of the JSON, and just maps the 
    // embedded `item`, not the `item_info`. 
    let itemInfoMapping = RKObjectMapping(forClass: NSMutableDictionary.self) 
    itemInfoMapping.addRelationshipMappingWithSourceKeyPath("item", mapping: itemMapping) 
    return itemInfoMapping 
} 

listMapping.addPropertyMapping(RKRelationshipMapping(
    fromKeyPath: "item_infos", 
    toKeyPath: "items", 
    withMapping: dynamicItemMapping)) 

Avec cette application,:

-[__NSDictionaryM _isKindOfEntity:]: unrecognized selector sent to instance 0x7fd2603cb400 

Ce qui ne me surprend pas, comme la façon dont la cartographie dynamique est mis en place ne me semble pas juste de toute façon - je suis à la recherche d'un moyen de "sauter" un niveau du JSON et seulement mapper le item intégré.


Une autre tentative a été de préciser pleinement le fromKeyPath comme "item_infos.item" pour la relation avec le listMapping, mais je ne peux pas utiliser le champ type dans le bloc de mappage dynamique pour déterminer le type de Item mapping à utiliser:

// ... 
dynamicItemMapping.setObjectMappingForRepresentationBlock { representation in 
    // `type` inaccessible from the nested item representation 
    switch representation.valueForKeyPath("type") as? String { 
    case .Some("TaskItem"):  return TaskItem.responseMappingForManagedObjectStore(objectStore) 
    case .Some("ReminderItem"): return ReminderItem.responseMappingForManagedObjectStore(objectStore) 
    default:     return nil 
} 

listMapping.addPropertyMapping(RKRelationshipMapping(
    fromKeyPath: "item_infos.item", 
    toKeyPath: "items", 
    withMapping: dynamicItemMapping)) 
+0

Vous n'avez pas dit quel est le problème. Personnellement, je n'aurais pas plusieurs entités différentes, j'en aurais 1 avec un identifiant de type. – Wain

+0

@Wain Désolé, je n'ai pas fait le problème très clair. J'ai mis à jour la question, mais en un mot, les exemples de mappage que j'ai donnés ne fonctionnent pas - le premier déclenche une exception et le second essaie d'effectuer le mappage dynamique basé sur un chemin clé inaccessible depuis le dictionnaire dans le bloc de mappage dynamique (en raison du 'fromKeyPath' du mappage de relation étant un niveau trop profond). Les entités sont simplifiées par souci de clarté/concision dans la question; en réalité, les objets sont suffisamment différents pour justifier d'être des entités distinctes. – Stuart

Répondre

1

Vous ne pouvez pas faire exactement ce que vous essayez de faire, car vous connectez une relation de données de base à un tableau de dictionnaires contenant des objets gérés.

La solution la plus simple consiste à sortir votre logique de saut d'où elle est et à créer tous les mappages pour les objets gérés (tâche et rappel) en ajoutant item. au début de la clé source (chemin). Donc

"item.title" : "title" 
+0

Merci, il est utile de savoir que je me dirigeais sur un chemin qui ne fonctionnerait pas. Je suppose que j'espérais en quelque sorte que les dictionnaires pourraient agir comme une représentation intermédiaire qui permettrait de mapper les éléments dans les données de base. J'espérais également éviter d'avoir à modifier les mappages d'éléments individuels car ils sont bien encapsulés par les classes d'objets, et il existe d'autres routes où ces mappages seraient utilisés sans le préfixe 'item'. Je suppose que je vais m'en remettre et ajouter simplement un paramètre 'sourceKeyPathPrefix' à la méthode qui retourne le mapping. Merci encore pour votre aide! – Stuart

+0

L'approche du dictionnaire ne fonctionnerait que si le mappage de liste n'avait rien à voir avec les données de base, car la relation ne fonctionnerait pas avec l'intermédiaire car ses données non-core dans une relation noyau-date – Wain

+0

Oui, cela a du sens. Merci pour votre aide, je connais la meilleure façon de procéder maintenant. – Stuart