Nav apraksta

ORKESerialization.m 112KB

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