-valueForKey: the method may cause a bug
CoderDHT opened this issue · comments
// .h
@interface WMActivity : JSONModel
@property (nonatomic, copy) NSString *theme;
@property (nonatomic, copy) NSString *content;
@property (nonatomic, strong) NSNumber *getStartDate;
@property (nonatomic, strong) NSNumber *startDate;
@end
// .m
@implementation WMActivity
+ (BOOL)propertyIsOptional:(NSString *)propertyName {
return YES;
}
@end
// using JSONModel
NSDictionary *dict = @{@"getStartDate" : @(1563199999), @"startDate" : @(1563199999)};
WMActivity *model = [[WMActivity alloc] initWithDictionary:dict error:nil];
NSLog(@"startDate == %@, getStartDate == %@", model.startDate, model.getStartDate);
NSLog(@"%@", model);
Analyze
In fact, it's the -valueForKey:
method that causes this result.
Apple notes this method like this:
The default implementation of this method does the following:
- Searches the class of the receiver for an accessor method whose name matches the pattern -get<Key>, -<key>, or -is<Key>, in that order. If such a method is found it is invoked.
Before JSONModel assigns startDate
, it use the [self valueForKey:@"startDate"]
method to determine whether the value to be assigned is equal to it, but it actually takes the value of getStartDate
, so they're equal, and then it doesn't assign startDate
.
The -description
method of the JSONModel also use -valueForKey:
, so the output startDate
is valued.
Solution
// .m
// override and try calling -<key> first
- (id)valueForKey:(NSString *)key {
SEL getter = NSSelectorFromString(key);
if ([self respondsToSelector:getter]) {
IMP imp = [self methodForSelector:getter];
id (*func)(id, SEL) = (void *)imp;
return func(self, getter);
}
return [super valueForKey:key];
}
PS: The problem occurs only if the values of startDate
and getStartDate
are equal and getStartDate
is assigned first, which is a very special case, you decide whether to deal with it or not. :)