iPhone - Changing a sub-sub-sub NSMutableDictionar

2019-08-01 19:16发布

问题:

If I have a data tree that is something like :

NSMutableDictionary (dict1)
   NSMutableDictionary (dict2)
      NSMutableArray (array)
        NSMutableDictionary (dict3)
           Key1
           Key2

        NSMutableDictionary (dict_n)
           Keyn
           Keyn

   NSMutableDictionary (dict_n)
      NSMutableArray (array_n)
        NSMutableDictionary (dict_n)
           Keyn
           Keyn

        NSMutableDictionary (dict_n)
           Keyn
           Keyn

If I want to change the value of Key1, is there a simplier way than...

getting dict1
then getting dict2
then getting array
then getting dict3

converting dict3 to a mutable Dictionary
then setting key1

Converting array to a mutable array
then setting dict3 into array

converting dict2 to a mutable Dictionary
then setting array into dict2

converting dict1 to a mutable Dictionary
then setting dict2 into dict1

Doing that for each value I have to change is a real headache, and really code consuming.

回答1:

You can't send a message to an object unless you have a pointer to that object, so in a basic sense the answer to your question is no, there's no other way.

However, one presumes that this data structure that you have represents some sort of data model. As such, it should probably be contained in some sort of model class that understands its parts, and that class should be the only one that needs to understand how the data is stored. The model class should offer a higher-level interface to the data. Say dict3 represents one particular vehicle in a fleet, and the keys are things like "vehicleTag", "registrationDate", "purchaseDate", etc. Maybe the dictionaries at the dict2 level the fleets in different regions, and dict2 itself represents the northeast fleet. Then the VehiclePool class, your model class which stores all the data, might offer methods like:

-registrationDateForVehicle:(int)vehicleIndex inFleet:(NSString*)fleetKey;
-setRegistrationDate:(NSDate*)regDate forVehicle:(int)vehicleIndex inFleet:(NSString*)fleetKey;

I'm not sure I'd really want an API like that -- I'd prefer to get the list of vehicles for a given fleet and then operate on those with simpler accessors, but you seem to want to avoid several levels of accessors. The point here is that you shouldn't be writing a ton of code to do the operations you need; you should write methods that know how to access the data and then call those.



回答2:

The NSDictionary documentation states:

In general, a key can be any object (provided that it conforms to the NSCopying protocol—see below), but note that when using key-value coding the key must be a string (see “Key-Value Coding Fundamentals”).

Therefore, if your keys (and sub-keys) are all strings, you can do the following to retrieve and set values:

id myNestedObject = [topLevel valueForKeyPath:@"firstKey.secondKey.thirdKey"];
[topLevel setObject:newNestedObject forKeyPath:@"firstKey.secondKey.thirdKey"];