-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCWModel.m
132 lines (103 loc) · 4.25 KB
/
CWModel.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//
// CWModel.m
//
// Created by Clément Wehrung on 01/05/2014.
// Copyright (c) 2014 Clément Wehrung. All rights reserved.
//
#import <objc/runtime.h>
#import "CWCollectionModelProtocol.h"
#import "CWModel.h"
#import "NSDate+JavascriptTimestamp.h"
@implementation CWModel
- (id)initWithIdentifier:(NSString *)identifier
{
if (self = [super init]) {
self.identifier = identifier;
}
return self;
}
/**
* managedProperties defines the list of the automatically synced properties.
* It provides a binding between the local property name and the remote key.
* { local: remote }
*/
- (NSDictionary *)managedProperties
{
return @{};
}
- (BOOL)updateWithDictionary:(NSDictionary *)dictionary
{
if (!(dictionary && [dictionary isKindOfClass:NSDictionary.class])) return NO;
BOOL didChange = NO;
NSDictionary *managedProperties = self.managedProperties;
for (NSString *localPropertyName in managedProperties)
{
NSString *remotePropertyName = managedProperties[localPropertyName];
id remoteValue = dictionary[remotePropertyName];
id currentValue = [self valueForKey:localPropertyName];
if (remoteValue && ![remoteValue isKindOfClass:NSNull.class] && !(currentValue && [currentValue isEqual:remoteValue])) {
Class expectedClass = [self classExpectedByPropertyNamed:localPropertyName];
if (![remoteValue isKindOfClass:expectedClass]) {
// Convert NSNumber => NSDate with assumption that NSNumber represents a JavaScript timestamp
if ([expectedClass isSubclassOfClass:[NSDate class]] && [remoteValue isKindOfClass:[NSNumber class]]) {
remoteValue = [NSDate dateFromJavascriptTimestamp:remoteValue];
}
else if ([expectedClass isSubclassOfClass:[NSString class]]) {
remoteValue = [NSString stringWithFormat:@"%@", remoteValue];
}
}
[self setValue:remoteValue forKey:localPropertyName];
didChange = YES;
}
}
return didChange;
}
- (NSDictionary *)dictionary
{
NSMutableDictionary *export = [NSMutableDictionary dictionary];
NSDictionary *managedProperties = self.managedProperties;
for (NSString *localPropertyName in managedProperties)
{
NSString *remotePropertyName = managedProperties[localPropertyName];
id localValue = [self valueForKey:localPropertyName];
// TODO: should we return NSNull for non-set values ?
if (localValue) {
// Convert NSDate => NSNumber with JavaScript timestamp
if ([localValue isKindOfClass:NSDate.class]) {
localValue = [NSDate javascriptTimestampFromDate:localValue];
}
export[remotePropertyName] = localValue;
}
}
return export;
}
#pragma mark - Properties Handling
- (Class)classExpectedByPropertyNamed:(NSString *)propertyName
{
objc_property_t property = class_getProperty( self.class, [propertyName UTF8String] );
if ( property == NULL ) { return ( NULL ); }
const char * type = property_getAttributes(property);
NSString * typeString = [NSString stringWithUTF8String:type];
NSArray * attributes = [typeString componentsSeparatedByString:@","];
NSString * typeAttribute = [attributes objectAtIndex:0];
NSString * propertyType = [typeAttribute substringFromIndex:1];
const char * rawPropertyType = [propertyType UTF8String];
if (strcmp(rawPropertyType, @encode(float)) == 0) {
//it's a float
} else if (strcmp(rawPropertyType, @encode(int)) == 0) {
//it's an int
} else if (strcmp(rawPropertyType, @encode(id)) == 0) {
//it's some sort of object
} else {
// According to Apples Documentation you can determine the corresponding encoding values
}
if ([typeAttribute hasPrefix:@"T@"]) {
NSString * typeClassName = [typeAttribute substringWithRange:NSMakeRange(3, [typeAttribute length]-4)]; //turns @"NSDate" into NSDate
Class typeClass = NSClassFromString(typeClassName);
if (typeClass != nil) {
return typeClass;
}
}
return nil;
}
@end