暫無描述

ORKESerialization.m 112KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065
  1. /*
  2. Copyright (c) 2015, Apple Inc. All rights reserved.
  3. Copyright (c) 2015-2016, Ricardo Sánchez-Sáez.
  4. Copyright (c) 2018, Brian Ganninger.
  5. Redistribution and use in source and binary forms, with or without modification,
  6. are permitted provided that the following conditions are met:
  7. 1. Redistributions of source code must retain the above copyright notice, this
  8. list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright notice,
  10. this list of conditions and the following disclaimer in the documentation and/or
  11. other materials provided with the distribution.
  12. 3. Neither the name of the copyright holder(s) nor the names of any contributors
  13. may be used to endorse or promote products derived from this software without
  14. specific prior written permission. No license is granted to the trademarks of
  15. the copyright holders even if such marks are included in this software.
  16. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  20. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #import "ORKESerialization.h"
  28. @import ResearchKit;
  29. @import ResearchKit.Private;
  30. @import MapKit;
  31. static NSString *ORKEStringFromDateISO8601(NSDate *date) {
  32. static NSDateFormatter *formatter = nil;
  33. static dispatch_once_t onceToken;
  34. dispatch_once(&onceToken, ^{
  35. formatter = [[NSDateFormatter alloc] init];
  36. [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];
  37. [formatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
  38. });
  39. return [formatter stringFromDate:date];
  40. }
  41. static NSDate *ORKEDateFromStringISO8601(NSString *string) {
  42. static NSDateFormatter *formatter = nil;
  43. static dispatch_once_t onceToken;
  44. dispatch_once(&onceToken, ^{
  45. formatter = [[NSDateFormatter alloc] init];
  46. [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];
  47. [formatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
  48. });
  49. return [formatter dateFromString:string];
  50. }
  51. static NSArray *ORKNumericAnswerStyleTable() {
  52. static NSArray *table = nil;
  53. static dispatch_once_t onceToken;
  54. dispatch_once(&onceToken, ^{
  55. table = @[@"decimal", @"integer"];
  56. });
  57. return table;
  58. }
  59. static NSArray *ORKImageChoiceAnswerStyleTable() {
  60. static NSArray *table = nil;
  61. static dispatch_once_t onceToken;
  62. dispatch_once(&onceToken, ^{
  63. table = @[@"singleChoice", @"multipleChoice"];
  64. });
  65. return table;
  66. }
  67. static NSArray *ORKMeasurementSystemTable() {
  68. static NSArray *table = nil;
  69. static dispatch_once_t onceToken;
  70. dispatch_once(&onceToken, ^{
  71. table = @[@"local", @"metric", @"USC"];
  72. });
  73. return table;
  74. }
  75. static id tableMapForward(NSInteger index, NSArray *table) {
  76. return table[(NSUInteger)index];
  77. }
  78. static NSInteger tableMapReverse(id value, NSArray *table) {
  79. NSUInteger idx = [table indexOfObject:value];
  80. if (idx == NSNotFound)
  81. {
  82. idx = 0;
  83. }
  84. return (NSInteger)idx;
  85. }
  86. static NSDictionary *dictionaryFromCGPoint(CGPoint p) {
  87. return @{ @"x": @(p.x), @"y": @(p.y) };
  88. }
  89. static NSDictionary *dictionaryFromCGSize(CGSize s) {
  90. return @{ @"h": @(s.height), @"w": @(s.width) };
  91. }
  92. static NSDictionary *dictionaryFromCGRect(CGRect r) {
  93. return @{ @"origin": dictionaryFromCGPoint(r.origin), @"size": dictionaryFromCGSize(r.size) };
  94. }
  95. static NSDictionary *dictionaryFromUIEdgeInsets(UIEdgeInsets i) {
  96. return @{ @"top": @(i.top), @"left": @(i.left), @"bottom": @(i.bottom), @"right": @(i.right) };
  97. }
  98. static CGSize sizeFromDictionary(NSDictionary *dict) {
  99. return (CGSize){.width = ((NSNumber *)dict[@"w"]).doubleValue, .height = ((NSNumber *)dict[@"h"]).doubleValue };
  100. }
  101. static CGPoint pointFromDictionary(NSDictionary *dict) {
  102. return (CGPoint){.x = ((NSNumber *)dict[@"x"]).doubleValue, .y = ((NSNumber *)dict[@"y"]).doubleValue};
  103. }
  104. static CGRect rectFromDictionary(NSDictionary *dict) {
  105. return (CGRect){.origin = pointFromDictionary(dict[@"origin"]), .size = sizeFromDictionary(dict[@"size"])};
  106. }
  107. static UIEdgeInsets edgeInsetsFromDictionary(NSDictionary *dict) {
  108. return (UIEdgeInsets){.top = ((NSNumber *)dict[@"top"]).doubleValue, .left = ((NSNumber *)dict[@"left"]).doubleValue, .bottom = ((NSNumber *)dict[@"bottom"]).doubleValue, .right = ((NSNumber *)dict[@"right"]).doubleValue};
  109. }
  110. static NSDictionary *dictionaryFromCoordinate (CLLocationCoordinate2D coordinate) {
  111. return @{ @"latitude": @(coordinate.latitude), @"longitude": @(coordinate.longitude) };
  112. }
  113. static CLLocationCoordinate2D coordinateFromDictionary(NSDictionary *dict) {
  114. return (CLLocationCoordinate2D){.latitude = ((NSNumber *)dict[@"latitude"]).doubleValue, .longitude = ((NSNumber *)dict[@"longitude"]).doubleValue };
  115. }
  116. static ORKNumericAnswerStyle ORKNumericAnswerStyleFromString(NSString *s) {
  117. return tableMapReverse(s, ORKNumericAnswerStyleTable());
  118. }
  119. static NSString *ORKNumericAnswerStyleToString(ORKNumericAnswerStyle style) {
  120. return tableMapForward(style, ORKNumericAnswerStyleTable());
  121. }
  122. static ORKNumericAnswerStyle ORKImageChoiceAnswerStyleFromString(NSString *s) {
  123. return tableMapReverse(s, ORKImageChoiceAnswerStyleTable());
  124. }
  125. static NSString *ORKImageChoiceAnswerStyleToString(ORKNumericAnswerStyle style) {
  126. return tableMapForward(style, ORKImageChoiceAnswerStyleTable());
  127. }
  128. static ORKMeasurementSystem ORKMeasurementSystemFromString(NSString *s) {
  129. return tableMapReverse(s, ORKMeasurementSystemTable());
  130. }
  131. static NSString *ORKMeasurementSystemToString(ORKMeasurementSystem measurementSystem) {
  132. return tableMapForward(measurementSystem, ORKMeasurementSystemTable());
  133. }
  134. static NSDictionary *dictionaryFromCircularRegion(CLCircularRegion *region) {
  135. NSDictionary *dictionary = region ?
  136. @{
  137. @"coordinate": dictionaryFromCoordinate(region.center),
  138. @"radius": @(region.radius),
  139. @"identifier": region.identifier
  140. } :
  141. @{};
  142. return dictionary;
  143. }
  144. //static NSDictionary *dictionaryFromPostalAddress(CNPostalAddress *address) {
  145. // return @{ @"city": address.city, @"street": address.street };
  146. //}
  147. static NSString *identifierFromClinicalType(HKClinicalType *type) {
  148. return type.identifier;
  149. }
  150. static CLCircularRegion *circularRegionFromDictionary(NSDictionary *dict) {
  151. CLCircularRegion *circularRegion;
  152. if (dict.count == 3) {
  153. circularRegion = [[CLCircularRegion alloc] initWithCenter:coordinateFromDictionary(dict[@"coordinate"])
  154. radius:((NSNumber *)dict[@"radius"]).doubleValue
  155. identifier:dict[@"identifier"]];
  156. }
  157. return circularRegion;
  158. }
  159. static NSArray *arrayFromRegularExpressionOptions(NSRegularExpressionOptions regularExpressionOptions) {
  160. NSMutableArray *optionsArray = [NSMutableArray new];
  161. if (regularExpressionOptions & NSRegularExpressionCaseInsensitive) {
  162. [optionsArray addObject:@"NSRegularExpressionCaseInsensitive"];
  163. }
  164. if (regularExpressionOptions & NSRegularExpressionAllowCommentsAndWhitespace) {
  165. [optionsArray addObject:@"NSRegularExpressionAllowCommentsAndWhitespace"];
  166. }
  167. if (regularExpressionOptions & NSRegularExpressionIgnoreMetacharacters) {
  168. [optionsArray addObject:@"NSRegularExpressionIgnoreMetacharacters"];
  169. }
  170. if (regularExpressionOptions & NSRegularExpressionDotMatchesLineSeparators) {
  171. [optionsArray addObject:@"NSRegularExpressionDotMatchesLineSeparators"];
  172. }
  173. if (regularExpressionOptions & NSRegularExpressionAnchorsMatchLines) {
  174. [optionsArray addObject:@"NSRegularExpressionAnchorsMatchLines"];
  175. }
  176. if (regularExpressionOptions & NSRegularExpressionUseUnixLineSeparators) {
  177. [optionsArray addObject:@"NSRegularExpressionUseUnixLineSeparators"];
  178. }
  179. if (regularExpressionOptions & NSRegularExpressionUseUnicodeWordBoundaries) {
  180. [optionsArray addObject:@"NSRegularExpressionUseUnicodeWordBoundaries"];
  181. }
  182. return [optionsArray copy];
  183. }
  184. static NSRegularExpressionOptions regularExpressionOptionsFromArray(NSArray *array) {
  185. NSRegularExpressionOptions regularExpressionOptions = 0;
  186. for (NSString *optionString in array) {
  187. if ([optionString isEqualToString:@"NSRegularExpressionCaseInsensitive"]) {
  188. regularExpressionOptions |= NSRegularExpressionCaseInsensitive;
  189. }
  190. else if ([optionString isEqualToString:@"NSRegularExpressionAllowCommentsAndWhitespace"]) {
  191. regularExpressionOptions |= NSRegularExpressionAllowCommentsAndWhitespace;
  192. }
  193. else if ([optionString isEqualToString:@"NSRegularExpressionIgnoreMetacharacters"]) {
  194. regularExpressionOptions |= NSRegularExpressionIgnoreMetacharacters;
  195. }
  196. else if ([optionString isEqualToString:@"NSRegularExpressionDotMatchesLineSeparators"]) {
  197. regularExpressionOptions |= NSRegularExpressionDotMatchesLineSeparators;
  198. }
  199. else if ([optionString isEqualToString:@"NSRegularExpressionAnchorsMatchLines"]) {
  200. regularExpressionOptions |= NSRegularExpressionAnchorsMatchLines;
  201. }
  202. else if ([optionString isEqualToString:@"NSRegularExpressionUseUnixLineSeparators"]) {
  203. regularExpressionOptions |= NSRegularExpressionUseUnixLineSeparators;
  204. }
  205. else if ([optionString isEqualToString:@"NSRegularExpressionUseUnicodeWordBoundaries"]) {
  206. regularExpressionOptions |= NSRegularExpressionUseUnicodeWordBoundaries;
  207. }
  208. }
  209. return regularExpressionOptions;
  210. }
  211. static NSDictionary *dictionaryFromRegularExpression(NSRegularExpression *regularExpression) {
  212. NSDictionary *dictionary = regularExpression ?
  213. @{
  214. @"pattern": regularExpression.pattern ?: @"",
  215. @"options": arrayFromRegularExpressionOptions(regularExpression.options)
  216. } :
  217. @{};
  218. return dictionary;
  219. }
  220. static NSRegularExpression *regularExpressionsFromDictionary(NSDictionary *dict) {
  221. NSRegularExpression *regularExpression;
  222. if (dict.count == 2) {
  223. regularExpression = [NSRegularExpression regularExpressionWithPattern:dict[@"pattern"]
  224. options:regularExpressionOptionsFromArray(dict[@"options"])
  225. error:nil];
  226. }
  227. return regularExpression;
  228. }
  229. static NSDictionary *dictionaryFromPasswordRules(UITextInputPasswordRules *passwordRules) {
  230. NSDictionary *dictionary = passwordRules ?
  231. @{
  232. @"rules": passwordRules.passwordRulesDescriptor ?: @""
  233. } :
  234. @{};
  235. return dictionary;
  236. }
  237. static UITextInputPasswordRules *passwordRulesFromDictionary(NSDictionary *dict) {
  238. UITextInputPasswordRules *passwordRules;
  239. if (dict.count == 1) {
  240. passwordRules = [UITextInputPasswordRules passwordRulesWithDescriptor:dict[@"rules"]];
  241. }
  242. return passwordRules;
  243. }
  244. //static CNPostalAddress *postalAddressFromDictionary(NSDictionary *dict) {
  245. // CNPostalAddress *postalAddress = [[CNPostalAddress alloc] init];
  246. // postalAddress.city = dict[@"city"];
  247. // postalAddress.street = dict[@"street"];
  248. // return [postalAddress copy];
  249. //}
  250. static HKClinicalType *typeFromIdentifier(NSString *identifier) {
  251. return [HKClinicalType clinicalTypeForIdentifier:identifier];
  252. }
  253. static NSMutableDictionary *ORKESerializationEncodingTable(void);
  254. static id propFromDict(NSDictionary *dict, NSString *propName, ORKESerializationLocalizer *localizer);
  255. static NSArray *classEncodingsForClass(Class c) ;
  256. static id objectForJsonObject(id input, Class expectedClass, ORKESerializationJSONToObjectBlock converterBlock, ORKESerializationLocalizer *localizer) ;
  257. __unused static NSInteger const SerializationVersion = 1; // Will be used moving forward as we get additional versions
  258. #define ESTRINGIFY2( x) #x
  259. #define ESTRINGIFY(x) ESTRINGIFY2(x)
  260. #define ENTRY(entryName, bb, props) @ESTRINGIFY(entryName) : [[ORKESerializableTableEntry alloc] initWithClass:[entryName class] initBlock:bb properties: props]
  261. #define PROPERTY(x, vc, cc, ww, jb, ob) @ESTRINGIFY(x) : ([[ORKESerializableProperty alloc] initWithPropertyName:@ESTRINGIFY(x) valueClass:[vc class] containerClass:[cc class] writeAfterInit:ww objectToJSONBlock:jb jsonToObjectBlock:ob ])
  262. #define DYNAMICCAST(x, c) ((c *) ([x isKindOfClass:[c class]] ? x : nil))
  263. @interface ORKESerializableTableEntry : NSObject
  264. - (instancetype)initWithClass:(Class)class
  265. initBlock:(ORKESerializationInitBlock)initBlock
  266. properties:(NSDictionary *)properties;
  267. @property (nonatomic) Class class;
  268. @property (nonatomic, copy) ORKESerializationInitBlock initBlock;
  269. @property (nonatomic, strong) NSMutableDictionary *properties;
  270. @end
  271. @interface ORKESerializableProperty : NSObject
  272. - (instancetype)initWithPropertyName:(NSString *)propertyName
  273. valueClass:(Class)valueClass
  274. containerClass:(Class)containerClass
  275. writeAfterInit:(BOOL)writeAfterInit
  276. objectToJSONBlock:(ORKESerializationObjectToJSONBlock)objectToJSON
  277. jsonToObjectBlock:(ORKESerializationJSONToObjectBlock)jsonToObjectBlock;
  278. @property (nonatomic, copy) NSString *propertyName;
  279. @property (nonatomic) Class valueClass;
  280. @property (nonatomic) Class containerClass;
  281. @property (nonatomic) BOOL writeAfterInit;
  282. @property (nonatomic, copy) ORKESerializationObjectToJSONBlock objectToJSONBlock;
  283. @property (nonatomic, copy) ORKESerializationJSONToObjectBlock jsonToObjectBlock;
  284. @end
  285. @implementation ORKESerializableTableEntry
  286. - (instancetype)initWithClass:(Class)class
  287. initBlock:(ORKESerializationInitBlock)initBlock
  288. properties:(NSDictionary *)properties {
  289. self = [super init];
  290. if (self) {
  291. _class = class;
  292. self.initBlock = initBlock;
  293. self.properties = [properties mutableCopy];
  294. }
  295. return self;
  296. }
  297. @end
  298. @implementation ORKESerializableProperty
  299. - (instancetype)initWithPropertyName:(NSString *)propertyName
  300. valueClass:(Class)valueClass
  301. containerClass:(Class)containerClass
  302. writeAfterInit:(BOOL)writeAfterInit
  303. objectToJSONBlock:(ORKESerializationObjectToJSONBlock)objectToJSON
  304. jsonToObjectBlock:(ORKESerializationJSONToObjectBlock)jsonToObjectBlock {
  305. self = [super init];
  306. if (self) {
  307. self.propertyName = propertyName;
  308. self.valueClass = valueClass;
  309. self.containerClass = containerClass;
  310. self.writeAfterInit = writeAfterInit;
  311. self.objectToJSONBlock = objectToJSON;
  312. self.jsonToObjectBlock = jsonToObjectBlock;
  313. }
  314. return self;
  315. }
  316. @end
  317. static NSString *_ClassKey = @"_class";
  318. static id propFromDict(NSDictionary *dict, NSString *propName, ORKESerializationLocalizer *localizer) {
  319. NSArray *classEncodings = classEncodingsForClass(NSClassFromString(dict[_ClassKey]));
  320. ORKESerializableProperty *propertyEntry = nil;
  321. for (ORKESerializableTableEntry *classEncoding in classEncodings) {
  322. NSDictionary *propertyEncoding = classEncoding.properties;
  323. propertyEntry = propertyEncoding[propName];
  324. if (propertyEntry != nil) {
  325. break;
  326. }
  327. }
  328. NSCAssert(propertyEntry != nil, @"Unexpected property %@ for class %@", propName, dict[_ClassKey]);
  329. Class containerClass = propertyEntry.containerClass;
  330. Class propertyClass = propertyEntry.valueClass;
  331. ORKESerializationJSONToObjectBlock converterBlock = propertyEntry.jsonToObjectBlock;
  332. id input = dict[propName];
  333. id output = nil;
  334. if (input != nil) {
  335. if ([containerClass isSubclassOfClass:[NSArray class]]) {
  336. NSMutableArray *outputArray = [NSMutableArray array];
  337. for (id value in DYNAMICCAST(input, NSArray)) {
  338. id convertedValue = objectForJsonObject(value, propertyClass, converterBlock, localizer);
  339. NSCAssert(convertedValue != nil, @"Could not convert to object of class %@", propertyClass);
  340. [outputArray addObject:convertedValue];
  341. }
  342. output = outputArray;
  343. } else if ([containerClass isSubclassOfClass:[NSDictionary class]]) {
  344. NSMutableDictionary *outputDictionary = [NSMutableDictionary dictionary];
  345. for (NSString *key in [DYNAMICCAST(input, NSDictionary) allKeys]) {
  346. id convertedValue = objectForJsonObject(DYNAMICCAST(input, NSDictionary)[key], propertyClass, converterBlock, nil);
  347. NSCAssert(convertedValue != nil, @"Could not convert to object of class %@", propertyClass);
  348. outputDictionary[key] = convertedValue;
  349. }
  350. output = outputDictionary;
  351. } else {
  352. NSCAssert(containerClass == [NSObject class], @"Unexpected container class %@", containerClass);
  353. output = objectForJsonObject(input, propertyClass, converterBlock, localizer);
  354. }
  355. }
  356. return output;
  357. }
  358. @implementation ORKESerializationLocalizer
  359. - (instancetype)initWithBundle:(NSBundle *)bundle tableName:(NSString *)tableName {
  360. self = [super init];
  361. if (self) {
  362. self.bundle = bundle;
  363. self.tableName = tableName;
  364. }
  365. return self;
  366. }
  367. @end
  368. #define NUMTOSTRINGBLOCK(table) ^id(id num) { return table[((NSNumber *)num).unsignedIntegerValue]; }
  369. #define STRINGTONUMBLOCK(table) ^id(id string) { NSUInteger index = [table indexOfObject:string]; \
  370. NSCAssert(index != NSNotFound, @"Expected valid entry from table %@", table); \
  371. return @(index); \
  372. }
  373. @implementation ORKESerializer
  374. static NSArray *ORKChoiceAnswerStyleTable() {
  375. static NSArray *table;
  376. static dispatch_once_t onceToken;
  377. dispatch_once(&onceToken, ^{
  378. table = @[@"singleChoice", @"multipleChoice"];
  379. });
  380. return table;
  381. }
  382. static NSArray *ORKDateAnswerStyleTable() {
  383. static NSArray *table = nil;
  384. static dispatch_once_t onceToken;
  385. dispatch_once(&onceToken, ^{
  386. table = @[@"dateTime", @"date"];
  387. });
  388. return table;
  389. }
  390. static NSArray *buttonIdentifierTable() {
  391. static NSArray *table = nil;
  392. static dispatch_once_t onceToken;
  393. dispatch_once(&onceToken, ^{
  394. table = @[@"none", @"left", @"right"];
  395. });
  396. return table;
  397. }
  398. static NSArray *memoryGameStatusTable() {
  399. static NSArray *table = nil;
  400. static dispatch_once_t onceToken;
  401. dispatch_once(&onceToken, ^{
  402. table = @[@"unknown", @"success", @"failure", @"timeout"];
  403. });
  404. return table;
  405. }
  406. static NSArray *numberFormattingStyleTable() {
  407. static NSArray *table = nil;
  408. static dispatch_once_t onceToken;
  409. dispatch_once(&onceToken, ^{
  410. table = @[@"default", @"percent"];
  411. });
  412. return table;
  413. }
  414. #define GETPROP(d,x) getter(d, @ESTRINGIFY(x))
  415. static NSMutableDictionary *ORKESerializationEncodingTable() {
  416. static dispatch_once_t onceToken;
  417. static NSMutableDictionary *internalEncodingTable = nil;
  418. dispatch_once(&onceToken, ^{
  419. internalEncodingTable =
  420. [@{
  421. ENTRY(ORKResultSelector,
  422. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  423. ORKResultSelector *selector = [[ORKResultSelector alloc] initWithTaskIdentifier:GETPROP(dict, taskIdentifier)
  424. stepIdentifier:GETPROP(dict, stepIdentifier)
  425. resultIdentifier:GETPROP(dict, resultIdentifier)];
  426. return selector;
  427. },(@{
  428. PROPERTY(taskIdentifier, NSString, NSObject, YES, nil, nil),
  429. PROPERTY(stepIdentifier, NSString, NSObject, YES, nil, nil),
  430. PROPERTY(resultIdentifier, NSString, NSObject, YES, nil, nil),
  431. })),
  432. ENTRY(ORKPredicateStepNavigationRule,
  433. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  434. ORKPredicateStepNavigationRule *rule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:GETPROP(dict, resultPredicates)
  435. destinationStepIdentifiers:GETPROP(dict, destinationStepIdentifiers)
  436. defaultStepIdentifier:GETPROP(dict, defaultStepIdentifier)
  437. validateArrays:NO];
  438. return rule;
  439. },(@{
  440. PROPERTY(resultPredicates, NSPredicate, NSArray, NO, nil, nil),
  441. PROPERTY(destinationStepIdentifiers, NSString, NSArray, NO, nil, nil),
  442. PROPERTY(defaultStepIdentifier, NSString, NSObject, NO, nil, nil),
  443. PROPERTY(additionalTaskResults, ORKTaskResult, NSArray, YES, nil, nil)
  444. })),
  445. ENTRY(ORKDirectStepNavigationRule,
  446. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  447. ORKDirectStepNavigationRule *rule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:GETPROP(dict, destinationStepIdentifier)];
  448. return rule;
  449. },(@{
  450. PROPERTY(destinationStepIdentifier, NSString, NSObject, NO, nil, nil),
  451. })),
  452. ENTRY(ORKAudioLevelNavigationRule,
  453. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  454. ORKAudioLevelNavigationRule *rule = [[ORKAudioLevelNavigationRule alloc] initWithAudioLevelStepIdentifier:GETPROP(dict, audioLevelStepIdentifier) destinationStepIdentifier:GETPROP(dict, destinationStepIdentifier)
  455. recordingSettings:GETPROP(dict, recordingSettings)];
  456. return rule;
  457. },(@{
  458. PROPERTY(audioLevelStepIdentifier, NSString, NSObject, NO, nil, nil),
  459. PROPERTY(destinationStepIdentifier, NSString, NSObject, NO, nil, nil),
  460. PROPERTY(recordingSettings, NSDictionary, NSObject, NO, nil, nil),
  461. })),
  462. ENTRY(ORKOrderedTask,
  463. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  464. ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:GETPROP(dict, identifier)
  465. steps:GETPROP(dict, steps)];
  466. return task;
  467. },(@{
  468. PROPERTY(identifier, NSString, NSObject, NO, nil, nil),
  469. PROPERTY(steps, ORKStep, NSArray, NO, nil, nil)
  470. })),
  471. ENTRY(ORKNavigableOrderedTask,
  472. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  473. ORKNavigableOrderedTask *task = [[ORKNavigableOrderedTask alloc] initWithIdentifier:GETPROP(dict, identifier)
  474. steps:GETPROP(dict, steps)];
  475. return task;
  476. },(@{
  477. PROPERTY(stepNavigationRules, ORKStepNavigationRule, NSMutableDictionary, YES, nil, nil),
  478. PROPERTY(skipStepNavigationRules, ORKSkipStepNavigationRule, NSMutableDictionary, YES, nil, nil),
  479. PROPERTY(stepModifiers, ORKStepModifier, NSMutableDictionary, YES, nil, nil),
  480. PROPERTY(shouldReportProgress, NSNumber, NSObject, YES, nil, nil),
  481. })),
  482. ENTRY(ORKStep,
  483. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  484. ORKStep *step = [[ORKStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  485. return step;
  486. },
  487. (@{
  488. PROPERTY(identifier, NSString, NSObject, NO, nil, nil),
  489. PROPERTY(optional, NSNumber, NSObject, YES, nil, nil),
  490. PROPERTY(title, NSString, NSObject, YES, nil, nil),
  491. PROPERTY(text, NSString, NSObject, YES, nil, nil),
  492. PROPERTY(shouldTintImages, NSNumber, NSObject, YES, nil, nil),
  493. PROPERTY(useSurveyMode, NSNumber, NSObject, YES, nil, nil)
  494. })),
  495. ENTRY(ORKReviewStep,
  496. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  497. ORKReviewStep *reviewStep = [ORKReviewStep standaloneReviewStepWithIdentifier:GETPROP(dict, identifier)
  498. steps:GETPROP(dict, steps)
  499. resultSource:GETPROP(dict, resultSource)];
  500. return reviewStep;
  501. },
  502. (@{
  503. PROPERTY(steps, ORKStep, NSArray, NO, nil, nil),
  504. PROPERTY(resultSource, ORKTaskResult, NSObject, NO, nil, nil),
  505. PROPERTY(excludeInstructionSteps, NSNumber, NSObject, YES, nil, nil)
  506. })),
  507. ENTRY(ORKVisualConsentStep,
  508. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  509. return [[ORKVisualConsentStep alloc] initWithIdentifier:GETPROP(dict, identifier)
  510. document:GETPROP(dict, consentDocument)];
  511. },
  512. @{
  513. PROPERTY(consentDocument, ORKConsentDocument, NSObject, NO, nil, nil)
  514. }),
  515. ENTRY(ORKPDFViewerStep,
  516. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  517. return [[ORKPDFViewerStep alloc] initWithIdentifier:GETPROP(dict, identifier)
  518. pdfURL:GETPROP(dict, pdfURL)];
  519. },
  520. (@{
  521. PROPERTY(pdfURL, NSURL, NSObject, YES,
  522. ^id(id url) { return [(NSURL *)url absoluteString]; },
  523. ^id(id string) { return [NSURL URLWithString:string]; }),
  524. PROPERTY(actionBarOption, NSNumber, NSObject, YES, nil, nil)
  525. })),
  526. ENTRY(ORKPasscodeStep,
  527. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  528. return [[ORKPasscodeStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  529. },
  530. (@{
  531. PROPERTY(passcodeType, NSNumber, NSObject, YES, nil, nil),
  532. PROPERTY(passcodeFlow, NSNumber, NSObject, YES, nil, nil)
  533. })),
  534. ENTRY(ORKWaitStep,
  535. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  536. return [[ORKWaitStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  537. },
  538. (@{
  539. PROPERTY(indicatorType, NSNumber, NSObject, YES, nil, nil)
  540. })),
  541. ENTRY(ORKRecorderConfiguration,
  542. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  543. ORKRecorderConfiguration *recorderConfiguration = [[ORKRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict, identifier)];
  544. return recorderConfiguration;
  545. },
  546. (@{
  547. PROPERTY(identifier, NSString, NSObject, NO, nil, nil),
  548. })),
  549. ENTRY(ORKQuestionStep,
  550. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  551. return [[ORKQuestionStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  552. },
  553. (@{
  554. PROPERTY(answerFormat, ORKAnswerFormat, NSObject, YES, nil, nil),
  555. PROPERTY(placeholder, NSString, NSObject, YES, nil, nil),
  556. PROPERTY(question, NSString, NSObject, YES, nil, nil),
  557. PROPERTY(useCardView, NSNumber, NSObject, YES, nil, nil)
  558. })),
  559. ENTRY(ORKInstructionStep,
  560. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  561. return [[ORKInstructionStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  562. },
  563. (@{
  564. PROPERTY(detailText, NSString, NSObject, YES, nil, nil),
  565. PROPERTY(footnote, NSString, NSObject, YES, nil, nil)
  566. })),
  567. ENTRY(ORKVideoInstructionStep,
  568. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  569. return [[ORKVideoInstructionStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  570. },
  571. (@{
  572. PROPERTY(videoURL, NSURL, NSObject, YES,
  573. ^id(id url) { return [(NSURL *)url absoluteString]; },
  574. ^id(id string) { return [NSURL URLWithString:string]; }),
  575. PROPERTY(thumbnailTime, NSNumber, NSObject, YES, nil, nil),
  576. })),
  577. ENTRY(ORKCompletionStep,
  578. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  579. return [[ORKCompletionStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  580. },
  581. (@{
  582. })),
  583. ENTRY(ORKCountdownStep,
  584. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  585. return [[ORKCountdownStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  586. },
  587. (@{
  588. })),
  589. ENTRY(ORKTouchAnywhereStep,
  590. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  591. return [[ORKTouchAnywhereStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  592. },
  593. (@{
  594. })),
  595. ENTRY(ORKWebViewStep,
  596. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  597. ORKWebViewStep *step = [[ORKWebViewStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  598. return step;
  599. },
  600. (@{
  601. PROPERTY(html, NSString, NSObject, YES, nil, nil),
  602. })),
  603. ENTRY(ORKWebViewStepResult,
  604. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  605. ORKWebViewStepResult *result = [[ORKWebViewStepResult alloc] initWithIdentifier:GETPROP(dict, identifier)];
  606. return result;
  607. },
  608. (@{
  609. PROPERTY(result, NSString, NSObject, YES, nil, nil),
  610. })),
  611. ENTRY(ORKHealthQuantityTypeRecorderConfiguration,
  612. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  613. return [[ORKHealthQuantityTypeRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict, identifier) healthQuantityType:GETPROP(dict, quantityType) unit:GETPROP(dict, unit)];
  614. },
  615. (@{
  616. PROPERTY(quantityType, HKQuantityType, NSObject, NO,
  617. ^id(id type) { return [(HKQuantityType *)type identifier]; },
  618. ^id(id string) { return [HKQuantityType quantityTypeForIdentifier:string]; }),
  619. PROPERTY(unit, HKUnit, NSObject, NO,
  620. ^id(id unit) { return [(HKUnit *)unit unitString]; },
  621. ^id(id string) { return [HKUnit unitFromString:string]; }),
  622. })),
  623. ENTRY(ORKActiveStep,
  624. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  625. return [[ORKActiveStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  626. },
  627. (@{
  628. PROPERTY(stepDuration, NSNumber, NSObject, YES, nil, nil),
  629. PROPERTY(shouldShowDefaultTimer, NSNumber, NSObject, YES, nil, nil),
  630. PROPERTY(shouldSpeakCountDown, NSNumber, NSObject, YES, nil, nil),
  631. PROPERTY(shouldSpeakRemainingTimeAtHalfway, NSNumber, NSObject, YES, nil, nil),
  632. PROPERTY(shouldStartTimerAutomatically, NSNumber, NSObject, YES, nil, nil),
  633. PROPERTY(shouldPlaySoundOnStart, NSNumber, NSObject, YES, nil, nil),
  634. PROPERTY(shouldPlaySoundOnFinish, NSNumber, NSObject, YES, nil, nil),
  635. PROPERTY(shouldVibrateOnStart, NSNumber, NSObject, YES, nil, nil),
  636. PROPERTY(shouldVibrateOnFinish, NSNumber, NSObject, YES, nil, nil),
  637. PROPERTY(shouldUseNextAsSkipButton, NSNumber, NSObject, YES, nil, nil),
  638. PROPERTY(shouldContinueOnFinish, NSNumber, NSObject, YES, nil, nil),
  639. PROPERTY(spokenInstruction, NSString, NSObject, YES, nil, nil),
  640. PROPERTY(finishedSpokenInstruction, NSString, NSObject, YES, nil, nil),
  641. PROPERTY(recorderConfigurations, ORKRecorderConfiguration, NSArray, YES, nil, nil),
  642. })),
  643. ENTRY(ORKAudioStep,
  644. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  645. return [[ORKAudioStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  646. },
  647. (@{
  648. })),
  649. ENTRY(ORKToneAudiometryStep,
  650. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  651. return [[ORKToneAudiometryStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  652. },
  653. ((@{
  654. PROPERTY(toneDuration, NSNumber, NSObject, YES, nil, nil),
  655. PROPERTY(practiceStep, NSNumber, NSObject, YES, nil, nil),
  656. }))),
  657. ENTRY(ORKdBHLToneAudiometryStep,
  658. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  659. return [[ORKdBHLToneAudiometryStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  660. },
  661. (@{
  662. PROPERTY(toneDuration, NSNumber, NSObject, YES, nil, nil),
  663. PROPERTY(maxRandomPreStimulusDelay, NSNumber, NSObject, YES, nil, nil),
  664. PROPERTY(postStimulusDelay, NSNumber, NSObject, YES, nil, nil),
  665. PROPERTY(maxNumberOfTransitionsPerFrequency, NSNumber, NSObject, YES, nil, nil),
  666. PROPERTY(initialdBHLValue, NSNumber, NSObject, YES, nil, nil),
  667. PROPERTY(dBHLStepUpSize, NSNumber, NSObject, YES, nil, nil),
  668. PROPERTY(dBHLStepDownSize, NSNumber, NSObject, YES, nil, nil),
  669. PROPERTY(headphoneType, NSString, NSObject, YES, nil, nil),
  670. PROPERTY(earPreference, NSNumber, NSObject, YES, nil, nil),
  671. PROPERTY(frequencyList, NSArray, NSObject, YES, nil, nil)
  672. })),
  673. ENTRY(ORKHolePegTestPlaceStep,
  674. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  675. return [[ORKHolePegTestPlaceStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  676. },
  677. (@{
  678. PROPERTY(movingDirection, NSNumber, NSObject, YES, nil, nil),
  679. PROPERTY(dominantHandTested, NSNumber, NSObject, YES, nil, nil),
  680. PROPERTY(numberOfPegs, NSNumber, NSObject, YES, nil, nil),
  681. PROPERTY(threshold, NSNumber, NSObject, YES, nil, nil),
  682. PROPERTY(rotated, NSNumber, NSObject, YES, nil, nil)
  683. })),
  684. ENTRY(ORKHolePegTestRemoveStep,
  685. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  686. return [[ORKHolePegTestRemoveStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  687. },
  688. (@{
  689. PROPERTY(movingDirection, NSNumber, NSObject, YES, nil, nil),
  690. PROPERTY(dominantHandTested, NSNumber, NSObject, YES, nil, nil),
  691. PROPERTY(numberOfPegs, NSNumber, NSObject, YES, nil, nil),
  692. PROPERTY(threshold, NSNumber, NSObject, YES, nil, nil)
  693. })),
  694. ENTRY(ORKImageCaptureStep,
  695. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  696. return [[ORKImageCaptureStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  697. },
  698. (@{
  699. PROPERTY(templateImageInsets, NSValue, NSObject, YES,
  700. ^id(id value) { return value?dictionaryFromUIEdgeInsets(((NSValue *)value).UIEdgeInsetsValue):nil; },
  701. ^id(id dict) { return [NSValue valueWithUIEdgeInsets:edgeInsetsFromDictionary(dict)]; }),
  702. PROPERTY(accessibilityHint, NSString, NSObject, YES, nil, nil),
  703. PROPERTY(accessibilityInstructions, NSString, NSObject, YES, nil, nil),
  704. PROPERTY(captureRaw, NSNumber, NSObject, YES, nil, nil)
  705. })),
  706. ENTRY(ORKVideoCaptureStep,
  707. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  708. return [[ORKVideoCaptureStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  709. },
  710. (@{
  711. PROPERTY(templateImageInsets, NSValue, NSObject, YES,
  712. ^id(id value) { return value?dictionaryFromUIEdgeInsets(((NSValue *)value).UIEdgeInsetsValue):nil; },
  713. ^id(id dict) { return [NSValue valueWithUIEdgeInsets:edgeInsetsFromDictionary(dict)]; }),
  714. PROPERTY(duration, NSNumber, NSObject, YES, nil, nil),
  715. PROPERTY(audioMute, NSNumber, NSObject, YES, nil, nil),
  716. PROPERTY(torchMode, NSNumber, NSObject, YES, nil, nil),
  717. PROPERTY(devicePosition, NSNumber, NSObject, YES, nil, nil),
  718. PROPERTY(accessibilityHint, NSString, NSObject, YES, nil, nil),
  719. PROPERTY(accessibilityInstructions, NSString, NSObject, YES, nil, nil),
  720. })),
  721. ENTRY(ORKSignatureStep,
  722. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  723. return [[ORKSignatureStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  724. },
  725. (@{
  726. })),
  727. ENTRY(ORKSpatialSpanMemoryStep,
  728. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  729. return [[ORKSpatialSpanMemoryStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  730. },
  731. (@{
  732. PROPERTY(initialSpan, NSNumber, NSObject, YES, nil, nil),
  733. PROPERTY(minimumSpan, NSNumber, NSObject, YES, nil, nil),
  734. PROPERTY(maximumSpan, NSNumber, NSObject, YES, nil, nil),
  735. PROPERTY(playSpeed, NSNumber, NSObject, YES, nil, nil),
  736. PROPERTY(maximumTests, NSNumber, NSObject, YES, nil, nil),
  737. PROPERTY(maximumConsecutiveFailures, NSNumber, NSObject, YES, nil, nil),
  738. PROPERTY(requireReversal, NSNumber, NSObject, YES, nil, nil),
  739. PROPERTY(customTargetPluralName, NSString, NSObject, YES, nil, nil),
  740. })),
  741. ENTRY(ORKWalkingTaskStep,
  742. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  743. return [[ORKWalkingTaskStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  744. },
  745. (@{
  746. PROPERTY(numberOfStepsPerLeg, NSNumber, NSObject, YES, nil, nil),
  747. })),
  748. ENTRY(ORKTableStep,
  749. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  750. return [[ORKTableStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  751. },
  752. ((@{
  753. PROPERTY(items, NSObject, NSArray, YES, nil, nil),
  754. PROPERTY(isBulleted, NSNumber, NSObject, YES, nil, nil),
  755. PROPERTY(bulletIconNames, NSString, NSArray, YES, nil, nil)
  756. }))),
  757. ENTRY(ORKTimedWalkStep,
  758. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  759. return [[ORKTimedWalkStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  760. },
  761. (@{
  762. PROPERTY(distanceInMeters, NSNumber, NSObject, YES, nil, nil),
  763. })),
  764. ENTRY(ORKPSATStep,
  765. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  766. return [[ORKPSATStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  767. },
  768. (@{
  769. PROPERTY(presentationMode, NSNumber, NSObject, YES, nil, nil),
  770. PROPERTY(interStimulusInterval, NSNumber, NSObject, YES, nil, nil),
  771. PROPERTY(stimulusDuration, NSNumber, NSObject, YES, nil, nil),
  772. PROPERTY(seriesLength, NSNumber, NSObject, YES, nil, nil),
  773. })),
  774. ENTRY(ORKRangeOfMotionStep,
  775. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  776. return [[ORKRangeOfMotionStep alloc] initWithIdentifier:GETPROP(dict, identifier) limbOption:(NSUInteger)[GETPROP(dict, identifier) integerValue]];
  777. },
  778. (@{
  779. PROPERTY(limbOption, NSNumber, NSObject, YES, nil, nil),
  780. })),
  781. ENTRY(ORKReactionTimeStep,
  782. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  783. return [[ORKReactionTimeStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  784. },
  785. (@{
  786. PROPERTY(maximumStimulusInterval, NSNumber, NSObject, YES, nil, nil),
  787. PROPERTY(minimumStimulusInterval, NSNumber, NSObject, YES, nil, nil),
  788. PROPERTY(timeout, NSNumber, NSObject, YES, nil, nil),
  789. PROPERTY(numberOfAttempts, NSNumber, NSObject, YES, nil, nil),
  790. PROPERTY(thresholdAcceleration, NSNumber, NSObject, YES, nil, nil),
  791. PROPERTY(successSound, NSNumber, NSObject, YES, nil, nil),
  792. PROPERTY(timeoutSound, NSNumber, NSObject, YES, nil, nil),
  793. PROPERTY(failureSound, NSNumber, NSObject, YES, nil, nil),
  794. })),
  795. ENTRY(ORKStroopStep,
  796. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  797. return [[ORKStroopStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  798. },
  799. (@{
  800. PROPERTY(numberOfAttempts, NSNumber, NSObject, YES, nil, nil)})),
  801. ENTRY(ORKTappingIntervalStep,
  802. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  803. return [[ORKTappingIntervalStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  804. },
  805. (@{
  806. })),
  807. ENTRY(ORKTrailmakingStep,
  808. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  809. return [[ORKTrailmakingStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  810. },
  811. (@{
  812. PROPERTY(trailType, NSString, NSObject, YES, nil, nil),
  813. })),
  814. ENTRY(ORKTowerOfHanoiStep,
  815. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  816. return [[ORKTowerOfHanoiStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  817. },
  818. (@{
  819. PROPERTY(numberOfDisks, NSNumber, NSObject, YES, nil, nil),
  820. })),
  821. ENTRY(ORKSpeechInNoiseStep,
  822. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  823. return [[ORKSpeechInNoiseStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  824. },
  825. ((@{
  826. PROPERTY(speechFileNameWithExtension, NSString, NSObject, YES, nil, nil),
  827. PROPERTY(noiseFileNameWithExtension, NSString, NSObject, YES, nil, nil),
  828. PROPERTY(filterFileNameWithExtension, NSString, NSObject, YES, nil, nil),
  829. PROPERTY(gainAppliedToNoise, NSNumber, NSObject, YES, nil, nil),
  830. PROPERTY(willAudioLoop, NSNumber, NSObject, YES, nil, nil),
  831. }))),
  832. ENTRY(ORKSpeechRecognitionStep,
  833. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  834. return [[ORKSpeechRecognitionStep alloc] initWithIdentifier:GETPROP(dict, identifier) image:nil text:GETPROP(dict, speechRecognitionText)];
  835. },
  836. (@{
  837. PROPERTY(shouldHideTranscript, NSNumber, NSObject, YES, nil, nil),
  838. PROPERTY(speechRecognitionText, NSString, NSObject, YES, nil, nil),
  839. PROPERTY(speechRecognizerLocale, NSString, NSObject, YES, nil, nil)
  840. })),
  841. ENTRY(ORKEnvironmentSPLMeterStep,
  842. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  843. return [[ORKEnvironmentSPLMeterStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  844. },
  845. (@{
  846. PROPERTY(thresholdValue, NSNumber, NSObject, YES, nil, nil),
  847. PROPERTY(samplingInterval, NSNumber, NSObject, YES, nil, nil),
  848. PROPERTY(requiredContiguousSamples, NSNumber, NSObject, YES, nil, nil),
  849. })),
  850. ENTRY(ORKEnvironmentSPLMeterResult,
  851. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  852. return [[ORKEnvironmentSPLMeterResult alloc] initWithIdentifier:GETPROP(dict, identifier)];
  853. },
  854. (@{
  855. PROPERTY(sensitivityOffset, NSNumber, NSObject, YES, nil, nil),
  856. PROPERTY(recordedSPLMeterSamples, NSNumber, NSArray, YES, nil, nil)
  857. })),
  858. ENTRY(ORKStreamingAudioRecorderConfiguration,
  859. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  860. return [[ORKStreamingAudioRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict, identifier)];
  861. },
  862. (@{
  863. })),
  864. ENTRY(ORKAccelerometerRecorderConfiguration,
  865. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  866. return [[ORKAccelerometerRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict, identifier) frequency:((NSNumber *)GETPROP(dict, frequency)).doubleValue];
  867. },
  868. (@{
  869. PROPERTY(frequency, NSNumber, NSObject, NO, nil, nil),
  870. })),
  871. ENTRY(ORKAudioRecorderConfiguration,
  872. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  873. return [[ORKAudioRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict, identifier) recorderSettings:GETPROP(dict, recorderSettings)];
  874. },
  875. (@{
  876. PROPERTY(recorderSettings, NSDictionary, NSObject, NO, nil, nil),
  877. })),
  878. ENTRY(ORKAmslerGridStep,
  879. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  880. return [[ORKAmslerGridStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  881. },
  882. (@{
  883. PROPERTY(eyeSide, NSNumber, NSObject, YES, nil, nil),
  884. })),
  885. ENTRY(ORKAmslerGridResult,
  886. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  887. return [[ORKAmslerGridResult alloc] initWithIdentifier:GETPROP(dict, identifier)image:[UIImage new] path:GETPROP(dict, path) eyeSide:(ORKAmslerGridEyeSide)[GETPROP(dict, eyeSide) integerValue]];
  888. },
  889. (@{
  890. PROPERTY(eyeSide, NSNumber, NSObject, NO, nil, nil),
  891. PROPERTY(path, UIBezierPath, NSArray, NO, nil, nil),
  892. })),
  893. ENTRY(ORKConsentDocument,
  894. nil,
  895. (@{
  896. PROPERTY(title, NSString, NSObject, NO, nil, nil),
  897. PROPERTY(sections, ORKConsentSection, NSArray, NO, nil, nil),
  898. PROPERTY(signaturePageTitle, NSString, NSObject, NO, nil, nil),
  899. PROPERTY(signaturePageContent, NSString, NSObject, NO, nil, nil),
  900. PROPERTY(signatures, ORKConsentSignature, NSArray, NO, nil, nil),
  901. PROPERTY(htmlReviewContent, NSString, NSObject, NO, nil, nil),
  902. })),
  903. ENTRY(ORKConsentSharingStep,
  904. ^(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  905. return [[ORKConsentSharingStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  906. },
  907. (@{
  908. PROPERTY(localizedLearnMoreHTMLContent, NSString, NSObject, YES, nil, nil),
  909. })),
  910. ENTRY(ORKConsentReviewStep,
  911. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  912. return [[ORKConsentReviewStep alloc] initWithIdentifier:GETPROP(dict, identifier) signature:GETPROP(dict, signature) inDocument:GETPROP(dict,consentDocument)];
  913. },
  914. (@{
  915. PROPERTY(consentDocument, ORKConsentDocument, NSObject, NO, nil, nil),
  916. PROPERTY(reasonForConsent, NSString, NSObject, YES, nil, nil),
  917. PROPERTY(signature, ORKConsentSignature, NSObject, NO, nil, nil),
  918. PROPERTY(requiresScrollToBottom, NSNumber, NSObject, YES, nil, nil)
  919. })),
  920. ENTRY(ORKFitnessStep,
  921. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  922. return [[ORKFitnessStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  923. },
  924. (@{
  925. })),
  926. ENTRY(ORKConsentSection,
  927. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  928. return [[ORKConsentSection alloc] initWithType:((NSNumber *)GETPROP(dict, type)).integerValue];
  929. },
  930. (@{
  931. PROPERTY(type, NSNumber, NSObject, NO, nil, nil),
  932. PROPERTY(title, NSString, NSObject, YES, nil, nil),
  933. PROPERTY(formalTitle, NSString, NSObject, YES, nil, nil),
  934. PROPERTY(summary, NSString, NSObject, YES, nil, nil),
  935. PROPERTY(content, NSString, NSObject, YES, nil, nil),
  936. PROPERTY(htmlContent, NSString, NSObject, YES, nil, nil),
  937. PROPERTY(contentURL, NSURL, NSObject, YES,
  938. ^id(id url) { return [(NSURL *)url absoluteString]; },
  939. ^id(id string) { return [NSURL URLWithString:string]; }),
  940. PROPERTY(customLearnMoreButtonTitle, NSString, NSObject, YES, nil, nil),
  941. PROPERTY(customAnimationURL, NSURL, NSObject, YES,
  942. ^id(id url) { return [(NSURL *)url absoluteString]; },
  943. ^id(id string) { return [NSURL URLWithString:string]; }),
  944. PROPERTY(omitFromDocument, NSNumber, NSObject, YES, nil, nil),
  945. })),
  946. ENTRY(ORKConsentSignature,
  947. nil,
  948. (@{
  949. PROPERTY(identifier, NSString, NSObject, YES, nil, nil),
  950. PROPERTY(title, NSString, NSObject, YES, nil, nil),
  951. PROPERTY(givenName, NSString, NSObject, YES, nil, nil),
  952. PROPERTY(familyName, NSString, NSObject, YES, nil, nil),
  953. PROPERTY(signatureDate, NSString, NSObject, YES, nil, nil),
  954. PROPERTY(requiresName, NSNumber, NSObject, YES, nil, nil),
  955. PROPERTY(requiresSignatureImage, NSNumber, NSObject, YES, nil, nil),
  956. PROPERTY(signatureDateFormatString, NSString, NSObject, YES, nil, nil),
  957. })),
  958. ENTRY(ORKRegistrationStep,
  959. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  960. return [[ORKRegistrationStep alloc] initWithIdentifier:GETPROP(dict, identifier) title:GETPROP(dict, title) text:GETPROP(dict, text) options:(NSUInteger)((NSNumber *)GETPROP(dict, options)).integerValue];
  961. },
  962. (@{
  963. PROPERTY(options, NSNumber, NSObject, NO, nil, nil)
  964. })),
  965. ENTRY(ORKVerificationStep,
  966. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  967. return [[ORKVerificationStep alloc] initWithIdentifier:GETPROP(dict, identifier) text:GETPROP(dict, text) verificationViewControllerClass:NSClassFromString(GETPROP(dict, verificationViewControllerString))];
  968. },
  969. (@{
  970. PROPERTY(verificationViewControllerString, NSString, NSObject, NO, nil, nil)
  971. })),
  972. ENTRY(ORKLoginStep,
  973. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  974. return [[ORKLoginStep alloc] initWithIdentifier:GETPROP(dict, identifier) title:GETPROP(dict, title) text:GETPROP(dict, text) loginViewControllerClass:NSClassFromString(GETPROP(dict, loginViewControllerString))];
  975. },
  976. (@{
  977. PROPERTY(loginViewControllerString, NSString, NSObject, NO, nil, nil)
  978. })),
  979. ENTRY(ORKDeviceMotionRecorderConfiguration,
  980. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  981. return [[ORKDeviceMotionRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict, identifier) frequency:((NSNumber *)GETPROP(dict, frequency)).doubleValue];
  982. },
  983. (@{
  984. PROPERTY(frequency, NSNumber, NSObject, NO, nil, nil),
  985. })),
  986. ENTRY(ORKdBHLToneAudiometryOnboardingStep,
  987. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  988. return [[ORKdBHLToneAudiometryOnboardingStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  989. },
  990. (@{
  991. PROPERTY(useCardView, NSNumber, NSObject, YES, nil, nil),
  992. })),
  993. ENTRY(ORKFormStep,
  994. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  995. return [[ORKFormStep alloc] initWithIdentifier:GETPROP(dict, identifier)];
  996. },
  997. (@{
  998. PROPERTY(formItems, ORKFormItem, NSArray, YES, nil, nil),
  999. PROPERTY(footnote, NSString, NSObject, YES, nil, nil),
  1000. PROPERTY(useCardView, NSNumber, NSObject, YES, nil, nil),
  1001. })),
  1002. ENTRY(ORKFormItem,
  1003. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1004. return [[ORKFormItem alloc] initWithIdentifier:GETPROP(dict, identifier) text:GETPROP(dict, text) answerFormat:GETPROP(dict, answerFormat)];
  1005. },
  1006. (@{
  1007. PROPERTY(identifier, NSString, NSObject, NO, nil, nil),
  1008. PROPERTY(optional, NSNumber, NSObject, YES, nil, nil),
  1009. PROPERTY(text, NSString, NSObject, NO, nil, nil),
  1010. PROPERTY(placeholder, NSString, NSObject, YES, nil, nil),
  1011. PROPERTY(answerFormat, ORKAnswerFormat, NSObject, NO, nil, nil),
  1012. })),
  1013. ENTRY(ORKPageStep,
  1014. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1015. ORKPageStep *step = [[ORKPageStep alloc] initWithIdentifier:GETPROP(dict, identifier) pageTask:GETPROP(dict, pageTask)];
  1016. return step;
  1017. },
  1018. (@{
  1019. PROPERTY(pageTask, ORKOrderedTask, NSObject, NO, nil, nil),
  1020. })),
  1021. ENTRY(ORKNavigablePageStep,
  1022. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1023. ORKNavigablePageStep *step = [[ORKNavigablePageStep alloc] initWithIdentifier:GETPROP(dict, identifier) pageTask:GETPROP(dict, pageTask)];
  1024. return step;
  1025. },
  1026. (@{
  1027. PROPERTY(pageTask, ORKOrderedTask, NSObject, NO, nil, nil),
  1028. })),
  1029. ENTRY(ORKHealthKitCharacteristicTypeAnswerFormat,
  1030. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1031. return [[ORKHealthKitCharacteristicTypeAnswerFormat alloc] initWithCharacteristicType:GETPROP(dict, characteristicType)];
  1032. },
  1033. (@{
  1034. PROPERTY(characteristicType, HKCharacteristicType, NSObject, NO,
  1035. ^id(id type) { return [(HKCharacteristicType *)type identifier]; },
  1036. ^id(id string) { return [HKCharacteristicType characteristicTypeForIdentifier:string]; }),
  1037. PROPERTY(defaultDate, NSDate, NSObject, YES,
  1038. ^id(id date) { return [ORKResultDateTimeFormatter() stringFromDate:date]; },
  1039. ^id(id string) { return [ORKResultDateTimeFormatter() dateFromString:string]; }),
  1040. PROPERTY(minimumDate, NSDate, NSObject, YES,
  1041. ^id(id date) { return [ORKResultDateTimeFormatter() stringFromDate:date]; },
  1042. ^id(id string) { return [ORKResultDateTimeFormatter() dateFromString:string]; }),
  1043. PROPERTY(maximumDate, NSDate, NSObject, YES,
  1044. ^id(id date) { return [ORKResultDateTimeFormatter() stringFromDate:date]; },
  1045. ^id(id string) { return [ORKResultDateTimeFormatter() dateFromString:string]; }),
  1046. PROPERTY(calendar, NSCalendar, NSObject, YES,
  1047. ^id(id calendar) { return [(NSCalendar *)calendar calendarIdentifier]; },
  1048. ^id(id string) { return [NSCalendar calendarWithIdentifier:string]; }),
  1049. PROPERTY(shouldRequestAuthorization, NSNumber, NSObject, YES, nil, nil),
  1050. })),
  1051. ENTRY(ORKHealthKitQuantityTypeAnswerFormat,
  1052. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1053. return [[ORKHealthKitQuantityTypeAnswerFormat alloc] initWithQuantityType:GETPROP(dict, quantityType) unit:GETPROP(dict, unit) style:((NSNumber *)GETPROP(dict, numericAnswerStyle)).integerValue];
  1054. },
  1055. (@{
  1056. PROPERTY(unit, HKUnit, NSObject, NO,
  1057. ^id(id unit) { return [(HKUnit *)unit unitString]; },
  1058. ^id(id string) { return [HKUnit unitFromString:string]; }),
  1059. PROPERTY(quantityType, HKQuantityType, NSObject, NO,
  1060. ^id(id type) { return [(HKQuantityType *)type identifier]; },
  1061. ^id(id string) { return [HKQuantityType quantityTypeForIdentifier:string]; }),
  1062. PROPERTY(numericAnswerStyle, NSNumber, NSObject, NO,
  1063. ^id(id num) { return ORKNumericAnswerStyleToString(((NSNumber *)num).integerValue); },
  1064. ^id(id string) { return @(ORKNumericAnswerStyleFromString(string)); }),
  1065. PROPERTY(shouldRequestAuthorization, NSNumber, NSObject, YES, nil, nil),
  1066. })),
  1067. ENTRY(ORKAnswerFormat,
  1068. nil,
  1069. (@{
  1070. })),
  1071. ENTRY(ORKValuePickerAnswerFormat,
  1072. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1073. return [[ORKValuePickerAnswerFormat alloc] initWithTextChoices:GETPROP(dict, textChoices)];
  1074. },
  1075. (@{
  1076. PROPERTY(textChoices, ORKTextChoice, NSArray, NO, nil, nil),
  1077. })),
  1078. ENTRY(ORKMultipleValuePickerAnswerFormat,
  1079. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1080. return [[ORKMultipleValuePickerAnswerFormat alloc] initWithValuePickers:GETPROP(dict, valuePickers) separator:GETPROP(dict, separator)];
  1081. },
  1082. (@{
  1083. PROPERTY(valuePickers, ORKValuePickerAnswerFormat, NSArray, NO, nil, nil),
  1084. PROPERTY(separator, NSString, NSObject, NO, nil, nil),
  1085. })),
  1086. ENTRY(ORKImageChoiceAnswerFormat,
  1087. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1088. return [[ORKImageChoiceAnswerFormat alloc] initWithImageChoices:GETPROP(dict, imageChoices) style:((NSNumber *)GETPROP(dict, style)).integerValue vertical:((NSNumber *)GETPROP(dict, vertical)).boolValue];
  1089. },
  1090. (@{
  1091. PROPERTY(imageChoices, ORKImageChoice, NSArray, NO, nil, nil),
  1092. PROPERTY(style, NSNumber, NSObject, NO,
  1093. ^id(id number) { return ORKImageChoiceAnswerStyleToString(((NSNumber *)number).integerValue); },
  1094. ^id(id string) { return @(ORKImageChoiceAnswerStyleFromString(string)); }),
  1095. PROPERTY(vertical, NSNumber, NSObject, NO, nil, nil),
  1096. })),
  1097. ENTRY(ORKTextChoiceAnswerFormat,
  1098. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1099. return [[ORKTextChoiceAnswerFormat alloc] initWithStyle:((NSNumber *)GETPROP(dict, style)).integerValue textChoices:GETPROP(dict, textChoices)];
  1100. },
  1101. (@{
  1102. PROPERTY(style, NSNumber, NSObject, NO, NUMTOSTRINGBLOCK(ORKChoiceAnswerStyleTable()), STRINGTONUMBLOCK(ORKChoiceAnswerStyleTable())),
  1103. PROPERTY(textChoices, ORKTextChoice, NSArray, NO, nil, nil),
  1104. })),
  1105. ENTRY(ORKTextChoice,
  1106. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1107. return [[ORKTextChoice alloc] initWithText:GETPROP(dict, text) detailText:GETPROP(dict, detailText) value:GETPROP(dict, value) exclusive:((NSNumber *)GETPROP(dict, exclusive)).boolValue];
  1108. },
  1109. (@{
  1110. PROPERTY(text, NSString, NSObject, NO, nil, nil),
  1111. PROPERTY(value, NSObject, NSObject, NO, nil, nil),
  1112. PROPERTY(detailText, NSString, NSObject, NO, nil, nil),
  1113. PROPERTY(exclusive, NSNumber, NSObject, NO, nil, nil),
  1114. })),
  1115. ENTRY(ORKTextChoice,
  1116. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1117. return [[ORKTextChoice alloc] initWithText:GETPROP(dict, text) detailText:GETPROP(dict, detailText) value:GETPROP(dict,value) exclusive:((NSNumber *)GETPROP(dict, exclusive)).boolValue];
  1118. },
  1119. (@{
  1120. PROPERTY(textViewPlaceholderText, NSString, NSObject, NO, nil, nil),
  1121. PROPERTY(textViewInputOptional, NSNumber, NSObject, NO, nil, nil),
  1122. PROPERTY(textViewStartsHidden, NSNumber, NSObject, NO, nil, nil),
  1123. })),
  1124. ENTRY(ORKImageChoice,
  1125. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1126. return [[ORKImageChoice alloc] initWithNormalImage:nil selectedImage:nil text:GETPROP(dict, text) value:GETPROP(dict, value)];
  1127. },
  1128. (@{
  1129. PROPERTY(text, NSString, NSObject, NO, nil, nil),
  1130. PROPERTY(value, NSObject, NSObject, NO, nil, nil),
  1131. })),
  1132. ENTRY(ORKTimeOfDayAnswerFormat,
  1133. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1134. return [[ORKTimeOfDayAnswerFormat alloc] initWithDefaultComponents:GETPROP(dict, defaultComponents)];
  1135. },
  1136. (@{
  1137. PROPERTY(defaultComponents, NSDateComponents, NSObject, NO,
  1138. ^id(id components) { return ORKTimeOfDayStringFromComponents(components); },
  1139. ^id(id string) { return ORKTimeOfDayComponentsFromString(string); }),
  1140. PROPERTY(minuteInterval, NSNumber, NSObject, YES, nil, nil)
  1141. })),
  1142. ENTRY(ORKDateAnswerFormat,
  1143. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1144. return [[ORKDateAnswerFormat alloc] initWithStyle:((NSNumber *)GETPROP(dict, style)).integerValue defaultDate:GETPROP(dict, defaultDate) minimumDate:GETPROP(dict, minimumDate) maximumDate:GETPROP(dict, maximumDate) calendar:GETPROP(dict, calendar)];
  1145. },
  1146. (@{
  1147. PROPERTY(style, NSNumber, NSObject, NO,
  1148. NUMTOSTRINGBLOCK(ORKDateAnswerStyleTable()),
  1149. STRINGTONUMBLOCK(ORKDateAnswerStyleTable())),
  1150. PROPERTY(calendar, NSCalendar, NSObject, NO,
  1151. ^id(id calendar) { return [(NSCalendar *)calendar calendarIdentifier]; },
  1152. ^id(id string) { return [NSCalendar calendarWithIdentifier:string]; }),
  1153. PROPERTY(minimumDate, NSDate, NSObject, NO,
  1154. ^id(id date) { return [ORKResultDateTimeFormatter() stringFromDate:date]; },
  1155. ^id(id string) { return [ORKResultDateTimeFormatter() dateFromString:string]; }),
  1156. PROPERTY(maximumDate, NSDate, NSObject, NO,
  1157. ^id(id date) { return [ORKResultDateTimeFormatter() stringFromDate:date]; },
  1158. ^id(id string) { return [ORKResultDateTimeFormatter() dateFromString:string]; }),
  1159. PROPERTY(defaultDate, NSDate, NSObject, NO,
  1160. ^id(id date) { return [ORKResultDateTimeFormatter() stringFromDate:date]; },
  1161. ^id(id string) { return [ORKResultDateTimeFormatter() dateFromString:string]; }),
  1162. PROPERTY(minuteInterval, NSNumber, NSObject, YES, nil, nil)
  1163. })),
  1164. ENTRY(ORKNumericAnswerFormat,
  1165. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1166. ORKNumericAnswerFormat *format = [[ORKNumericAnswerFormat alloc] initWithStyle:((NSNumber *)GETPROP(dict, style)).integerValue unit:GETPROP(dict, unit) minimum:GETPROP(dict, minimum) maximum:GETPROP(dict, maximum) maximumFractionDigits:GETPROP(dict, maximumFractionDigits)];
  1167. format.defaultNumericAnswer = GETPROP(dict, defaultNumericAnswer);
  1168. return format;
  1169. },
  1170. (@{
  1171. PROPERTY(style, NSNumber, NSObject, NO,
  1172. ^id(id num) { return ORKNumericAnswerStyleToString(((NSNumber *)num).integerValue); },
  1173. ^id(id string) { return @(ORKNumericAnswerStyleFromString(string)); }),
  1174. PROPERTY(unit, NSString, NSObject, NO, nil, nil),
  1175. PROPERTY(minimum, NSNumber, NSObject, NO, nil, nil),
  1176. PROPERTY(maximum, NSNumber, NSObject, NO, nil, nil),
  1177. PROPERTY(maximumFractionDigits, NSNumber, NSObject, NO, nil, nil),
  1178. PROPERTY(defaultNumericAnswer, NSNumber, NSObject, NO, nil, nil),
  1179. })),
  1180. ENTRY(ORKScaleAnswerFormat,
  1181. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1182. return [[ORKScaleAnswerFormat alloc] initWithMaximumValue:((NSNumber *)GETPROP(dict, maximum)).integerValue minimumValue:((NSNumber *)GETPROP(dict, minimum)).integerValue defaultValue:((NSNumber *)GETPROP(dict, defaultValue)).integerValue step:((NSNumber *)GETPROP(dict, step)).integerValue vertical:((NSNumber *)GETPROP(dict, vertical)).boolValue maximumValueDescription:GETPROP(dict, maximumValueDescription) minimumValueDescription:GETPROP(dict, minimumValueDescription)];
  1183. },
  1184. (@{
  1185. PROPERTY(minimum, NSNumber, NSObject, NO, nil, nil),
  1186. PROPERTY(maximum, NSNumber, NSObject, NO, nil, nil),
  1187. PROPERTY(defaultValue, NSNumber, NSObject, NO, nil, nil),
  1188. PROPERTY(step, NSNumber, NSObject, NO, nil, nil),
  1189. PROPERTY(vertical, NSNumber, NSObject, NO, nil, nil),
  1190. PROPERTY(maximumValueDescription, NSString, NSObject, NO, nil, nil),
  1191. PROPERTY(minimumValueDescription, NSString, NSObject, NO, nil, nil),
  1192. PROPERTY(gradientColors, UIColor, NSArray, YES, nil, nil),
  1193. PROPERTY(gradientLocations, NSNumber, NSArray, YES, nil, nil),
  1194. PROPERTY(hideSelectedValue, NSNumber, NSObject, YES, nil, nil)
  1195. })),
  1196. ENTRY(ORKContinuousScaleAnswerFormat,
  1197. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1198. return [[ORKContinuousScaleAnswerFormat alloc] initWithMaximumValue:((NSNumber *)GETPROP(dict, maximum)).doubleValue minimumValue:((NSNumber *)GETPROP(dict, minimum)).doubleValue defaultValue:((NSNumber *)GETPROP(dict, defaultValue)).doubleValue maximumFractionDigits:((NSNumber *)GETPROP(dict, maximumFractionDigits)).integerValue vertical:((NSNumber *)GETPROP(dict, vertical)).boolValue maximumValueDescription:GETPROP(dict, maximumValueDescription) minimumValueDescription:GETPROP(dict, minimumValueDescription)];
  1199. },
  1200. (@{
  1201. PROPERTY(minimum, NSNumber, NSObject, NO, nil, nil),
  1202. PROPERTY(maximum, NSNumber, NSObject, NO, nil, nil),
  1203. PROPERTY(defaultValue, NSNumber, NSObject, NO, nil, nil),
  1204. PROPERTY(maximumFractionDigits, NSNumber, NSObject, NO, nil, nil),
  1205. PROPERTY(vertical, NSNumber, NSObject, NO, nil, nil),
  1206. PROPERTY(numberStyle, NSNumber, NSObject, YES,
  1207. ^id(id numeric) { return tableMapForward(((NSNumber *)numeric).integerValue, numberFormattingStyleTable()); },
  1208. ^id(id string) { return @(tableMapReverse(string, numberFormattingStyleTable())); }),
  1209. PROPERTY(maximumValueDescription, NSString, NSObject, NO, nil, nil),
  1210. PROPERTY(minimumValueDescription, NSString, NSObject, NO, nil, nil),
  1211. PROPERTY(gradientColors, UIColor, NSArray, YES, nil, nil),
  1212. PROPERTY(gradientLocations, NSNumber, NSArray, YES, nil, nil),
  1213. PROPERTY(hideSelectedValue, NSNumber, NSObject, YES, nil, nil)
  1214. })),
  1215. ENTRY(ORKTextScaleAnswerFormat,
  1216. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1217. return [[ORKTextScaleAnswerFormat alloc] initWithTextChoices:GETPROP(dict, textChoices) defaultIndex:(NSInteger)[GETPROP(dict, defaultIndex) doubleValue] vertical:[GETPROP(dict, vertical) boolValue]];
  1218. },
  1219. (@{
  1220. PROPERTY(textChoices, ORKTextChoice, NSArray<ORKTextChoice *>, NO, nil, nil),
  1221. PROPERTY(defaultIndex, NSNumber, NSObject, NO, nil, nil),
  1222. PROPERTY(vertical, NSNumber, NSObject, NO, nil, nil),
  1223. PROPERTY(gradientColors, UIColor, NSArray, YES, nil, nil),
  1224. PROPERTY(gradientLocations, NSNumber, NSArray, YES, nil, nil),
  1225. PROPERTY(hideSelectedValue, NSNumber, NSObject, YES, nil, nil)
  1226. })),
  1227. ENTRY(ORKTextAnswerFormat,
  1228. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1229. return [[ORKTextAnswerFormat alloc] initWithMaximumLength:((NSNumber *)GETPROP(dict, maximumLength)).integerValue];
  1230. },
  1231. (@{
  1232. PROPERTY(maximumLength, NSNumber, NSObject, NO, nil, nil),
  1233. PROPERTY(validationRegularExpression, NSRegularExpression, NSObject, YES,
  1234. ^id(id value) { return dictionaryFromRegularExpression((NSRegularExpression *)value); },
  1235. ^id(id dict) { return regularExpressionsFromDictionary(dict); } ),
  1236. PROPERTY(invalidMessage, NSString, NSObject, YES, nil, nil),
  1237. PROPERTY(defaultTextAnswer, NSString, NSObject, YES, nil, nil),
  1238. PROPERTY(autocapitalizationType, NSNumber, NSObject, YES, nil, nil),
  1239. PROPERTY(autocorrectionType, NSNumber, NSObject, YES, nil, nil),
  1240. PROPERTY(spellCheckingType, NSNumber, NSObject, YES, nil, nil),
  1241. PROPERTY(keyboardType, NSNumber, NSObject, YES, nil, nil),
  1242. PROPERTY(multipleLines, NSNumber, NSObject, YES, nil, nil),
  1243. PROPERTY(secureTextEntry, NSNumber, NSObject, YES, nil, nil),
  1244. PROPERTY(textContentType, NSString, NSObject, YES, nil, nil),
  1245. PROPERTY(passwordRules, UITextInputPasswordRules, NSObject, YES,
  1246. ^id(id value) { return dictionaryFromPasswordRules((UITextInputPasswordRules *)value); },
  1247. ^id(id dict) { return passwordRulesFromDictionary(dict); } )
  1248. })),
  1249. ENTRY(ORKEmailAnswerFormat,
  1250. nil,
  1251. (@{
  1252. PROPERTY(usernameField, NSNumber, NSObject, YES, nil, nil),
  1253. })),
  1254. ENTRY(ORKConfirmTextAnswerFormat,
  1255. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1256. return [[ORKConfirmTextAnswerFormat alloc] initWithOriginalItemIdentifier:GETPROP(dict, originalItemIdentifier) errorMessage:GETPROP(dict, errorMessage)];
  1257. },
  1258. (@{
  1259. PROPERTY(originalItemIdentifier, NSString, NSObject, NO, nil, nil),
  1260. PROPERTY(errorMessage, NSString, NSObject, NO, nil, nil),
  1261. PROPERTY(maximumLength, NSNumber, NSObject, YES, nil, nil)
  1262. })),
  1263. ENTRY(ORKTimeIntervalAnswerFormat,
  1264. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1265. return [[ORKTimeIntervalAnswerFormat alloc] initWithDefaultInterval:((NSNumber *)GETPROP(dict, defaultInterval)).doubleValue step:((NSNumber *)GETPROP(dict, step)).integerValue];
  1266. },
  1267. (@{
  1268. PROPERTY(defaultInterval, NSNumber, NSObject, NO, nil, nil),
  1269. PROPERTY(step, NSNumber, NSObject, NO, nil, nil),
  1270. })),
  1271. ENTRY(ORKBooleanAnswerFormat,
  1272. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1273. return [[ORKBooleanAnswerFormat alloc] initWithYesString:((NSString *)GETPROP(dict, yes)) noString:((NSString *)GETPROP(dict, no))];
  1274. },
  1275. (@{
  1276. PROPERTY(yes, NSString, NSObject, NO, nil, nil),
  1277. PROPERTY(no, NSString, NSObject, NO, nil, nil)
  1278. })),
  1279. ENTRY(ORKHeightAnswerFormat,
  1280. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1281. return [[ORKHeightAnswerFormat alloc] initWithMeasurementSystem:((NSNumber *)GETPROP(dict, measurementSystem)).integerValue];
  1282. },
  1283. (@{
  1284. PROPERTY(measurementSystem, NSNumber, NSObject, NO,
  1285. ^id(id number) { return ORKMeasurementSystemToString(((NSNumber *)number).integerValue); },
  1286. ^id(id string) { return @(ORKMeasurementSystemFromString(string)); }),
  1287. })),
  1288. ENTRY(ORKWeightAnswerFormat,
  1289. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1290. return [[ORKWeightAnswerFormat alloc] initWithMeasurementSystem:((NSNumber *)GETPROP(dict, measurementSystem)).integerValue
  1291. numericPrecision:((NSNumber *)GETPROP(dict, numericPrecision)).integerValue
  1292. minimumValue:((NSNumber *)GETPROP(dict, minimumValue)).doubleValue
  1293. maximumValue:((NSNumber *)GETPROP(dict, maximumValue)).doubleValue
  1294. defaultValue:((NSNumber *)GETPROP(dict, defaultValue)).doubleValue];
  1295. },
  1296. (@{
  1297. PROPERTY(measurementSystem, NSNumber, NSObject, NO,
  1298. ^id(id number) { return ORKMeasurementSystemToString(((NSNumber *)number).integerValue); },
  1299. ^id(id string) { return @(ORKMeasurementSystemFromString(string)); }),
  1300. PROPERTY(numericPrecision, NSNumber, NSObject, NO, nil, nil),
  1301. PROPERTY(minimumValue, NSNumber, NSObject, NO, nil, nil),
  1302. PROPERTY(maximumValue, NSNumber, NSObject, NO, nil, nil),
  1303. PROPERTY(defaultValue, NSNumber, NSObject, NO, nil, nil),
  1304. })),
  1305. ENTRY(ORKLocationAnswerFormat,
  1306. ^id(__unused NSDictionary *dict, __unused ORKESerializationPropertyGetter getter) {
  1307. return [[ORKLocationAnswerFormat alloc] init];
  1308. },
  1309. (@{
  1310. PROPERTY(useCurrentLocation, NSNumber, NSObject, YES, nil, nil)
  1311. })),
  1312. ENTRY(ORKLocationRecorderConfiguration,
  1313. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1314. return [[ORKLocationRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict,identifier)];
  1315. },
  1316. (@{
  1317. })),
  1318. ENTRY(ORKPedometerRecorderConfiguration,
  1319. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1320. return [[ORKPedometerRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict,identifier)];
  1321. },
  1322. (@{
  1323. })),
  1324. ENTRY(ORKTouchRecorderConfiguration,
  1325. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1326. return [[ORKTouchRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict,identifier)];
  1327. },
  1328. (@{
  1329. })),
  1330. ENTRY(ORKResult,
  1331. nil,
  1332. (@{
  1333. PROPERTY(identifier, NSString, NSObject, NO, nil, nil),
  1334. PROPERTY(startDate, NSDate, NSObject, YES,
  1335. ^id(id date) { return ORKEStringFromDateISO8601(date); },
  1336. ^id(id string) { return ORKEDateFromStringISO8601(string); }),
  1337. PROPERTY(endDate, NSDate, NSObject, YES,
  1338. ^id(id date) { return ORKEStringFromDateISO8601(date); },
  1339. ^id(id string) { return ORKEDateFromStringISO8601(string); }),
  1340. PROPERTY(userInfo, NSDictionary, NSObject, YES, nil, nil)
  1341. })),
  1342. ENTRY(ORKTappingSample,
  1343. nil,
  1344. (@{
  1345. PROPERTY(timestamp, NSNumber, NSObject, NO, nil, nil),
  1346. PROPERTY(duration, NSNumber, NSObject, NO, nil, nil),
  1347. PROPERTY(buttonIdentifier, NSNumber, NSObject, NO,
  1348. ^id(id numeric) { return tableMapForward(((NSNumber *)numeric).integerValue, buttonIdentifierTable()); },
  1349. ^id(id string) { return @(tableMapReverse(string, buttonIdentifierTable())); }),
  1350. PROPERTY(location, NSValue, NSObject, NO,
  1351. ^id(id value) { return value?dictionaryFromCGPoint(((NSValue *)value).CGPointValue):nil; },
  1352. ^id(id dict) { return [NSValue valueWithCGPoint:pointFromDictionary(dict)]; })
  1353. })),
  1354. ENTRY(ORKTappingIntervalResult,
  1355. nil,
  1356. (@{
  1357. PROPERTY(samples, ORKTappingSample, NSArray, NO, nil, nil),
  1358. PROPERTY(stepViewSize, NSValue, NSObject, NO,
  1359. ^id(id value) { return value?dictionaryFromCGSize(((NSValue *)value).CGSizeValue):nil; },
  1360. ^id(id dict) { return [NSValue valueWithCGSize:sizeFromDictionary(dict)]; }),
  1361. PROPERTY(buttonRect1, NSValue, NSObject, NO,
  1362. ^id(id value) { return value?dictionaryFromCGRect(((NSValue *)value).CGRectValue):nil; },
  1363. ^id(id dict) { return [NSValue valueWithCGRect:rectFromDictionary(dict)]; }),
  1364. PROPERTY(buttonRect2, NSValue, NSObject, NO,
  1365. ^id(id value) { return value?dictionaryFromCGRect(((NSValue *)value).CGRectValue):nil; },
  1366. ^id(id dict) { return [NSValue valueWithCGRect:rectFromDictionary(dict)]; })
  1367. })),
  1368. ENTRY(ORKTrailmakingTap,
  1369. nil,
  1370. (@{
  1371. PROPERTY(timestamp, NSNumber, NSObject, NO, nil, nil),
  1372. PROPERTY(index, NSNumber, NSObject, NO, nil, nil),
  1373. PROPERTY(incorrect, NSNumber, NSObject, NO, nil, nil),
  1374. })),
  1375. ENTRY(ORKTrailmakingResult,
  1376. nil,
  1377. (@{
  1378. PROPERTY(taps, ORKTrailmakingTap, NSArray, NO, nil, nil),
  1379. PROPERTY(numberOfErrors, NSNumber, NSObject, NO, nil, nil)
  1380. })),
  1381. ENTRY(ORKSpatialSpanMemoryGameTouchSample,
  1382. nil,
  1383. (@{
  1384. PROPERTY(timestamp, NSNumber, NSObject, NO, nil, nil),
  1385. PROPERTY(targetIndex, NSNumber, NSObject, NO, nil, nil),
  1386. PROPERTY(correct, NSNumber, NSObject, NO, nil, nil),
  1387. PROPERTY(location, NSValue, NSObject, NO,
  1388. ^id(id value) { return value?dictionaryFromCGPoint(((NSValue *)value).CGPointValue):nil; },
  1389. ^id(id dict) { return [NSValue valueWithCGPoint:pointFromDictionary(dict)]; })
  1390. })),
  1391. ENTRY(ORKSpatialSpanMemoryGameRecord,
  1392. nil,
  1393. (@{
  1394. PROPERTY(seed, NSNumber, NSObject, NO, nil, nil),
  1395. PROPERTY(sequence, NSNumber, NSArray, NO, nil, nil),
  1396. PROPERTY(gameSize, NSNumber, NSObject, NO, nil, nil),
  1397. PROPERTY(gameStatus, NSNumber, NSObject, NO, nil, nil),
  1398. PROPERTY(score, NSNumber, NSObject, NO, nil, nil),
  1399. PROPERTY(touchSamples, ORKSpatialSpanMemoryGameTouchSample, NSArray, NO,
  1400. ^id(id numeric) { return tableMapForward(((NSNumber *)numeric).integerValue, memoryGameStatusTable()); },
  1401. ^id(id string) { return @(tableMapReverse(string, memoryGameStatusTable())); }),
  1402. PROPERTY(targetRects, NSValue, NSArray, NO,
  1403. ^id(id value) { return value?dictionaryFromCGRect(((NSValue *)value).CGRectValue):nil; },
  1404. ^id(id dict) { return [NSValue valueWithCGRect:rectFromDictionary(dict)]; })
  1405. })),
  1406. ENTRY(ORKSpatialSpanMemoryResult,
  1407. nil,
  1408. (@{
  1409. PROPERTY(score, NSNumber, NSObject, NO, nil, nil),
  1410. PROPERTY(numberOfGames, NSNumber, NSObject, NO, nil, nil),
  1411. PROPERTY(numberOfFailures, NSNumber, NSObject, NO, nil, nil),
  1412. PROPERTY(gameRecords, ORKSpatialSpanMemoryGameRecord, NSArray, NO, nil, nil)
  1413. })),
  1414. ENTRY(ORKFileResult,
  1415. nil,
  1416. (@{
  1417. PROPERTY(contentType, NSString, NSObject, NO, nil, nil),
  1418. PROPERTY(fileURL, NSURL, NSObject, NO,
  1419. ^id(id url) { return [url absoluteString]; },
  1420. ^id(id string) { return [NSURL URLWithString:string]; })
  1421. })),
  1422. ENTRY(ORKToneAudiometrySample,
  1423. nil,
  1424. (@{
  1425. PROPERTY(frequency, NSNumber, NSObject, NO, nil, nil),
  1426. PROPERTY(channel, NSNumber, NSObject, NO, nil, nil),
  1427. PROPERTY(amplitude, NSNumber, NSObject, NO, nil, nil),
  1428. PROPERTY(channelSelected, NSNumber, NSObject, NO, nil, nil)
  1429. })),
  1430. ENTRY(ORKToneAudiometryResult,
  1431. nil,
  1432. (@{
  1433. PROPERTY(outputVolume, NSNumber, NSObject, NO, nil, nil),
  1434. PROPERTY(samples, ORKToneAudiometrySample, NSArray, NO, nil, nil),
  1435. })),
  1436. ENTRY(ORKdBHLToneAudiometryUnit,
  1437. nil,
  1438. (@{
  1439. PROPERTY(dBHLValue, NSNumber, NSObject, NO, nil, nil),
  1440. PROPERTY(startOfUnitTimeStamp, NSNumber, NSObject, NO, nil, nil),
  1441. PROPERTY(preStimulusDelay, NSNumber, NSObject, NO, nil, nil),
  1442. PROPERTY(userTapTimeStamp, NSNumber, NSObject, NO, nil, nil),
  1443. PROPERTY(timeoutTimeStamp, NSNumber, NSObject, NO, nil, nil)
  1444. })),
  1445. ENTRY(ORKdBHLToneAudiometryFrequencySample,
  1446. nil,
  1447. (@{
  1448. PROPERTY(frequency, NSNumber, NSObject, NO, nil, nil),
  1449. PROPERTY(calculatedThreshold, NSNumber, NSObject, NO,
  1450. (^id(id threshold) { return [NSString stringWithFormat:@"%@", threshold]; }),
  1451. (^id(id string) { return [NSDecimalNumber decimalNumberWithString:string]; })),
  1452. PROPERTY(channel, NSNumber, NSObject, NO, nil, nil),
  1453. PROPERTY(units, ORKdBHLToneAudiometryUnit, NSArray, NO, nil, nil)
  1454. })),
  1455. ENTRY(ORKdBHLToneAudiometryResult,
  1456. nil,
  1457. (@{
  1458. PROPERTY(outputVolume, NSNumber, NSObject, NO, nil, nil),
  1459. PROPERTY(tonePlaybackDuration, NSNumber, NSObject, NO, nil, nil),
  1460. PROPERTY(postStimulusDelay, NSNumber, NSObject, NO, nil, nil),
  1461. PROPERTY(headphoneType, NSString, NSObject, NO, nil, nil),
  1462. PROPERTY(samples, ORKdBHLToneAudiometryFrequencySample, NSArray, NO, nil, nil),
  1463. })),
  1464. ENTRY(ORKReactionTimeResult,
  1465. nil,
  1466. (@{
  1467. PROPERTY(timestamp, NSNumber, NSObject, NO, nil, nil),
  1468. PROPERTY(fileResult, ORKResult, NSObject, NO, nil, nil)
  1469. })),
  1470. ENTRY(ORKSpeechRecognitonResult,
  1471. nil,
  1472. (@{
  1473. })),
  1474. ENTRY(ORKStroopResult,
  1475. nil,
  1476. (@{
  1477. PROPERTY(startTime, NSNumber, NSObject, NO, nil, nil),
  1478. PROPERTY(endTime, NSNumber, NSObject, NO, nil, nil),
  1479. PROPERTY(color, NSString, NSObject, NO, nil, nil),
  1480. PROPERTY(text, NSString, NSObject, NO, nil, nil),
  1481. PROPERTY(colorSelected, NSString, NSObject, NO, nil, nil)
  1482. })),
  1483. ENTRY(ORKTimedWalkResult,
  1484. nil,
  1485. (@{
  1486. PROPERTY(distanceInMeters, NSNumber, NSObject, NO, nil, nil),
  1487. PROPERTY(timeLimit, NSNumber, NSObject, NO, nil, nil),
  1488. PROPERTY(duration, NSNumber, NSObject, NO, nil, nil),
  1489. })),
  1490. ENTRY(ORKPSATSample,
  1491. nil,
  1492. (@{
  1493. PROPERTY(correct, NSNumber, NSObject, NO, nil, nil),
  1494. PROPERTY(digit, NSNumber, NSObject, NO, nil, nil),
  1495. PROPERTY(answer, NSNumber, NSObject, NO, nil, nil),
  1496. PROPERTY(time, NSNumber, NSObject, NO, nil, nil),
  1497. })),
  1498. ENTRY(ORKPSATResult,
  1499. nil,
  1500. (@{
  1501. PROPERTY(presentationMode, NSNumber, NSObject, NO, nil, nil),
  1502. PROPERTY(interStimulusInterval, NSNumber, NSObject, NO, nil, nil),
  1503. PROPERTY(stimulusDuration, NSNumber, NSObject, NO, nil, nil),
  1504. PROPERTY(length, NSNumber, NSObject, NO, nil, nil),
  1505. PROPERTY(totalCorrect, NSNumber, NSObject, NO, nil, nil),
  1506. PROPERTY(totalDyad, NSNumber, NSObject, NO, nil, nil),
  1507. PROPERTY(totalTime, NSNumber, NSObject, NO, nil, nil),
  1508. PROPERTY(initialDigit, NSNumber, NSObject, NO, nil, nil),
  1509. PROPERTY(samples, ORKPSATSample, NSArray, NO, nil, nil),
  1510. })),
  1511. ENTRY(ORKRangeOfMotionResult,
  1512. nil,
  1513. (@{
  1514. PROPERTY(start, NSNumber, NSObject, NO, nil, nil),
  1515. PROPERTY(finish, NSNumber, NSObject, NO, nil, nil),
  1516. PROPERTY(minimum, NSNumber, NSObject, NO, nil, nil),
  1517. PROPERTY(maximum, NSNumber, NSObject, NO, nil, nil),
  1518. PROPERTY(range, NSNumber, NSObject, NO, nil, nil),
  1519. })),
  1520. ENTRY(ORKTowerOfHanoiResult,
  1521. nil,
  1522. (@{
  1523. PROPERTY(puzzleWasSolved, NSNumber, NSObject, YES, nil, nil),
  1524. PROPERTY(moves, ORKTowerOfHanoiMove, NSArray, YES, nil, nil),
  1525. })),
  1526. ENTRY(ORKTowerOfHanoiMove,
  1527. nil,
  1528. (@{
  1529. PROPERTY(timestamp, NSNumber, NSObject, YES, nil, nil),
  1530. PROPERTY(donorTowerIndex, NSNumber, NSObject, YES, nil, nil),
  1531. PROPERTY(recipientTowerIndex, NSNumber, NSObject, YES, nil, nil),
  1532. })),
  1533. ENTRY(ORKHolePegTestSample,
  1534. nil,
  1535. (@{
  1536. PROPERTY(time, NSNumber, NSObject, NO, nil, nil),
  1537. PROPERTY(distance, NSNumber, NSObject, NO, nil, nil)
  1538. })),
  1539. ENTRY(ORKHolePegTestResult,
  1540. nil,
  1541. (@{
  1542. PROPERTY(movingDirection, NSNumber, NSObject, NO, nil, nil),
  1543. PROPERTY(dominantHandTested, NSNumber, NSObject, NO, nil, nil),
  1544. PROPERTY(numberOfPegs, NSNumber, NSObject, NO, nil, nil),
  1545. PROPERTY(threshold, NSNumber, NSObject, NO, nil, nil),
  1546. PROPERTY(rotated, NSNumber, NSObject, NO, nil, nil),
  1547. PROPERTY(totalSuccesses, NSNumber, NSObject, NO, nil, nil),
  1548. PROPERTY(totalFailures, NSNumber, NSObject, NO, nil, nil),
  1549. PROPERTY(totalTime, NSNumber, NSObject, NO, nil, nil),
  1550. PROPERTY(totalDistance, NSNumber, NSObject, NO, nil, nil),
  1551. PROPERTY(samples, ORKHolePegTestSample, NSArray, NO, nil, nil),
  1552. })),
  1553. ENTRY(ORKPasscodeResult,
  1554. nil,
  1555. (@{
  1556. PROPERTY(passcodeSaved, NSNumber, NSObject, YES, nil, nil),
  1557. PROPERTY(touchIdEnabled, NSNumber, NSObject, YES, nil, nil)
  1558. })),
  1559. ENTRY(ORKQuestionResult,
  1560. nil,
  1561. (@{
  1562. PROPERTY(questionType, NSNumber, NSObject, NO, nil, nil)
  1563. })),
  1564. ENTRY(ORKScaleQuestionResult,
  1565. nil,
  1566. (@{
  1567. PROPERTY(scaleAnswer, NSNumber, NSObject, NO, nil, nil)
  1568. })),
  1569. ENTRY(ORKChoiceQuestionResult,
  1570. nil,
  1571. (@{
  1572. PROPERTY(choiceAnswers, NSObject, NSObject, NO, nil, nil)
  1573. })),
  1574. ENTRY(ORKMultipleComponentQuestionResult,
  1575. nil,
  1576. (@{
  1577. PROPERTY(componentsAnswer, NSObject, NSObject, NO, nil, nil),
  1578. PROPERTY(separator, NSString, NSObject, NO, nil, nil)
  1579. })),
  1580. ENTRY(ORKBooleanQuestionResult,
  1581. nil,
  1582. (@{
  1583. PROPERTY(booleanAnswer, NSNumber, NSObject, NO, nil, nil)
  1584. })),
  1585. ENTRY(ORKTextQuestionResult,
  1586. nil,
  1587. (@{
  1588. PROPERTY(textAnswer, NSString, NSObject, NO, nil, nil)
  1589. })),
  1590. ENTRY(ORKNumericQuestionResult,
  1591. nil,
  1592. (@{
  1593. PROPERTY(numericAnswer, NSNumber, NSObject, NO, nil, nil),
  1594. PROPERTY(unit, NSString, NSObject, NO, nil, nil)
  1595. })),
  1596. ENTRY(ORKTimeOfDayQuestionResult,
  1597. nil,
  1598. (@{
  1599. PROPERTY(dateComponentsAnswer, NSDateComponents, NSObject, NO,
  1600. ^id(id dateComponents) { return ORKTimeOfDayStringFromComponents(dateComponents); },
  1601. ^id(id string) { return ORKTimeOfDayComponentsFromString(string); })
  1602. })),
  1603. ENTRY(ORKTimeIntervalQuestionResult,
  1604. nil,
  1605. (@{
  1606. PROPERTY(intervalAnswer, NSNumber, NSObject, NO, nil, nil)
  1607. })),
  1608. ENTRY(ORKDateQuestionResult,
  1609. nil,
  1610. (@{
  1611. PROPERTY(dateAnswer, NSDate, NSObject, NO,
  1612. ^id(id date) { return ORKEStringFromDateISO8601(date); },
  1613. ^id(id string) { return ORKEDateFromStringISO8601(string); }),
  1614. PROPERTY(calendar, NSCalendar, NSObject, NO,
  1615. ^id(id calendar) { return [(NSCalendar *)calendar calendarIdentifier]; },
  1616. ^id(id string) { return [NSCalendar calendarWithIdentifier:string]; }),
  1617. PROPERTY(timeZone, NSTimeZone, NSObject, NO,
  1618. ^id(id timeZone) { return @([timeZone secondsFromGMT]); },
  1619. ^id(id number) { return [NSTimeZone timeZoneForSecondsFromGMT:(NSInteger)((NSNumber *)number).doubleValue]; })
  1620. })),
  1621. // ENTRY(ORKLocation,
  1622. // ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1623. // CLLocationCoordinate2D coordinate = coordinateFromDictionary(dict[@ESTRINGIFY(coordinate)]);
  1624. // return [[ORKLocation alloc] initWithCoordinate:coordinate];
  1625. //// region:GETPROP(dict, region)
  1626. //// userInput:GETPROP(dict, userInput)
  1627. //// postalAddress:GETPROP(dict, postalAddress)];
  1628. // },
  1629. // (@{
  1630. // PROPERTY(userInput, NSString, NSObject, NO, nil, nil),
  1631. // PROPERTY(postalAddress, CNPostalAddress, NSObject, NO,
  1632. // ^id(id value) { return dictionaryFromPasswordRules(value); },
  1633. // ^id(id dict) { return passwordRulesFromDictionary(dict); }),
  1634. // PROPERTY(coordinate, NSValue, NSObject, NO,
  1635. // ^id(id value) { return value ? dictionaryFromCoordinate(((NSValue *)value).MKCoordinateValue) : nil; },
  1636. // ^id(id dict) { return [NSValue valueWithMKCoordinate:coordinateFromDictionary(dict)]; }),
  1637. // PROPERTY(region, CLCircularRegion, NSObject, NO,
  1638. // ^id(id value) { return dictionaryFromCircularRegion((CLCircularRegion *)value); },
  1639. // ^id(id dict) { return circularRegionFromDictionary(dict); }),
  1640. // })),
  1641. ENTRY(ORKLocationQuestionResult,
  1642. nil,
  1643. (@{
  1644. PROPERTY(locationAnswer, ORKLocation, NSObject, NO, nil, nil)
  1645. })),
  1646. ENTRY(ORKConsentSignatureResult,
  1647. nil,
  1648. (@{
  1649. PROPERTY(signature, ORKConsentSignature, NSObject, YES, nil, nil),
  1650. PROPERTY(consented, NSNumber, NSObject, YES, nil, nil),
  1651. })),
  1652. ENTRY(ORKSignatureResult,
  1653. nil,
  1654. (@{
  1655. })),
  1656. ENTRY(ORKCollectionResult,
  1657. nil,
  1658. (@{
  1659. PROPERTY(results, ORKResult, NSArray, YES, nil, nil)
  1660. })),
  1661. ENTRY(ORKTaskResult,
  1662. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1663. return [[ORKTaskResult alloc] initWithTaskIdentifier:GETPROP(dict, identifier) taskRunUUID:GETPROP(dict, taskRunUUID) outputDirectory:GETPROP(dict, outputDirectory)];
  1664. },
  1665. (@{
  1666. PROPERTY(taskRunUUID, NSUUID, NSObject, NO,
  1667. ^id(id uuid) { return [uuid UUIDString]; },
  1668. ^id(id string) { return [[NSUUID alloc] initWithUUIDString:string]; }),
  1669. PROPERTY(outputDirectory, NSURL, NSObject, NO,
  1670. ^id(id url) { return [url absoluteString]; },
  1671. ^id(id string) { return [NSURL URLWithString:string]; })
  1672. })),
  1673. ENTRY(ORKStepResult,
  1674. nil,
  1675. (@{
  1676. PROPERTY(enabledAssistiveTechnology, NSString, NSObject, YES, nil, nil),
  1677. PROPERTY(isPreviousResult, NSNumber, NSObject, YES, nil, nil),
  1678. })),
  1679. ENTRY(ORKPageResult,
  1680. nil,
  1681. (@{
  1682. })),
  1683. ENTRY(ORKVideoInstructionStepResult,
  1684. nil,
  1685. (@{
  1686. PROPERTY(playbackStoppedTime, NSNumber, NSObject, YES, nil, nil),
  1687. PROPERTY(playbackCompleted, NSNumber, NSObject, YES, nil, nil),
  1688. })),
  1689. } mutableCopy];
  1690. if (@available(iOS 12.0, *)) {
  1691. [internalEncodingTable addEntriesFromDictionary:@{ ENTRY(ORKHealthClinicalTypeRecorderConfiguration,
  1692. ^id(NSDictionary *dict, ORKESerializationPropertyGetter getter) {
  1693. return [[ORKHealthClinicalTypeRecorderConfiguration alloc] initWithIdentifier:GETPROP(dict, identifier) healthClinicalType:GETPROP(dict, healthClinicalType) healthFHIRResourceType:GETPROP(dict, healthFHIRResourceType)];
  1694. },
  1695. (@{
  1696. PROPERTY(healthClinicalType, HKClinicalType, NSObject, NO,
  1697. ^id(id type) { return identifierFromClinicalType(type); },
  1698. ^id(id identifier) { return typeFromIdentifier(identifier); }),
  1699. PROPERTY(healthFHIRResourceType, NSString, NSObject, NO, nil, nil),
  1700. })) }];
  1701. }
  1702. });
  1703. return internalEncodingTable;
  1704. }
  1705. #undef GETPROP
  1706. static NSArray *classEncodingsForClass(Class c) {
  1707. NSDictionary *encodingTable = ORKESerializationEncodingTable();
  1708. NSMutableArray *classEncodings = [NSMutableArray array];
  1709. Class sc = c;
  1710. while (sc != nil) {
  1711. NSString *className = NSStringFromClass(sc);
  1712. ORKESerializableTableEntry *classEncoding = encodingTable[className];
  1713. if (classEncoding) {
  1714. [classEncodings addObject:classEncoding];
  1715. }
  1716. sc = [sc superclass];
  1717. }
  1718. return classEncodings;
  1719. }
  1720. static id objectForJsonObject(id input, Class expectedClass, ORKESerializationJSONToObjectBlock converterBlock, ORKESerializationLocalizer *localizer) {
  1721. id output = nil;
  1722. if (converterBlock != nil) {
  1723. input = converterBlock(input);
  1724. }
  1725. if (expectedClass != nil && [input isKindOfClass:expectedClass]) {
  1726. // Input is already of the expected class, do nothing
  1727. // Edge case for ORKAnswerFormat options. Certain formats (e.g. ORKTextChoiceAnswerFormat) contain
  1728. // text strings (e.g. 'Yes', 'No') that need to be localized but are already of the expected type.
  1729. if ([input isKindOfClass:[NSString class]] && localizer != nil) {
  1730. NSString *localizedValue = NSLocalizedStringFromTableInBundle((NSString *)input, localizer.tableName, localizer.bundle, nil);
  1731. output = localizedValue;
  1732. } else {
  1733. output = input;
  1734. }
  1735. } else if ([input isKindOfClass:[NSDictionary class]]) {
  1736. NSDictionary *dict = (NSDictionary *)input;
  1737. NSString *className = input[_ClassKey];
  1738. if (expectedClass != nil) {
  1739. NSCAssert([NSClassFromString(className) isSubclassOfClass:expectedClass], @"Expected subclass of %@ but got %@", expectedClass, className);
  1740. }
  1741. NSArray *classEncodings = classEncodingsForClass(NSClassFromString(className));
  1742. NSCAssert([classEncodings count] > 0, @"Expected serializable class but got %@", className);
  1743. ORKESerializableTableEntry *leafClassEncoding = classEncodings.firstObject;
  1744. ORKESerializationInitBlock initBlock = leafClassEncoding.initBlock;
  1745. BOOL writeAllProperties = YES;
  1746. if (initBlock != nil) {
  1747. output = initBlock(dict,
  1748. ^id(NSDictionary *propDict, NSString *param) {
  1749. return propFromDict(propDict, param, localizer); });
  1750. writeAllProperties = NO;
  1751. } else {
  1752. output = [[NSClassFromString(className) alloc] init];
  1753. }
  1754. for (NSString *key in [dict allKeys]) {
  1755. if ([key isEqualToString:_ClassKey]) {
  1756. continue;
  1757. }
  1758. BOOL haveSetProp = NO;
  1759. for (ORKESerializableTableEntry *encoding in classEncodings) {
  1760. NSDictionary *propertyTable = encoding.properties;
  1761. ORKESerializableProperty *propertyEntry = propertyTable[key];
  1762. if (propertyEntry != nil) {
  1763. // Only write the property if it has not already been set during init
  1764. if (writeAllProperties || propertyEntry.writeAfterInit) {
  1765. id property = propFromDict(dict, key, localizer);
  1766. if ((localizer != nil) && ([property isKindOfClass: [NSString class]])) {
  1767. // Keys that exist in the localization table will be localized.
  1768. //
  1769. // If the key is not found in the table the provided key string will be returned as is,
  1770. // supporting the expected functionality for inputs that contain both strings to be
  1771. // localized as well as strings to be displayed as is.
  1772. NSString *localizedValue = NSLocalizedStringFromTableInBundle((NSString *)property, localizer.tableName, localizer.bundle, nil);
  1773. [output setValue:localizedValue forKey:key];
  1774. } else {
  1775. [output setValue:property forKey:key];
  1776. }
  1777. }
  1778. haveSetProp = YES;
  1779. break;
  1780. }
  1781. }
  1782. NSCAssert(haveSetProp, @"Unexpected property on %@: %@", className, key);
  1783. }
  1784. } else {
  1785. NSCAssert(0, @"Unexpected input of class %@ for %@", [input class], expectedClass);
  1786. }
  1787. return output;
  1788. }
  1789. static BOOL isValid(id object) {
  1790. return [NSJSONSerialization isValidJSONObject:object] || [object isKindOfClass:[NSNumber class]] || [object isKindOfClass:[NSString class]] || [object isKindOfClass:[NSNull class]];
  1791. }
  1792. static id jsonObjectForObject(id object) {
  1793. if (object == nil) {
  1794. // Leaf: nil
  1795. return nil;
  1796. }
  1797. id jsonOutput = nil;
  1798. Class c = [object class];
  1799. NSArray *classEncodings = classEncodingsForClass(c);
  1800. if ([classEncodings count]) {
  1801. NSMutableDictionary *encodedDict = [NSMutableDictionary dictionary];
  1802. encodedDict[_ClassKey] = NSStringFromClass(c);
  1803. for (ORKESerializableTableEntry *encoding in classEncodings) {
  1804. NSDictionary *propertyTable = encoding.properties;
  1805. for (NSString *propertyName in [propertyTable allKeys]) {
  1806. ORKESerializableProperty *propertyEntry = propertyTable[propertyName];
  1807. ORKESerializationObjectToJSONBlock converter = propertyEntry.objectToJSONBlock;
  1808. Class containerClass = propertyEntry.containerClass;
  1809. id valueForKey = [object valueForKey:propertyName];
  1810. if (valueForKey != nil) {
  1811. if ([containerClass isSubclassOfClass:[NSArray class]]) {
  1812. NSMutableArray *a = [NSMutableArray array];
  1813. for (id valueItem in valueForKey) {
  1814. id outputItem;
  1815. if (converter != nil) {
  1816. outputItem = converter(valueItem);
  1817. NSCAssert(isValid(valueItem), @"Expected valid JSON object");
  1818. } else {
  1819. // Recurse for each property
  1820. outputItem = jsonObjectForObject(valueItem);
  1821. }
  1822. [a addObject:outputItem];
  1823. }
  1824. valueForKey = a;
  1825. } else {
  1826. if (converter != nil) {
  1827. valueForKey = converter(valueForKey);
  1828. NSCAssert((valueForKey == nil) || isValid(valueForKey), @"Expected valid JSON object");
  1829. } else {
  1830. // Recurse for each property
  1831. valueForKey = jsonObjectForObject(valueForKey);
  1832. }
  1833. }
  1834. }
  1835. if (valueForKey != nil) {
  1836. encodedDict[propertyName] = valueForKey;
  1837. }
  1838. }
  1839. }
  1840. jsonOutput = encodedDict;
  1841. } else if ([c isSubclassOfClass:[NSArray class]]) {
  1842. NSArray *inputArray = (NSArray *)object;
  1843. NSMutableArray *encodedArray = [NSMutableArray arrayWithCapacity:[inputArray count]];
  1844. for (id input in inputArray) {
  1845. // Recurse for each array element
  1846. [encodedArray addObject:jsonObjectForObject(input)];
  1847. }
  1848. jsonOutput = encodedArray;
  1849. } else if ([c isSubclassOfClass:[NSDictionary class]]) {
  1850. NSDictionary *inputDict = (NSDictionary *)object;
  1851. NSMutableDictionary *encodedDictionary = [NSMutableDictionary dictionaryWithCapacity:[inputDict count]];
  1852. for (NSString *key in [inputDict allKeys] ) {
  1853. // Recurse for each dictionary value
  1854. encodedDictionary[key] = jsonObjectForObject(inputDict[key]);
  1855. }
  1856. jsonOutput = encodedDictionary;
  1857. } else if (![c isSubclassOfClass:[NSPredicate class]]) { // Ignore NSPredicate which cannot be easily serialized for now
  1858. NSCAssert(isValid(object), @"Expected valid JSON object");
  1859. // Leaf: native JSON object
  1860. jsonOutput = object;
  1861. }
  1862. return jsonOutput;
  1863. }
  1864. + (NSDictionary *)JSONObjectForObject:(id)object error:(__unused NSError * __autoreleasing *)error {
  1865. id json = jsonObjectForObject(object);
  1866. return json;
  1867. }
  1868. + (id)objectFromJSONObject:(NSDictionary *)object error:(__unused NSError * __autoreleasing *)error {
  1869. return objectForJsonObject(object, nil, nil, nil);
  1870. }
  1871. + (id)objectFromJSONObject:(NSDictionary *)object localizer:(ORKESerializationLocalizer *)localizer error:(__unused NSError * __autoreleasing *)error {
  1872. return objectForJsonObject(object, nil, nil, localizer);
  1873. }
  1874. + (NSData *)JSONDataForObject:(id)object error:(NSError * __autoreleasing *)error {
  1875. id json = jsonObjectForObject(object);
  1876. return [NSJSONSerialization dataWithJSONObject:json options:(NSJSONWritingOptions)0 error:error];
  1877. }
  1878. + (id)objectFromJSONData:(NSData *)data error:(NSError * __autoreleasing *)error {
  1879. id json = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingOptions)0 error:error];
  1880. id ret = nil;
  1881. if (json != nil) {
  1882. ret = objectForJsonObject(json, nil, nil, nil);
  1883. }
  1884. return ret;
  1885. }
  1886. + (NSArray *)serializableClasses {
  1887. NSMutableArray *a = [NSMutableArray array];
  1888. NSDictionary *table = ORKESerializationEncodingTable();
  1889. for (NSString *key in [table allKeys]) {
  1890. [a addObject:NSClassFromString(key)];
  1891. }
  1892. return a;
  1893. }
  1894. @end
  1895. @implementation ORKESerializer(Registration)
  1896. + (void)registerSerializableClass:(Class)serializableClass
  1897. initBlock:(ORKESerializationInitBlock)initBlock {
  1898. NSMutableDictionary *encodingTable = ORKESerializationEncodingTable();
  1899. ORKESerializableTableEntry *entry = encodingTable[NSStringFromClass(serializableClass)];
  1900. if (entry) {
  1901. entry.class = serializableClass;
  1902. entry.initBlock = initBlock;
  1903. } else {
  1904. entry = [[ORKESerializableTableEntry alloc] initWithClass:serializableClass initBlock:initBlock properties:@{}];
  1905. encodingTable[NSStringFromClass(serializableClass)] = entry;
  1906. }
  1907. }
  1908. + (void)registerSerializableClassPropertyName:(NSString *)propertyName
  1909. forClass:(Class)serializableClass
  1910. valueClass:(Class)valueClass
  1911. containerClass:(Class)containerClass
  1912. writeAfterInit:(BOOL)writeAfterInit
  1913. objectToJSONBlock:(ORKESerializationObjectToJSONBlock)objectToJSON
  1914. jsonToObjectBlock:(ORKESerializationJSONToObjectBlock)jsonToObjectBlock {
  1915. NSMutableDictionary *encodingTable = ORKESerializationEncodingTable();
  1916. ORKESerializableTableEntry *entry = encodingTable[NSStringFromClass(serializableClass)];
  1917. if (!entry) {
  1918. entry = [[ORKESerializableTableEntry alloc] initWithClass:serializableClass initBlock:nil properties:@{}];
  1919. encodingTable[NSStringFromClass(serializableClass)] = entry;
  1920. }
  1921. ORKESerializableProperty *property = entry.properties[propertyName];
  1922. if (property == nil) {
  1923. property = [[ORKESerializableProperty alloc] initWithPropertyName:propertyName
  1924. valueClass:valueClass
  1925. containerClass:containerClass
  1926. writeAfterInit:writeAfterInit
  1927. objectToJSONBlock:objectToJSON
  1928. jsonToObjectBlock:jsonToObjectBlock];
  1929. entry.properties[propertyName] = property;
  1930. } else {
  1931. property.propertyName = propertyName;
  1932. property.valueClass = valueClass;
  1933. property.containerClass = containerClass;
  1934. property.writeAfterInit = writeAfterInit;
  1935. property.objectToJSONBlock = objectToJSON;
  1936. property.jsonToObjectBlock = jsonToObjectBlock;
  1937. }
  1938. }
  1939. @end