From 18003b0f31488c318e50fa9e89056f32f0a0e69e Mon Sep 17 00:00:00 2001 From: ashishn Date: Sat, 27 Sep 2025 20:26:10 +0530 Subject: [PATCH 1/3] Workaround to fix parsing when afterLiveQueryEvent is active on server --- ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift b/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift index 45eb2c54c..787205997 100644 --- a/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift +++ b/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift @@ -19,7 +19,10 @@ private func parseObject(_ objectDictionary: [String:AnyObject]) th throw LiveQueryErrors.InvalidJSONError(json: objectDictionary, expectedKey: "objectId") } - guard let object = PFDecoder.object().decode(objectDictionary) as? T else { + //workaround to fix missing __type key Decoder expects with value "Object" + var dict = objectDictionary + dict["__type"] = String("Object") as AnyObject + guard let object = PFDecoder.object().decode(dict) as? T else { throw LiveQueryErrors.InvalidJSONObject(json: objectDictionary, details: "cannot decode json into \(T.self)") } From eeebc5bbe34662d69d764bf498bcce63943b3f67 Mon Sep 17 00:00:00 2001 From: ashishn Date: Sun, 28 Sep 2025 13:18:14 +0530 Subject: [PATCH 2/3] LiveryQuery server response sends data or events in "object":jsonf= format but PFDecoder.m checks for __type key which is missing as shown in below example so this fix will add "__type ":"Object" key-value if dictionary has className and objectId representing PFObject. "object":{ "desc": "Technology", "createdAt": "2020-10-03T19:34:16.823Z", "updatedAt": "2025-09-27T17:55:02.360Z", "image_name": "technology.png", "className": "categories", "objectId": "kHnBntWHHW" }, "original": { "desc": "Technologyy", "createdAt": "2020-10-03T19:34:16.823Z", "updatedAt": "2025-09-27T17:54:10.800Z", "image_name": "technology.png", "className": "categories", "objectId": "kHnBntWHHW" } --- Parse/Parse/Source/PFDecoder.m | 7 +++++++ ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift | 6 +----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Parse/Parse/Source/PFDecoder.m b/Parse/Parse/Source/PFDecoder.m index 33054d609..d1f7f90b9 100644 --- a/Parse/Parse/Source/PFDecoder.m +++ b/Parse/Parse/Source/PFDecoder.m @@ -47,6 +47,13 @@ - (id)decodeDictionary:(NSDictionary *)dictionary { } NSString *type = dictionary[@"__type"]; + // Inject __type = @"Object" if missing but className/objectId present + if (!type && dictionary[@"className"] && dictionary[@"objectId"]) { + NSMutableDictionary *mutable = [dictionary mutableCopy]; + mutable[@"__type"] = @"Object"; + type = @"Object"; + dictionary = mutable; + } if (type) { if ([type isEqualToString:@"Date"]) { return [[PFDateFormatter sharedFormatter] dateFromString:dictionary[@"iso"]]; diff --git a/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift b/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift index 787205997..cd11e9ab9 100644 --- a/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift +++ b/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift @@ -18,11 +18,7 @@ private func parseObject(_ objectDictionary: [String:AnyObject]) th guard let _ = objectDictionary["objectId"] as? String else { throw LiveQueryErrors.InvalidJSONError(json: objectDictionary, expectedKey: "objectId") } - - //workaround to fix missing __type key Decoder expects with value "Object" - var dict = objectDictionary - dict["__type"] = String("Object") as AnyObject - guard let object = PFDecoder.object().decode(dict) as? T else { + guard let object = PFDecoder.object().decode(objectDictionary) as? T else { throw LiveQueryErrors.InvalidJSONObject(json: objectDictionary, details: "cannot decode json into \(T.self)") } From 07b9c629554eb4ac2dd98e6380a9caeb240e6c27 Mon Sep 17 00:00:00 2001 From: ashishn Date: Sun, 28 Sep 2025 16:58:35 +0530 Subject: [PATCH 3/3] Inject __type = @"Object" if missing but className/objectId present and on the presence of additional data fields so that bare pointer stubs continue to fall back to the legacy dictionary path. --- Parse/Parse/Source/PFDecoder.m | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Parse/Parse/Source/PFDecoder.m b/Parse/Parse/Source/PFDecoder.m index d1f7f90b9..7eb99dec7 100644 --- a/Parse/Parse/Source/PFDecoder.m +++ b/Parse/Parse/Source/PFDecoder.m @@ -47,13 +47,28 @@ - (id)decodeDictionary:(NSDictionary *)dictionary { } NSString *type = dictionary[@"__type"]; - // Inject __type = @"Object" if missing but className/objectId present + // Inject __type = @"Object" if missing but className/objectId present and on the presence of additional data fields so that bare pointer stubs continue to fall back to the legacy dictionary path. if (!type && dictionary[@"className"] && dictionary[@"objectId"]) { - NSMutableDictionary *mutable = [dictionary mutableCopy]; - mutable[@"__type"] = @"Object"; - type = @"Object"; - dictionary = mutable; - } + static NSSet *pointerKeys; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + pointerKeys = [NSSet setWithObjects:@"className", @"objectId", @"localId", nil]; + }); + BOOL hasAdditionalFields = NO; + for (NSString *key in dictionary) { + if (![pointerKeys containsObject:key]) { + hasAdditionalFields = YES; + break; + } + } + if (!hasAdditionalFields) { + return dictionary; + } + NSMutableDictionary *mutable = [dictionary mutableCopy]; + mutable[@"__type"] = @"Object"; + type = @"Object"; + dictionary = mutable; + } if (type) { if ([type isEqualToString:@"Date"]) { return [[PFDateFormatter sharedFormatter] dateFromString:dictionary[@"iso"]];