简体   繁体   中英

Obj-C setValuesForKeysWithDictionary 64-bit vs 32-bit

I am pulling a JSON object from my API and creating it using the following code (in hindsight not the way to go):

+ (YActivity *)instanceFromDictionary:(NSDictionary *)jsonDictionary
{
    YActivity * instance = [[YActivity alloc] init];
    [instance setAttributesFromDictionary:jsonDictionary];
    return instance;
}

- (void)setAttributesFromDictionary:(NSDictionary *)jsonDictionary
    {
        if (![jsonDictionary isKindOfClass:[NSDictionary class]]) {
            return;
        }

        [self setValuesForKeysWithDictionary:jsonDictionary];
}

One of the keys is "type". I have a read-only variable @synthesized called "type". On the 32-bit version of my app, this is set right away before setValue:(id)value forUndefinedKey:(NSString *)key is called. I reference this value in that method, and on the 64-bit version of my app, when the breakpoint hits this method, type is not set yet.

Clearly this isn't the best course of action. I am just wondering if anyone else as seen this or if I'm barking up the wrong tree. I diffed the files between the two versions and they are identical. I am running them both on iOS 8.1 Simulator, the API is returning the same thing for both...I'm stumped. Basically on the old version defined keys are set before undefined, and on the new version it seems the opposite of that.

NSDictionary objects are unordered collections, so code should never make assumptions about the order in which a dictionary will enumerate its own keys. It turns out that there are implementation differences between the 32- and 64-bit runtimes that affect where hashed values end up being stored.

Since the API contract explicitly doesn't guarantee order, that shouldn't cause problems, but it can (and in this case apparently does ) have the side-effect of causing code that formerly 'worked' to break when compiled for the 64-bit architecture.

A quick way to fix the problem you're currently having without significantly changing the implementation would be to enumerate the dictionary's keys yourself, which would allow you to provide an array of keys ordered however you wish:

- (void)setAttributesFromDictionary:(NSDictionary *)dictionary
{
    // So instead of doing this...
    //
    // [self setValuesForKeysWithDictionary:dictionary];

    // You could do something along these lines:
    //
    NSMutableArray *keys = dictionary.allKeys.mutableCopy;

    // TODO: insert code to change the order of the keys array.
    // Then loop through the keys yourself...

    for (NSString *key in keys)
    {
        [self setValue:dictionary[key] forKey:key];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM