diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f50bfa7ca..286876617 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,7 @@ jobs: - test:facebook_utils:ios - test:twitter_utils:ios - test:parseui:all + - test:parse_live_query:all - package:release fail-fast: false runs-on: ${{ (matrix.script == 'package:release' && 'macos-11') || 'macos-12' }} diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Cartfile b/Cartfile index 4cc9402f3..19539dfd3 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1,5 @@ github "BoltsFramework/Bolts-ObjC" ~> 1.9.1 +github "BoltsFramework/Bolts-Swift" >= 1.5.0 github "facebook/facebook-ios-sdk" == 15.1.0 +github "daltoniam/Starscream" >= 4.0.4 diff --git a/Cartfile.resolved b/Cartfile.resolved index cea6faaa8..b0b344042 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,2 +1,4 @@ github "BoltsFramework/Bolts-ObjC" "1.9.1" +github "BoltsFramework/Bolts-Swift" "1.5.0" +github "daltoniam/Starscream" "4.0.4" github "facebook/facebook-ios-sdk" "v15.1.0" diff --git a/Package.resolved b/Package.resolved index b9cb840bb..8a581d81d 100644 --- a/Package.resolved +++ b/Package.resolved @@ -3,11 +3,20 @@ "pins": [ { "package": "Bolts", - "repositoryURL": "https://github.com/rocxteady/Bolts-ObjC", + "repositoryURL": "https://github.com/parse-community/Bolts-ObjC.git", "state": { "branch": null, - "revision": "0419586ce3df0a004fbf94533198132de9c9aa0a", - "version": null + "revision": "1eee96ad3bcfc8964c0a5815ce94f491eb6ac8c2", + "version": "1.10.0" + } + }, + { + "package": "BoltsSwift", + "repositoryURL": "https://github.com/BoltsFramework/Bolts-Swift.git", + "state": { + "branch": null, + "revision": "d8c07eee2045a13f34330c0a4664053b5176e3f0", + "version": "1.5.0" } }, { @@ -18,6 +27,15 @@ "revision": "7fd8a930a5b2c940a22efafe0e214ed0df671312", "version": "15.1.0" } + }, + { + "package": "Starscream", + "repositoryURL": "https://github.com/daltoniam/Starscream.git", + "state": { + "branch": null, + "revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21", + "version": "4.0.4" + } } ] }, diff --git a/Package.swift b/Package.swift index a81ae1796..668117b1e 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ let package = Package( name: "ParseObjC", defaultLocalization: "en", platforms: [.iOS(.v12), - .macOS(.v10_10), + .macOS(.v10_15), .tvOS(.v12), .watchOS(.v2)], products: [ @@ -14,10 +14,13 @@ let package = Package( .library(name: "ParseFacebookUtilsiOS", targets: ["ParseFacebookUtilsiOS"]), .library(name: "ParseFacebookUtilsTvOS", targets: ["ParseFacebookUtilsTvOS"]), .library(name: "ParseTwitterUtils", targets: ["ParseTwitterUtils"]), - .library(name: "ParseUI", targets: ["ParseUI"]) + .library(name: "ParseUI", targets: ["ParseUI"]), + .library(name: "ParseLiveQuery", targets: ["ParseLiveQuery"]) ], dependencies: [ .package(url: "https://github.com/parse-community/Bolts-ObjC.git", from: "1.10.0"), + .package(url: "https://github.com/BoltsFramework/Bolts-Swift.git", from: "1.5.0"), + .package(url: "https://github.com/daltoniam/Starscream.git", from: "4.0.4"), .package(url: "https://github.com/facebook/facebook-ios-sdk.git", from: "15.1.0") ], targets: [ @@ -37,7 +40,7 @@ let package = Package( .product(name: "FacebookCore", package: "facebook-ios-sdk", condition: .when(platforms: [.iOS, .tvOS])), .product(name: "FacebookLogin", package: "facebook-ios-sdk", condition: .when(platforms: [.iOS, .tvOS]))], path: "ParseFacebookUtils/ParseFacebookUtils", - exclude: ["exclude", "Resources/Info-tvOS.plist", "Resources/Info-iOS.plist"], + exclude: ["Resources/Info-tvOS.plist", "Resources/Info-iOS.plist"], resources: [.process("Resources")], publicHeadersPath: "Source"), .target(name: "ParseFacebookUtilsiOS", @@ -45,7 +48,7 @@ let package = Package( "ParseFacebookUtils" ], path: "ParseFacebookUtilsiOS/ParseFacebookUtilsiOS", - exclude: ["exclude", "Resources/Info-iOS.plist"], + exclude: ["Resources/Info-iOS.plist"], resources: [.process("Resources")], publicHeadersPath: "Source", cSettings: [.headerSearchPath("Internal/**")]), @@ -55,7 +58,7 @@ let package = Package( .product(name: "FacebookTV", package: "facebook-ios-sdk", condition: .when(platforms: [.tvOS])) ], path: "ParseFacebookUtilsTvOS/ParseFacebookUtilsTvOS", - exclude: ["exclude", "Resources/Info-tvOS.plist"], + exclude: ["Resources/Info-tvOS.plist"], resources: [.process("Resources")], publicHeadersPath: "Source", cSettings: [.headerSearchPath("Internal/**")]), @@ -78,5 +81,14 @@ let package = Package( resources: [.process("Resources")], publicHeadersPath: "Source", cSettings: [.headerSearchPath("Internal/**")]), + .target(name: "ParseLiveQuery", + dependencies: [ + .product(name: "BoltsSwift", package: "Bolts-Swift"), + "Starscream", + "ParseCore" + ], + path: "ParseLiveQuery/ParseLiveQuery", + exclude: ["Resources/Info.plist"], + resources: [.process("Resources")]) ] ) diff --git a/Parse.xcworkspace/contents.xcworkspacedata b/Parse.xcworkspace/contents.xcworkspacedata index 5a6b81197..0344fa5af 100644 --- a/Parse.xcworkspace/contents.xcworkspacedata +++ b/Parse.xcworkspace/contents.xcworkspacedata @@ -16,6 +16,9 @@ + + diff --git a/Parse/Parse.xcodeproj/project.pbxproj b/Parse/Parse.xcodeproj/project.pbxproj index 82e7d358d..0b665bcca 100644 --- a/Parse/Parse.xcodeproj/project.pbxproj +++ b/Parse/Parse.xcodeproj/project.pbxproj @@ -2962,6 +2962,69 @@ remoteGlobalIDString = 81C3821B19CCA89E0066284A; remoteInfo = "Parse-iOS"; }; + 9575FF1E299136C60057B4CE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9575FF10299136C60057B4CE /* Starscream.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 33CCF0921F5DDC030099B092; + remoteInfo = Starscream; + }; + 9575FF20299136C60057B4CE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9575FF10299136C60057B4CE /* Starscream.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 335FA2021F5DF71D00F6D2EC; + remoteInfo = "Starscream Tests"; + }; + 95AEEB192991373F00165C0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 87FEF3661A9085FA00C60678; + remoteInfo = "BoltsSwift-iOS"; + }; + 95AEEB1B2991373F00165C0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 87FEF3711A9085FA00C60678; + remoteInfo = "BoltsSwiftTests-iOS"; + }; + 95AEEB1D2991373F00165C0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81CC14EC1A9BE0A100B28F86; + remoteInfo = "BoltsSwift-macOS"; + }; + 95AEEB1F2991373F00165C0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81CC14F61A9BE0A100B28F86; + remoteInfo = "BoltsSwiftTests-macOS"; + }; + 95AEEB212991373F00165C0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 065894FF1C9A93B7000FDDA6; + remoteInfo = "BoltsSwift-tvOS"; + }; + 95AEEB232991373F00165C0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0658951B1C9A947B000FDDA6; + remoteInfo = "BoltsSwiftTests-tvOS"; + }; + 95AEEB252991373F00165C0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 065894E71C9A933B000FDDA6; + remoteInfo = "BoltsSwift-watchOS"; + }; BC105FC424C5D0C900295EF7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BC105FBA24C5D0C900295EF7 /* OCMock.xcodeproj */; @@ -3575,6 +3638,8 @@ 91DF24941A09BAF100CFC7D4 /* PFPinningEventuallyQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFPinningEventuallyQueue.h; sourceTree = ""; }; 91DF24951A09BAF100CFC7D4 /* PFPinningEventuallyQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFPinningEventuallyQueue.m; sourceTree = ""; }; 91DF24981A0B0FF200CFC7D4 /* PFEventuallyQueue_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFEventuallyQueue_Private.h; sourceTree = ""; }; + 9575FF10299136C60057B4CE /* Starscream.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Starscream.xcodeproj; path = ../Carthage/Checkouts/Starscream/Starscream.xcodeproj; sourceTree = ""; }; + 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = BoltsSwift.xcodeproj; path = "../Carthage/Checkouts/Bolts-Swift/BoltsSwift.xcodeproj"; sourceTree = ""; }; 97010FAC1630B18F00AB761E /* Parse.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Parse.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 97AA93B816780B7600445C2D /* Parse-OSX.Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Parse-OSX.Info.plist"; sourceTree = ""; }; 97E18AE41623835600B17A67 /* PFLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFLocationManager.h; sourceTree = ""; }; @@ -3872,6 +3937,8 @@ 7CE6ABDD292074C70054D9D2 /* AudioToolbox.framework */, 7CE6ABD2292074C10054D9D2 /* libsqlite3.tbd */, BC105FBA24C5D0C900295EF7 /* OCMock.xcodeproj */, + 9575FF10299136C60057B4CE /* Starscream.xcodeproj */, + 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */, 4A1351082027FCFB000F5FD5 /* Bolts.xcodeproj */, ); name = Frameworks; @@ -5148,6 +5215,29 @@ path = CurrentUserController; sourceTree = ""; }; + 9575FF11299136C60057B4CE /* Products */ = { + isa = PBXGroup; + children = ( + 9575FF1F299136C60057B4CE /* Starscream.framework */, + 9575FF21299136C60057B4CE /* Starscream Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 95AEEB102991373F00165C0D /* Products */ = { + isa = PBXGroup; + children = ( + 95AEEB1A2991373F00165C0D /* BoltsSwift.framework */, + 95AEEB1C2991373F00165C0D /* BoltsSwiftTests.xctest */, + 95AEEB1E2991373F00165C0D /* BoltsSwift.framework */, + 95AEEB202991373F00165C0D /* BoltsSwiftTests.xctest */, + 95AEEB222991373F00165C0D /* BoltsSwift.framework */, + 95AEEB242991373F00165C0D /* BoltsSwiftTests.xctest */, + 95AEEB262991373F00165C0D /* BoltsSwift.framework */, + ); + name = Products; + sourceTree = ""; + }; BC105FBB24C5D0C900295EF7 /* Products */ = { isa = PBXGroup; children = ( @@ -7076,10 +7166,18 @@ ProductGroup = 4A13517620281768000F5FD5 /* Products */; ProjectRef = 4A1351082027FCFB000F5FD5 /* Bolts.xcodeproj */; }, + { + ProductGroup = 95AEEB102991373F00165C0D /* Products */; + ProjectRef = 95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */; + }, { ProductGroup = BC105FBB24C5D0C900295EF7 /* Products */; ProjectRef = BC105FBA24C5D0C900295EF7 /* OCMock.xcodeproj */; }, + { + ProductGroup = 9575FF11299136C60057B4CE /* Products */; + ProjectRef = 9575FF10299136C60057B4CE /* Starscream.xcodeproj */; + }, ); projectRoot = ""; targets = ( @@ -7175,6 +7273,69 @@ remoteRef = 4A13519720281768000F5FD5 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 9575FF1F299136C60057B4CE /* Starscream.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Starscream.framework; + remoteRef = 9575FF1E299136C60057B4CE /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 9575FF21299136C60057B4CE /* Starscream Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "Starscream Tests.xctest"; + remoteRef = 9575FF20299136C60057B4CE /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95AEEB1A2991373F00165C0D /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95AEEB192991373F00165C0D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95AEEB1C2991373F00165C0D /* BoltsSwiftTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = BoltsSwiftTests.xctest; + remoteRef = 95AEEB1B2991373F00165C0D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95AEEB1E2991373F00165C0D /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95AEEB1D2991373F00165C0D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95AEEB202991373F00165C0D /* BoltsSwiftTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = BoltsSwiftTests.xctest; + remoteRef = 95AEEB1F2991373F00165C0D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95AEEB222991373F00165C0D /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95AEEB212991373F00165C0D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95AEEB242991373F00165C0D /* BoltsSwiftTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = BoltsSwiftTests.xctest; + remoteRef = 95AEEB232991373F00165C0D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95AEEB262991373F00165C0D /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95AEEB252991373F00165C0D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; BC105FC524C5D0C900295EF7 /* OCMock.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; @@ -8868,7 +9029,7 @@ CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; }; name = Debug; }; @@ -8885,7 +9046,7 @@ CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; @@ -9070,7 +9231,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = F55ABB5A1B4F39DA00A0ECD5 /* ParseUnitTests-macOS.xcconfig */; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.15; SWIFT_VERSION = 5.0; }; name = Debug; @@ -9079,7 +9240,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = F55ABB5A1B4F39DA00A0ECD5 /* ParseUnitTests-macOS.xcconfig */; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.15; SWIFT_VERSION = 5.0; }; name = Release; @@ -9098,7 +9259,7 @@ ); SUPPORTS_MACCATALYST = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 5.7; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -9116,7 +9277,7 @@ "@loader_path/Frameworks", ); SUPPORTS_MACCATALYST = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 5.7; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -9188,7 +9349,7 @@ baseConfigurationReference = F55ABB541B4F39DA00A0ECD5 /* Parse-macOS.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.15; }; name = Debug; }; @@ -9197,7 +9358,7 @@ baseConfigurationReference = F55ABB541B4F39DA00A0ECD5 /* Parse-macOS.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.15; }; name = Release; }; diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj new file mode 100644 index 000000000..c63e2bcbf --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj @@ -0,0 +1,393 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 395FFA7429D761B4006502C5 /* ParseLiveQuery.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 395FFA4429D75F1F006502C5 /* ParseLiveQuery.framework */; }; + F509D5461CA9E5B8007B15B0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F519CBB41CA9CA04005295C0 /* main.m */; }; + F509D5471CA9E5B8007B15B0 /* Message.m in Sources */ = {isa = PBXBuildFile; fileRef = F519CBBC1CA9CA2B005295C0 /* Message.m */; }; + F509D5481CA9E5B8007B15B0 /* Room.m in Sources */ = {isa = PBXBuildFile; fileRef = F519CBBF1CA9CA34005295C0 /* Room.m */; }; + F509D5491CA9E5B8007B15B0 /* ChatRoomManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F519CBCF1CA9CC4D005295C0 /* ChatRoomManager.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 395FFA4129D75F1F006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F5A9BFCA1BE0248D00E78326; + remoteInfo = "ParseLiveQuery-iOS"; + }; + 395FFA4329D75F1F006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F5903CEA1BD999C500C3EFFE; + remoteInfo = "ParseLiveQuery-OSX"; + }; + 395FFA4529D75F1F006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 708836722561F502005B32F0; + remoteInfo = "ParseLiveQuery-watchOS"; + }; + 395FFA4729D75F1F006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 708836942561F55B005B32F0; + remoteInfo = "ParseLiveQuery-tvOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ParseLiveQuery.xcodeproj; path = ../ParseLiveQuery.xcodeproj; sourceTree = ""; }; + F509D5321CA9E597007B15B0 /* LiveQueryDemo-ObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "LiveQueryDemo-ObjC.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + F509D5441CA9E5AF007B15B0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F519CBB41CA9CA04005295C0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + F519CBBB1CA9CA2B005295C0 /* Message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Message.h; sourceTree = ""; }; + F519CBBC1CA9CA2B005295C0 /* Message.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Message.m; sourceTree = ""; }; + F519CBBE1CA9CA34005295C0 /* Room.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Room.h; sourceTree = ""; }; + F519CBBF1CA9CA34005295C0 /* Room.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Room.m; sourceTree = ""; }; + F519CBCE1CA9CC4D005295C0 /* ChatRoomManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatRoomManager.h; sourceTree = ""; }; + F519CBCF1CA9CC4D005295C0 /* ChatRoomManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatRoomManager.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F509D52F1CA9E597007B15B0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 395FFA7429D761B4006502C5 /* ParseLiveQuery.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 395FFA3B29D75F1F006502C5 /* Products */ = { + isa = PBXGroup; + children = ( + 395FFA4229D75F1F006502C5 /* ParseLiveQuery.framework */, + 395FFA4429D75F1F006502C5 /* ParseLiveQuery.framework */, + 395FFA4629D75F1F006502C5 /* ParseLiveQuery_watchOS.framework */, + 395FFA4829D75F1F006502C5 /* ParseLiveQuery_tvOS.framework */, + ); + name = Products; + sourceTree = ""; + }; + E0B5CD933BEBE8518E7750F2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */, + ); + name = Frameworks; + sourceTree = ""; + }; + F519CBA81CA9CA04005295C0 = { + isa = PBXGroup; + children = ( + F519CBB31CA9CA04005295C0 /* LiveQueryDemo-ObjC */, + F519CBB21CA9CA04005295C0 /* Products */, + E0B5CD933BEBE8518E7750F2 /* Frameworks */, + ); + sourceTree = ""; + }; + F519CBB21CA9CA04005295C0 /* Products */ = { + isa = PBXGroup; + children = ( + F509D5321CA9E597007B15B0 /* LiveQueryDemo-ObjC.app */, + ); + name = Products; + sourceTree = ""; + }; + F519CBB31CA9CA04005295C0 /* LiveQueryDemo-ObjC */ = { + isa = PBXGroup; + children = ( + F509D5441CA9E5AF007B15B0 /* Info.plist */, + F519CBB41CA9CA04005295C0 /* main.m */, + F519CBBB1CA9CA2B005295C0 /* Message.h */, + F519CBBC1CA9CA2B005295C0 /* Message.m */, + F519CBBE1CA9CA34005295C0 /* Room.h */, + F519CBBF1CA9CA34005295C0 /* Room.m */, + F519CBCE1CA9CC4D005295C0 /* ChatRoomManager.h */, + F519CBCF1CA9CC4D005295C0 /* ChatRoomManager.m */, + ); + path = "LiveQueryDemo-ObjC"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F509D5311CA9E597007B15B0 /* LiveQueryDemo-ObjC */ = { + isa = PBXNativeTarget; + buildConfigurationList = F509D5431CA9E597007B15B0 /* Build configuration list for PBXNativeTarget "LiveQueryDemo-ObjC" */; + buildPhases = ( + F509D52E1CA9E597007B15B0 /* Sources */, + F509D52F1CA9E597007B15B0 /* Frameworks */, + F509D5301CA9E597007B15B0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "LiveQueryDemo-ObjC"; + productName = LiveQueryDemo; + productReference = F509D5321CA9E597007B15B0 /* LiveQueryDemo-ObjC.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F519CBA91CA9CA04005295C0 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = parse; + TargetAttributes = { + F509D5311CA9E597007B15B0 = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = F519CBAC1CA9CA04005295C0 /* Build configuration list for PBXProject "LiveQueryDemo-ObjC" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F519CBA81CA9CA04005295C0; + productRefGroup = F519CBB21CA9CA04005295C0 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 395FFA3B29D75F1F006502C5 /* Products */; + ProjectRef = 395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + F509D5311CA9E597007B15B0 /* LiveQueryDemo-ObjC */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 395FFA4229D75F1F006502C5 /* ParseLiveQuery.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery.framework; + remoteRef = 395FFA4129D75F1F006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 395FFA4429D75F1F006502C5 /* ParseLiveQuery.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery.framework; + remoteRef = 395FFA4329D75F1F006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 395FFA4629D75F1F006502C5 /* ParseLiveQuery_watchOS.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery_watchOS.framework; + remoteRef = 395FFA4529D75F1F006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 395FFA4829D75F1F006502C5 /* ParseLiveQuery_tvOS.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery_tvOS.framework; + remoteRef = 395FFA4729D75F1F006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + F509D5301CA9E597007B15B0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F509D52E1CA9E597007B15B0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F509D5491CA9E5B8007B15B0 /* ChatRoomManager.m in Sources */, + F509D5481CA9E5B8007B15B0 /* Room.m in Sources */, + F509D5461CA9E5B8007B15B0 /* main.m in Sources */, + F509D5471CA9E5B8007B15B0 /* Message.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + F509D5401CA9E597007B15B0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "$(SRCROOT)/LiveQueryDemo-ObjC/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.LiveQueryDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + F509D5411CA9E597007B15B0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "$(SRCROOT)/LiveQueryDemo-ObjC/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.LiveQueryDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; + F519CBB61CA9CA04005295C0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + F519CBB71CA9CA04005295C0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F509D5431CA9E597007B15B0 /* Build configuration list for PBXNativeTarget "LiveQueryDemo-ObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F509D5401CA9E597007B15B0 /* Debug */, + F509D5411CA9E597007B15B0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F519CBAC1CA9CA04005295C0 /* Build configuration list for PBXProject "LiveQueryDemo-ObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F519CBB61CA9CA04005295C0 /* Debug */, + F519CBB71CA9CA04005295C0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F519CBA91CA9CA04005295C0 /* Project object */; +} diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo-ObjC.xcscheme b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo-ObjC.xcscheme new file mode 100644 index 000000000..6e7915b7b --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo-ObjC.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/ChatRoomManager.h b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/ChatRoomManager.h new file mode 100644 index 000000000..a856ac609 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/ChatRoomManager.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +@import Foundation; +@import ParseCore; +@import ParseLiveQuery; + +#import "Message.h" + +NS_ASSUME_NONNULL_BEGIN + +@class ChatRoomManager; + +@protocol ChatRoomManagerDataSource + +- (PFQuery *)queryForChatRoomManager:(ChatRoomManager *)manager; +- (PFLiveQueryClient *)liveQueryClientForChatRoomManager:(ChatRoomManager *)manager; + +@end + +@protocol ChatRoomManagerDelegate + +- (void)chatRoomManager:(ChatRoomManager *)manager didReceiveMessage:(Message *)message; + +@end + +@interface ChatRoomManager : NSObject + +@property (nonatomic, assign, readonly, getter=isConnected) BOOL connected; +@property (nonatomic, weak, readonly) id dataSource; +@property (nonatomic, weak, readonly) id delegate; + +- (instancetype)initWithDataSource:(id)dataSource delegate:(id)delegate; + +- (void)connect; +- (void)disconnect; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/ChatRoomManager.m b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/ChatRoomManager.m new file mode 100644 index 000000000..59d19bc3a --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/ChatRoomManager.m @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ChatRoomManager.h" + +@interface ChatRoomManager() + +@property (nonatomic, strong) PFLiveQueryClient *client; +@property (nonatomic, strong) PFQuery *query; +@property (nonatomic, strong) PFLiveQuerySubscription *subscription; + +@end + +@implementation ChatRoomManager + +- (instancetype)initWithDataSource:(id)dataSource delegate:(id)delegate{ + self = [super init]; + if (!self) return self; + + _dataSource = dataSource; + _delegate = delegate; + + return self; +} + +- (BOOL)isConnected { + return self.subscription != nil; +} + +- (void)connect { + self.client = [self.dataSource liveQueryClientForChatRoomManager:self]; + self.query = [self.dataSource queryForChatRoomManager:self]; + + __weak typeof(self) weakSelf = self; + + self.subscription = [[self.client subscribeToQuery:self.query] addCreateHandler:^(PFQuery *query, PFObject *message) { + [weakSelf.delegate chatRoomManager:weakSelf didReceiveMessage:(Message *)message]; + }]; +} + +- (void)disconnect { + self.client = nil; + self.query = nil; + self.subscription = nil; +} + +@end diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Info.plist b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Info.plist new file mode 100644 index 000000000..56c22a6bf --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 Parse. All rights reserved. + NSPrincipalClass + NSApplication + + diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Message.h b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Message.h new file mode 100644 index 000000000..bdb98a620 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Message.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +@import ParseCore; + +NS_ASSUME_NONNULL_BEGIN + +@interface Message : PFObject + +@property (nullable, nonatomic, strong) PFUser *author; +@property (nullable, nonatomic, strong) NSString *authorName; +@property (nullable, nonatomic, strong) NSString *message; +@property (nullable, nonatomic, strong) PFObject *room; +@property (nullable, nonatomic, strong) NSString *roomName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Message.m b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Message.m new file mode 100644 index 000000000..68b1fc340 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Message.m @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "Message.h" + +@implementation Message + +@dynamic author, authorName, message, room, roomName; + ++ (NSString *)parseClassName { + return @"Message"; +} + +@end diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Room.h b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Room.h new file mode 100644 index 000000000..c368ad242 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Room.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface Room : PFObject + +@property (nullable, nonatomic, strong) NSString *name; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Room.m b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Room.m new file mode 100644 index 000000000..b4ebbb159 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/Room.m @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "Room.h" + +@implementation Room + +@dynamic name; + ++ (NSString *)parseClassName { + return @"Room"; +} + +@end diff --git a/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/main.m b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/main.m new file mode 100644 index 000000000..5a2f5e87e --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo-ObjC/main.m @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +@import Foundation; +@import ParseCore; +@import ParseLiveQuery; + +#import "ChatRoomManager.h" +#import "Message.h" +#import "Room.h" + +BFTask *AttemptLogin() { + puts("Enter username: "); + char buffer[1024]; + fgets(buffer, 1024, stdin); + + NSString *usernameInput = [NSString stringWithUTF8String:buffer]; + + NSString *prompt = [NSString stringWithFormat:@"Enter password for %@", usernameInput]; + NSString *passwordInput = [NSString stringWithUTF8String:getpass([prompt UTF8String])]; + + NSString *username = [usernameInput stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + NSString *password = [passwordInput stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + + return [[PFUser logInWithUsernameInBackground:username password:password] continueWithBlock:^id (BFTask *task) { + if (task.result) { + return task.result; + } + + puts("Login failed, please try again."); + return AttemptLogin(); + }]; +} + +BFTask *AttemptRoom() { + puts("Enter chat room to connect to: "); + char buffer[1024]; + fgets(buffer, 1024, stdin); + + NSString *roomName = [NSString stringWithUTF8String:buffer]; + + return [[[[Room query] whereKey:@"name" + equalTo:[roomName stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]] + getFirstObjectInBackground] + continueWithBlock:^id _Nullable(BFTask * _Nonnull task) { + if (task.result) { + return task.result; + } + + puts("Room not found, please try again."); + return AttemptRoom(); + }]; +} + +@interface ChatRoomHandler : NSObject + +@property (nonatomic, strong, readonly) Room *room; +@property (nonatomic, strong, readonly) PFLiveQueryClient *client; + +@end + +@implementation ChatRoomHandler + +- (instancetype)initWithRoom:(Room *)room { + self = [super init]; + if (!self) return self; + + _room = room; + _client = [[PFLiveQueryClient alloc] init]; + + return self; +} + +- (PFQuery *)queryForChatRoomManager:(ChatRoomManager *)manager { + return [[[Message query] whereKey:@"roomName" + equalTo:self.room.name] + orderByAscending:@"createdAt"]; +} + +- (PFLiveQueryClient *)liveQueryClientForChatRoomManager:(ChatRoomManager *)manager { + return _client; +} + +- (void)chatRoomManager:(ChatRoomManager *)manager didReceiveMessage:(Message *)message { + NSString *formatted = [NSString stringWithFormat:@"%@ %@ %@", message.createdAt, message.authorName, message.message]; + printf("%s\n", formatted.UTF8String); +} + +@end + +int main(int argc, const char * argv[]) { + @autoreleasepool { + [Message registerSubclass]; + [Room registerSubclass]; + + [Parse initializeWithConfiguration:[ParseClientConfiguration configurationWithBlock:^(id configuration) { + configuration.applicationId = @"myAppId"; +// configuration.clientKey = @"myClientKey"; + configuration.server = @"http://localhost:1337/parse"; + }]]; + + [[AttemptLogin() continueWithBlock:^id (BFTask *task) { + return AttemptRoom(); + }] continueWithBlock:^id (BFTask *task) { + Room *room = task.result; + ChatRoomHandler *handler = [[ChatRoomHandler alloc] initWithRoom:room]; + ChatRoomManager *manager = [[ChatRoomManager alloc] initWithDataSource:handler delegate:handler]; + + // Print out the previous messages + PFQuery *query = [handler queryForChatRoomManager:manager]; + [[query findObjectsInBackground] continueWithBlock:^id (BFTask *task) { + for (Message *message in task.result) { + [handler chatRoomManager:manager didReceiveMessage:message]; + } + + [manager connect]; + return nil; + }]; + + dispatch_io_t stdinChannel = dispatch_io_create(DISPATCH_IO_STREAM, STDIN_FILENO, dispatch_get_main_queue(), ^(int error) { + perror("dispatch_io_create"); + }); + + dispatch_io_set_low_water(stdinChannel, 1); + dispatch_io_read(stdinChannel, 0, SIZE_MAX, dispatch_get_main_queue(), ^(bool done, dispatch_data_t data, int error) { + NSString *messageText = [[[NSString alloc] initWithData:(NSData *)data + encoding:NSUTF8StringEncoding] + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + + Message *message = [[Message alloc] init]; + message.author = [PFUser currentUser]; + message.authorName = [PFUser currentUser].username; + message.message = messageText; + message.room = room; + message.roomName = room.name; + + [message saveInBackground]; + }); + + return nil; + }]; + + dispatch_main(); + } + + return 0; +} diff --git a/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.pbxproj b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.pbxproj new file mode 100644 index 000000000..115b5245d --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.pbxproj @@ -0,0 +1,389 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + F509D5291CA9E53D007B15B0 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59F85B61C9BB4B600566A29 /* Message.swift */; }; + F509D52A1CA9E53D007B15B0 /* Room.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59F85B71C9BB4B600566A29 /* Room.swift */; }; + F509D52B1CA9E53D007B15B0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59F85AF1C9BB48200566A29 /* main.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 395FFA9129D7740B006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA8A29D7740B006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F5A9BFCA1BE0248D00E78326; + remoteInfo = "ParseLiveQuery-iOS"; + }; + 395FFA9329D7740B006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA8A29D7740B006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F5903CEA1BD999C500C3EFFE; + remoteInfo = "ParseLiveQuery-OSX"; + }; + 395FFA9529D7740B006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA8A29D7740B006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 708836722561F502005B32F0; + remoteInfo = "ParseLiveQuery-watchOS"; + }; + 395FFA9729D7740B006502C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 395FFA8A29D7740B006502C5 /* ParseLiveQuery.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 708836942561F55B005B32F0; + remoteInfo = "ParseLiveQuery-tvOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 395FFA8A29D7740B006502C5 /* ParseLiveQuery.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ParseLiveQuery.xcodeproj; path = ../ParseLiveQuery.xcodeproj; sourceTree = ""; }; + F509D5171CA9E4AE007B15B0 /* LiveQueryDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LiveQueryDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F509D5241CA9E4AE007B15B0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F59F85AF1C9BB48200566A29 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + F59F85B61C9BB4B600566A29 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; + F59F85B71C9BB4B600566A29 /* Room.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Room.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F509D5141CA9E4AE007B15B0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2E2DAD338FCB65EC95CB7AA9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 395FFA8A29D7740B006502C5 /* ParseLiveQuery.xcodeproj */, + ); + name = Frameworks; + sourceTree = ""; + }; + 395FFA8B29D7740B006502C5 /* Products */ = { + isa = PBXGroup; + children = ( + 395FFA9229D7740B006502C5 /* ParseLiveQuery.framework */, + 395FFA9429D7740B006502C5 /* ParseLiveQuery.framework */, + 395FFA9629D7740B006502C5 /* ParseLiveQuery_watchOS.framework */, + 395FFA9829D7740B006502C5 /* ParseLiveQuery_tvOS.framework */, + ); + name = Products; + sourceTree = ""; + }; + F59F85A31C9BB48200566A29 = { + isa = PBXGroup; + children = ( + F59F85AE1C9BB48200566A29 /* LiveQueryDemo */, + F59F85AD1C9BB48200566A29 /* Products */, + 2E2DAD338FCB65EC95CB7AA9 /* Frameworks */, + ); + indentWidth = 4; + sourceTree = ""; + tabWidth = 4; + }; + F59F85AD1C9BB48200566A29 /* Products */ = { + isa = PBXGroup; + children = ( + F509D5171CA9E4AE007B15B0 /* LiveQueryDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + F59F85AE1C9BB48200566A29 /* LiveQueryDemo */ = { + isa = PBXGroup; + children = ( + F509D5241CA9E4AE007B15B0 /* Info.plist */, + F59F85B61C9BB4B600566A29 /* Message.swift */, + F59F85B71C9BB4B600566A29 /* Room.swift */, + F59F85AF1C9BB48200566A29 /* main.swift */, + ); + path = LiveQueryDemo; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F509D5161CA9E4AE007B15B0 /* LiveQueryDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = F509D5251CA9E4AE007B15B0 /* Build configuration list for PBXNativeTarget "LiveQueryDemo" */; + buildPhases = ( + F509D5131CA9E4AE007B15B0 /* Sources */, + F509D5141CA9E4AE007B15B0 /* Frameworks */, + F509D5151CA9E4AE007B15B0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = LiveQueryDemo; + productName = AppKitDemo; + productReference = F509D5171CA9E4AE007B15B0 /* LiveQueryDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F59F85A41C9BB48200566A29 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = Parse; + TargetAttributes = { + F509D5161CA9E4AE007B15B0 = { + CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = F59F85A71C9BB48200566A29 /* Build configuration list for PBXProject "LiveQueryDemo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F59F85A31C9BB48200566A29; + productRefGroup = F59F85AD1C9BB48200566A29 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 395FFA8B29D7740B006502C5 /* Products */; + ProjectRef = 395FFA8A29D7740B006502C5 /* ParseLiveQuery.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + F509D5161CA9E4AE007B15B0 /* LiveQueryDemo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 395FFA9229D7740B006502C5 /* ParseLiveQuery.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery.framework; + remoteRef = 395FFA9129D7740B006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 395FFA9429D7740B006502C5 /* ParseLiveQuery.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery.framework; + remoteRef = 395FFA9329D7740B006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 395FFA9629D7740B006502C5 /* ParseLiveQuery_watchOS.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery_watchOS.framework; + remoteRef = 395FFA9529D7740B006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 395FFA9829D7740B006502C5 /* ParseLiveQuery_tvOS.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ParseLiveQuery_tvOS.framework; + remoteRef = 395FFA9729D7740B006502C5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + F509D5151CA9E4AE007B15B0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F509D5131CA9E4AE007B15B0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F509D52A1CA9E53D007B15B0 /* Room.swift in Sources */, + F509D5291CA9E53D007B15B0 /* Message.swift in Sources */, + F509D52B1CA9E53D007B15B0 /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + F509D5261CA9E4AE007B15B0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "$(SRCROOT)/LiveQueryDemo/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.LiveQueryDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + F509D5271CA9E4AE007B15B0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "$(SRCROOT)/LiveQueryDemo/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.LiveQueryDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + F59F85B11C9BB48200566A29 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + F59F85B21C9BB48200566A29 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F509D5251CA9E4AE007B15B0 /* Build configuration list for PBXNativeTarget "LiveQueryDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F509D5261CA9E4AE007B15B0 /* Debug */, + F509D5271CA9E4AE007B15B0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F59F85A71C9BB48200566A29 /* Build configuration list for PBXProject "LiveQueryDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F59F85B11C9BB48200566A29 /* Debug */, + F59F85B21C9BB48200566A29 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F59F85A41C9BB48200566A29 /* Project object */; +} diff --git a/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo.xcscheme b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo.xcscheme new file mode 100644 index 000000000..5cba7a07e --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ParseLiveQuery/Examples/LiveQueryDemo/Info.plist b/ParseLiveQuery/Examples/LiveQueryDemo/Info.plist new file mode 100644 index 000000000..ce936cd93 --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo/Info.plist @@ -0,0 +1,37 @@ + + + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 Parse. All rights reserved. + NSPrincipalClass + NSApplication + + diff --git a/ParseLiveQuery/Examples/LiveQueryDemo/Message.swift b/ParseLiveQuery/Examples/LiveQueryDemo/Message.swift new file mode 100644 index 000000000..49c57752e --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo/Message.swift @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation +import ParseCore + +class Message: PFObject, PFSubclassing { + @NSManaged var author: PFUser? + @NSManaged var authorName: String? + @NSManaged var message: String? + @NSManaged var room: PFObject? + @NSManaged var roomName: String? + + class func parseClassName() -> String { + return "Message" + } +} diff --git a/ParseLiveQuery/Examples/LiveQueryDemo/Room.swift b/ParseLiveQuery/Examples/LiveQueryDemo/Room.swift new file mode 100644 index 000000000..b99a2982c --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo/Room.swift @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation +import ParseCore + +class Room: PFObject, PFSubclassing { + @NSManaged var name: String? + + static func parseClassName() -> String { + return "Room" + } +} diff --git a/ParseLiveQuery/Examples/LiveQueryDemo/main.swift b/ParseLiveQuery/Examples/LiveQueryDemo/main.swift new file mode 100644 index 000000000..78c2d1b8b --- /dev/null +++ b/ParseLiveQuery/Examples/LiveQueryDemo/main.swift @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation +import ParseCore +import ParseLiveQuery + +Message.registerSubclass() +Room.registerSubclass() + +Parse.initialize(with: ParseClientConfiguration { + $0.applicationId = "myAppId" +// $0.clientKey = "myClientKey" + $0.server = "http://localhost:1337/parse" + }) + +let liveQueryClient = ParseLiveQuery.Client() + +class ChatRoomManager { + fileprivate var currentChatRoom: Room? + fileprivate var subscription: Subscription? + + var connected: Bool { return currentChatRoom != nil } + var messagesQuery: PFQuery { + return (Message.query()? + .whereKey("roomName", equalTo: currentChatRoom!.name!) + .order(byAscending: "createdAt")) as! PFQuery + } + + func connectToChatRoom(_ room: String) { + if connected { + disconnectFromChatRoom() + } + + Room.query()?.whereKey("name", equalTo: room).getFirstObjectInBackground() + .continueOnSuccessWith(block: { task -> Any? in + self.currentChatRoom = task.result as? Room + print("Connected to room \(self.currentChatRoom?.name ?? "null")") + + self.printPriorMessages() + self.subscribeToUpdates() + + return nil + }) + } + + func disconnectFromChatRoom() { + liveQueryClient.unsubscribe(messagesQuery, handler: subscription!) + } + + func sendMessage(_ msg: String) { + let message = Message() + message.author = PFUser.current() + message.authorName = message.author?.username + message.message = msg + message.room = currentChatRoom + message.roomName = currentChatRoom?.name + + message.saveInBackground() + } + + func printPriorMessages() { + messagesQuery.findObjectsInBackground() + .continueOnSuccessWith(block: { task -> Any? in + (task.result as? [Message])?.forEach(self.printMessage) + + return nil + }) + } + + func subscribeToUpdates() { + subscription = liveQueryClient + .subscribe(messagesQuery) + .handle(Event.created) { _, message in + self.printMessage(message) + } + } + + fileprivate func printMessage(_ message: Message) { + let createdAt = message.createdAt ?? Date() + + print("\(createdAt) \(message.authorName ?? "unknown"): \(message.message ?? "")") + } +} + +class InputManager { + let stdinChannel = DispatchIO(__type: DispatchIO.StreamType.stream.rawValue, fd: STDIN_FILENO, queue: DispatchQueue.main) { _ in } + let chatManager: ChatRoomManager + + init(chatManager: ChatRoomManager) { + self.chatManager = chatManager + + stdinChannel.setLimit(lowWater: 1) + stdinChannel.read(offset: 0, length: Int.max, queue: DispatchQueue.main, ioHandler: handleInput) + } + + fileprivate func handleInput(_ done: Bool, data: DispatchData?, error: Int32) { + guard + let inputString = data?.withUnsafeBytes(body: {(b: UnsafePointer) -> String? in + return String(cString: b) + })?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) else { + return + } + + if chatManager.connected { + chatManager.sendMessage(inputString) + } else { + chatManager.connectToChatRoom(inputString) + } + } +} + +print("Enter username: ") + +let username = readLine()! +let password = "Enter password for \(username): ".withCString { + String(validatingUTF8: getpass($0))! +} + +let chatManager = ChatRoomManager() +let inputManager = InputManager(chatManager: chatManager) + +PFUser.logInWithUsername(inBackground: username, password: password) + .continueOnSuccessWith(block: { task -> Any? in + print("Enter chat room to connect to: ") + return nil +}) + +dispatchMain() diff --git a/ParseLiveQuery/ParseLiveQuery-tvOS/Info.plist b/ParseLiveQuery/ParseLiveQuery-tvOS/Info.plist new file mode 100644 index 000000000..b2b03b7e0 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery-tvOS/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 2.2.0 + CFBundleVersion + 2.2.0 + + diff --git a/ParseLiveQuery/ParseLiveQuery-tvOS/ParseLiveQuery_tvOS.h b/ParseLiveQuery/ParseLiveQuery-tvOS/ParseLiveQuery_tvOS.h new file mode 100644 index 000000000..8f067e906 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery-tvOS/ParseLiveQuery_tvOS.h @@ -0,0 +1,19 @@ +// +// ParseLiveQuery_tvOS.h +// ParseLiveQuery-tvOS +// +// Created by Corey Baker on 11/15/20. +// Copyright © 2020 Parse. All rights reserved. +// + +#import + +//! Project version number for ParseLiveQuery_tvOS. +FOUNDATION_EXPORT double ParseLiveQuery_tvOSVersionNumber; + +//! Project version string for ParseLiveQuery_tvOS. +FOUNDATION_EXPORT const unsigned char ParseLiveQuery_tvOSVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/ParseLiveQuery/ParseLiveQuery-watchOS/Info.plist b/ParseLiveQuery/ParseLiveQuery-watchOS/Info.plist new file mode 100644 index 000000000..b2b03b7e0 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery-watchOS/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 2.2.0 + CFBundleVersion + 2.2.0 + + diff --git a/ParseLiveQuery/ParseLiveQuery-watchOS/ParseLiveQuery_watchOS.h b/ParseLiveQuery/ParseLiveQuery-watchOS/ParseLiveQuery_watchOS.h new file mode 100644 index 000000000..47b493a8a --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery-watchOS/ParseLiveQuery_watchOS.h @@ -0,0 +1,19 @@ +// +// ParseLiveQuery_watchOS.h +// ParseLiveQuery-watchOS +// +// Created by Corey Baker on 11/15/20. +// Copyright © 2020 Parse. All rights reserved. +// + +#import + +//! Project version number for ParseLiveQuery_watchOS. +FOUNDATION_EXPORT double ParseLiveQuery_watchOSVersionNumber; + +//! Project version string for ParseLiveQuery_watchOS. +FOUNDATION_EXPORT const unsigned char ParseLiveQuery_watchOSVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.pbxproj b/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.pbxproj new file mode 100644 index 000000000..e4c06f74a --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.pbxproj @@ -0,0 +1,1373 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0632EDD41CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0632EDD31CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift */; }; + 0632EDD51CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0632EDD31CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift */; }; + 094AE9001E25AF3100F408BC /* libicucore.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 094AE8FF1E25AF3100F408BC /* libicucore.tbd */; }; + 09D80FE21E26C05200AC7A2D /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 09D80FE11E26C05200AC7A2D /* libsqlite3.tbd */; }; + 39506FFB2A304E6B007F9550 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39506FFA2A304E6B007F9550 /* Common.swift */; }; + 39506FFC2A3056B6007F9550 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39506FFA2A304E6B007F9550 /* Common.swift */; }; + 4A819D9D1D937866009C0F61 /* ObjCCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */; }; + 4A819D9E1D93786A009C0F61 /* ObjCCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */; }; + 708836762561F503005B32F0 /* ParseLiveQuery_watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 708836742561F503005B32F0 /* ParseLiveQuery_watchOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 708836982561F55B005B32F0 /* ParseLiveQuery_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 708836962561F55B005B32F0 /* ParseLiveQuery_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9595D6E429AFAB0700D9B731 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95E916A52995270900EFDB34 /* Starscream.framework */; }; + 9595D6E529AFAB0700D9B731 /* Starscream.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 95E916A52995270900EFDB34 /* Starscream.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9595D6E629AFAB3300D9B731 /* BoltsSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95E9168D299526F200EFDB34 /* BoltsSwift.framework */; }; + 9595D6E729AFAB3400D9B731 /* BoltsSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 95E9168D299526F200EFDB34 /* BoltsSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95E91676299526B200EFDB34 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 094AE9011E25AF3A00F408BC /* Foundation.framework */; }; + 95E91677299526B200EFDB34 /* Foundation.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 094AE9011E25AF3A00F408BC /* Foundation.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95E91678299526B300EFDB34 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09D80FDF1E26C04800AC7A2D /* AudioToolbox.framework */; }; + 95E91679299526B300EFDB34 /* AudioToolbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09D80FDF1E26C04800AC7A2D /* AudioToolbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95E9167A299526B500EFDB34 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 094AE9031E25AF4300F408BC /* Security.framework */; }; + 95E9167B299526B500EFDB34 /* Security.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 094AE9031E25AF4300F408BC /* Security.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95E9167C299526B900EFDB34 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09D80FDD1E26C03E00AC7A2D /* SystemConfiguration.framework */; }; + 95E9167D299526B900EFDB34 /* SystemConfiguration.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09D80FDD1E26C03E00AC7A2D /* SystemConfiguration.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95E916A82995272A00EFDB34 /* BoltsSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95E91689299526F200EFDB34 /* BoltsSwift.framework */; }; + 95E916A92995272A00EFDB34 /* BoltsSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 95E91689299526F200EFDB34 /* BoltsSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95E916AB2995273D00EFDB34 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95E916A52995270900EFDB34 /* Starscream.framework */; }; + 95E916AC2995273D00EFDB34 /* Starscream.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 95E916A52995270900EFDB34 /* Starscream.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95E916B12995279800EFDB34 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09D80FDF1E26C04800AC7A2D /* AudioToolbox.framework */; }; + 95E916B6299527DC00EFDB34 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09D80FDD1E26C03E00AC7A2D /* SystemConfiguration.framework */; }; + F534A5B21BDAFE0200CBD11A /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534A5B11BDAFE0200CBD11A /* Subscription.swift */; }; + F534A5B41BDB09CE00CBD11A /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534A5B31BDB09CE00CBD11A /* Operation.swift */; }; + F54D58B81C8E3446009F8D6C /* ClientPrivate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B71C8E3446009F8D6C /* ClientPrivate.swift */; }; + F59CA92F1C8E496200329737 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59CA92E1C8E496200329737 /* Errors.swift */; }; + F5A88F4A1C9B6EBA002F0E0D /* PFQuery+Subscribe.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A88F491C9B6EBA002F0E0D /* PFQuery+Subscribe.swift */; }; + F5A88F4E1C9B7341002F0E0D /* QueryEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5591BA91BD97BB70072F966 /* QueryEncoder.swift */; }; + F5A88F4F1C9B7341002F0E0D /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534A5B31BDB09CE00CBD11A /* Operation.swift */; }; + F5A88F501C9B7341002F0E0D /* ClientPrivate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B71C8E3446009F8D6C /* ClientPrivate.swift */; }; + F5A88F521C9B7341002F0E0D /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5591BA31BD720E10072F966 /* Client.swift */; }; + F5A88F531C9B7341002F0E0D /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534A5B11BDAFE0200CBD11A /* Subscription.swift */; }; + F5A88F551C9B7341002F0E0D /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59CA92E1C8E496200329737 /* Errors.swift */; }; + F5A88F561C9B7341002F0E0D /* PFQuery+Subscribe.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A88F491C9B6EBA002F0E0D /* PFQuery+Subscribe.swift */; }; + F5D965351BD99DA200C3AAFC /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5591BA31BD720E10072F966 /* Client.swift */; }; + F5D965381BD99DA200C3AAFC /* QueryEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5591BA91BD97BB70072F966 /* QueryEncoder.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 39B857B329D75AE00023ADB0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 39B8579E29D75AE00023ADB0 /* LiveQueryDemo-ObjC.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F509D5321CA9E597007B15B0; + remoteInfo = "LiveQueryDemo-ObjC"; + }; + 39B857B629D75AE00023ADB0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 39B8579A29D75AE00023ADB0 /* LiveQueryDemo.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F509D5171CA9E4AE007B15B0; + remoteInfo = LiveQueryDemo; + }; + 9595D6E229AFAAB400D9B731 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 97010FAB1630B18F00AB761E; + remoteInfo = "Parse-macOS"; + }; + 95E916602995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81C3821C19CCA89E0066284A; + remoteInfo = "Parse-iOS"; + }; + 95E916622995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81C5845D1C3B0A98000063C6; + remoteInfo = "Parse-iOS-Dynamic"; + }; + 95E916642995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 816F449B1A8E8933009CDB32; + remoteInfo = "ParseUnitTests-iOS"; + }; + 95E916662995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 97010FAC1630B18F00AB761E; + remoteInfo = "Parse-macOS"; + }; + 95E916682995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81C09F861AF97A490043B49C; + remoteInfo = "ParseUnitTests-macOS"; + }; + 95E9166A2995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 815F24151BD04D150054659F; + remoteInfo = "Parse-tvOS"; + }; + 95E9166C2995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81C585BF1C3B0AA1000063C6; + remoteInfo = "Parse-tvOS-Dynamic"; + }; + 95E9166E2995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 810156691BB3832700D7C7BD; + remoteInfo = "Parse-watchOS"; + }; + 95E916702995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81C5870F1C3B0AA9000063C6; + remoteInfo = "Parse-watchOS-Dynamic"; + }; + 95E916722995216A00EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 4AE33A0B1F5451AD0088DCA0; + remoteInfo = "ParseUnitTests-iOS-host"; + }; + 95E916742995217600EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 81C3821B19CCA89E0066284A; + remoteInfo = "Parse-iOS"; + }; + 95E91688299526F200EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 87FEF3661A9085FA00C60678; + remoteInfo = "BoltsSwift-iOS"; + }; + 95E9168A299526F200EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 87FEF3711A9085FA00C60678; + remoteInfo = "BoltsSwiftTests-iOS"; + }; + 95E9168C299526F200EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81CC14EC1A9BE0A100B28F86; + remoteInfo = "BoltsSwift-macOS"; + }; + 95E9168E299526F200EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 81CC14F61A9BE0A100B28F86; + remoteInfo = "BoltsSwiftTests-macOS"; + }; + 95E91690299526F200EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 065894FF1C9A93B7000FDDA6; + remoteInfo = "BoltsSwift-tvOS"; + }; + 95E91692299526F200EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0658951B1C9A947B000FDDA6; + remoteInfo = "BoltsSwiftTests-tvOS"; + }; + 95E91694299526F200EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 065894E71C9A933B000FDDA6; + remoteInfo = "BoltsSwift-watchOS"; + }; + 95E916A42995270900EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9169F2995270900EFDB34 /* Starscream.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 33CCF0921F5DDC030099B092; + remoteInfo = Starscream; + }; + 95E916A62995270900EFDB34 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 95E9169F2995270900EFDB34 /* Starscream.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 335FA2021F5DF71D00F6D2EC; + remoteInfo = "Starscream Tests"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 708836A22561F58F005B32F0 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 708836A52561F5A6005B32F0 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 9575FF0B299135220057B4CE /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 95E91677299526B200EFDB34 /* Foundation.framework in Embed Frameworks */, + 9595D6E729AFAB3400D9B731 /* BoltsSwift.framework in Embed Frameworks */, + 95E9167B299526B500EFDB34 /* Security.framework in Embed Frameworks */, + 95E9167D299526B900EFDB34 /* SystemConfiguration.framework in Embed Frameworks */, + 9595D6E529AFAB0700D9B731 /* Starscream.framework in Embed Frameworks */, + 95E91679299526B300EFDB34 /* AudioToolbox.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 1; + }; + 95E916AA2995272A00EFDB34 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 95E916A92995272A00EFDB34 /* BoltsSwift.framework in Embed Frameworks */, + 95E916AC2995273D00EFDB34 /* Starscream.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0632EDD31CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Parse+LiveQuery.swift"; sourceTree = ""; }; + 094AE8FF1E25AF3100F408BC /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = usr/lib/libicucore.tbd; sourceTree = SDKROOT; }; + 094AE9011E25AF3A00F408BC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 094AE9031E25AF4300F408BC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 09D80FDD1E26C03E00AC7A2D /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 09D80FDF1E26C04800AC7A2D /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + 09D80FE11E26C05200AC7A2D /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; + 39506FFA2A304E6B007F9550 /* Common.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = ""; }; + 39B8579A29D75AE00023ADB0 /* LiveQueryDemo.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = LiveQueryDemo.xcodeproj; sourceTree = ""; }; + 39B8579E29D75AE00023ADB0 /* LiveQueryDemo-ObjC.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = "LiveQueryDemo-ObjC.xcodeproj"; sourceTree = ""; }; + 708836722561F502005B32F0 /* ParseLiveQuery_watchOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseLiveQuery_watchOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 708836742561F503005B32F0 /* ParseLiveQuery_watchOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseLiveQuery_watchOS.h; sourceTree = ""; }; + 708836752561F503005B32F0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 708836942561F55B005B32F0 /* ParseLiveQuery_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseLiveQuery_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 708836962561F55B005B32F0 /* ParseLiveQuery_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseLiveQuery_tvOS.h; sourceTree = ""; }; + 708836972561F55B005B32F0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 95E916532995216A00EFDB34 /* Parse.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Parse.xcodeproj; path = ../Parse/Parse.xcodeproj; sourceTree = ""; }; + 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = BoltsSwift.xcodeproj; path = "../Carthage/Checkouts/Bolts-Swift/BoltsSwift.xcodeproj"; sourceTree = ""; }; + 95E9169F2995270900EFDB34 /* Starscream.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Starscream.xcodeproj; path = ../Carthage/Checkouts/Starscream/Starscream.xcodeproj; sourceTree = ""; }; + 95E916B2299527BD00EFDB34 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; }; + 95E916B4299527CC00EFDB34 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; + F5256FD31BD71F9A0052FB8A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F534A5B11BDAFE0200CBD11A /* Subscription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = ""; }; + F534A5B31BDB09CE00CBD11A /* Operation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operation.swift; sourceTree = ""; }; + F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjCCompat.swift; sourceTree = ""; }; + F54D58B71C8E3446009F8D6C /* ClientPrivate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClientPrivate.swift; sourceTree = ""; }; + F5591BA31BD720E10072F966 /* Client.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; + F5591BA91BD97BB70072F966 /* QueryEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryEncoder.swift; sourceTree = ""; }; + F5903CEA1BD999C500C3EFFE /* ParseLiveQuery.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseLiveQuery.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F59CA92E1C8E496200329737 /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = Internal/Errors.swift; sourceTree = ""; }; + F5A88F491C9B6EBA002F0E0D /* PFQuery+Subscribe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PFQuery+Subscribe.swift"; sourceTree = ""; }; + F5A9BFCA1BE0248D00E78326 /* ParseLiveQuery.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseLiveQuery.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7088366F2561F502005B32F0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 708836912561F55B005B32F0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5903CE61BD999C500C3EFFE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 09D80FE21E26C05200AC7A2D /* libsqlite3.tbd in Frameworks */, + 9595D6E629AFAB3300D9B731 /* BoltsSwift.framework in Frameworks */, + 9595D6E429AFAB0700D9B731 /* Starscream.framework in Frameworks */, + 95E91676299526B200EFDB34 /* Foundation.framework in Frameworks */, + 094AE9001E25AF3100F408BC /* libicucore.tbd in Frameworks */, + 95E9167A299526B500EFDB34 /* Security.framework in Frameworks */, + 95E9167C299526B900EFDB34 /* SystemConfiguration.framework in Frameworks */, + 95E91678299526B300EFDB34 /* AudioToolbox.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5A9BFC01BE0248D00E78326 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 95E916AB2995273D00EFDB34 /* Starscream.framework in Frameworks */, + 95E916A82995272A00EFDB34 /* BoltsSwift.framework in Frameworks */, + 95E916B6299527DC00EFDB34 /* SystemConfiguration.framework in Frameworks */, + 95E916B12995279800EFDB34 /* AudioToolbox.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0BD13CAB7945A6C1A2A7B613 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 95E916B4299527CC00EFDB34 /* NetworkExtension.framework */, + 95E916B2299527BD00EFDB34 /* Network.framework */, + 95E916532995216A00EFDB34 /* Parse.xcodeproj */, + 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */, + 95E9169F2995270900EFDB34 /* Starscream.xcodeproj */, + 09D80FDD1E26C03E00AC7A2D /* SystemConfiguration.framework */, + 09D80FDF1E26C04800AC7A2D /* AudioToolbox.framework */, + 09D80FE11E26C05200AC7A2D /* libsqlite3.tbd */, + 094AE9011E25AF3A00F408BC /* Foundation.framework */, + 094AE9031E25AF4300F408BC /* Security.framework */, + 094AE8FF1E25AF3100F408BC /* libicucore.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; + 39B8575929D6446C0023ADB0 /* Resources */ = { + isa = PBXGroup; + children = ( + F5256FD31BD71F9A0052FB8A /* Info.plist */, + ); + path = Resources; + sourceTree = ""; + }; + 39B8579429D75AE00023ADB0 /* Examples */ = { + isa = PBXGroup; + children = ( + 39B8579A29D75AE00023ADB0 /* LiveQueryDemo.xcodeproj */, + 39B8579E29D75AE00023ADB0 /* LiveQueryDemo-ObjC.xcodeproj */, + ); + path = Examples; + sourceTree = ""; + }; + 39B8579B29D75AE00023ADB0 /* Products */ = { + isa = PBXGroup; + children = ( + 39B857B729D75AE00023ADB0 /* LiveQueryDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + 39B8579F29D75AE00023ADB0 /* Products */ = { + isa = PBXGroup; + children = ( + 39B857B429D75AE00023ADB0 /* LiveQueryDemo-ObjC.app */, + ); + name = Products; + sourceTree = ""; + }; + 708836732561F503005B32F0 /* ParseLiveQuery-watchOS */ = { + isa = PBXGroup; + children = ( + 708836742561F503005B32F0 /* ParseLiveQuery_watchOS.h */, + 708836752561F503005B32F0 /* Info.plist */, + ); + path = "ParseLiveQuery-watchOS"; + sourceTree = ""; + }; + 708836952561F55B005B32F0 /* ParseLiveQuery-tvOS */ = { + isa = PBXGroup; + children = ( + 708836962561F55B005B32F0 /* ParseLiveQuery_tvOS.h */, + 708836972561F55B005B32F0 /* Info.plist */, + ); + path = "ParseLiveQuery-tvOS"; + sourceTree = ""; + }; + 95E916542995216A00EFDB34 /* Products */ = { + isa = PBXGroup; + children = ( + 95E916612995216A00EFDB34 /* Parse.framework */, + 95E916632995216A00EFDB34 /* Parse.framework */, + 95E916652995216A00EFDB34 /* ParseUnitTests-iOS.xctest */, + 95E916672995216A00EFDB34 /* Parse.framework */, + 95E916692995216A00EFDB34 /* ParseUnitTests-macOS.xctest */, + 95E9166B2995216A00EFDB34 /* Parse.framework */, + 95E9166D2995216A00EFDB34 /* Parse.framework */, + 95E9166F2995216A00EFDB34 /* Parse.framework */, + 95E916712995216A00EFDB34 /* Parse.framework */, + 95E916732995216A00EFDB34 /* ParseUnitTests-iOS-host.app */, + ); + name = Products; + sourceTree = ""; + }; + 95E9167F299526F200EFDB34 /* Products */ = { + isa = PBXGroup; + children = ( + 95E91689299526F200EFDB34 /* BoltsSwift.framework */, + 95E9168B299526F200EFDB34 /* BoltsSwiftTests.xctest */, + 95E9168D299526F200EFDB34 /* BoltsSwift.framework */, + 95E9168F299526F200EFDB34 /* BoltsSwiftTests.xctest */, + 95E91691299526F200EFDB34 /* BoltsSwift.framework */, + 95E91693299526F200EFDB34 /* BoltsSwiftTests.xctest */, + 95E91695299526F200EFDB34 /* BoltsSwift.framework */, + ); + name = Products; + sourceTree = ""; + }; + 95E916A02995270900EFDB34 /* Products */ = { + isa = PBXGroup; + children = ( + 95E916A52995270900EFDB34 /* Starscream.framework */, + 95E916A72995270900EFDB34 /* Starscream Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + F5256FC41BD71F9A0052FB8A = { + isa = PBXGroup; + children = ( + 39B8579429D75AE00023ADB0 /* Examples */, + F5256FD01BD71F9A0052FB8A /* ParseLiveQuery */, + 708836732561F503005B32F0 /* ParseLiveQuery-watchOS */, + 708836952561F55B005B32F0 /* ParseLiveQuery-tvOS */, + F5256FCF1BD71F9A0052FB8A /* Products */, + 0BD13CAB7945A6C1A2A7B613 /* Frameworks */, + ); + indentWidth = 4; + sourceTree = ""; + tabWidth = 4; + }; + F5256FCF1BD71F9A0052FB8A /* Products */ = { + isa = PBXGroup; + children = ( + F5903CEA1BD999C500C3EFFE /* ParseLiveQuery.framework */, + F5A9BFCA1BE0248D00E78326 /* ParseLiveQuery.framework */, + 708836722561F502005B32F0 /* ParseLiveQuery_watchOS.framework */, + 708836942561F55B005B32F0 /* ParseLiveQuery_tvOS.framework */, + ); + name = Products; + sourceTree = ""; + }; + F5256FD01BD71F9A0052FB8A /* ParseLiveQuery */ = { + isa = PBXGroup; + children = ( + F5DC9D381BD9BAFC00E8FF07 /* Internal */, + 39B8575929D6446C0023ADB0 /* Resources */, + F5591BA31BD720E10072F966 /* Client.swift */, + F534A5B11BDAFE0200CBD11A /* Subscription.swift */, + F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */, + F59CA92E1C8E496200329737 /* Errors.swift */, + 0632EDD31CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift */, + F5A88F491C9B6EBA002F0E0D /* PFQuery+Subscribe.swift */, + ); + path = ParseLiveQuery; + sourceTree = ""; + }; + F5DC9D381BD9BAFC00E8FF07 /* Internal */ = { + isa = PBXGroup; + children = ( + F5591BA91BD97BB70072F966 /* QueryEncoder.swift */, + 39506FFA2A304E6B007F9550 /* Common.swift */, + F534A5B31BDB09CE00CBD11A /* Operation.swift */, + F54D58B71C8E3446009F8D6C /* ClientPrivate.swift */, + ); + path = Internal; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 7088366D2561F502005B32F0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 708836762561F503005B32F0 /* ParseLiveQuery_watchOS.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7088368F2561F55B005B32F0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 708836982561F55B005B32F0 /* ParseLiveQuery_tvOS.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5903CE71BD999C500C3EFFE /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5A9BFC31BE0248D00E78326 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 708836712561F502005B32F0 /* ParseLiveQuery-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7088368B2561F503005B32F0 /* Build configuration list for PBXNativeTarget "ParseLiveQuery-watchOS" */; + buildPhases = ( + 7088366D2561F502005B32F0 /* Headers */, + 7088366E2561F502005B32F0 /* Sources */, + 7088366F2561F502005B32F0 /* Frameworks */, + 708836702561F502005B32F0 /* Resources */, + 708836A52561F5A6005B32F0 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ParseLiveQuery-watchOS"; + productName = "ParseLiveQuery-watchOS"; + productReference = 708836722561F502005B32F0 /* ParseLiveQuery_watchOS.framework */; + productType = "com.apple.product-type.framework"; + }; + 708836932561F55B005B32F0 /* ParseLiveQuery-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 708836992561F55B005B32F0 /* Build configuration list for PBXNativeTarget "ParseLiveQuery-tvOS" */; + buildPhases = ( + 7088368F2561F55B005B32F0 /* Headers */, + 708836902561F55B005B32F0 /* Sources */, + 708836912561F55B005B32F0 /* Frameworks */, + 708836922561F55B005B32F0 /* Resources */, + 708836A22561F58F005B32F0 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ParseLiveQuery-tvOS"; + productName = "ParseLiveQuery-tvOS"; + productReference = 708836942561F55B005B32F0 /* ParseLiveQuery_tvOS.framework */; + productType = "com.apple.product-type.framework"; + }; + F5903CE91BD999C500C3EFFE /* ParseLiveQuery-OSX */ = { + isa = PBXNativeTarget; + buildConfigurationList = F5903CEF1BD999C500C3EFFE /* Build configuration list for PBXNativeTarget "ParseLiveQuery-OSX" */; + buildPhases = ( + F5903CE51BD999C500C3EFFE /* Sources */, + F5903CE61BD999C500C3EFFE /* Frameworks */, + F5903CE71BD999C500C3EFFE /* Headers */, + F5903CE81BD999C500C3EFFE /* Resources */, + 9575FF0B299135220057B4CE /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 9595D6E329AFAAB400D9B731 /* PBXTargetDependency */, + ); + name = "ParseLiveQuery-OSX"; + productName = ParseLiveQuery; + productReference = F5903CEA1BD999C500C3EFFE /* ParseLiveQuery.framework */; + productType = "com.apple.product-type.framework"; + }; + F5A9BFB61BE0248D00E78326 /* ParseLiveQuery-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = F5A9BFC71BE0248D00E78326 /* Build configuration list for PBXNativeTarget "ParseLiveQuery-iOS" */; + buildPhases = ( + F5A9BFBA1BE0248D00E78326 /* Sources */, + F5A9BFC01BE0248D00E78326 /* Frameworks */, + F5A9BFC31BE0248D00E78326 /* Headers */, + F5A9BFC51BE0248D00E78326 /* Resources */, + 95E916AA2995272A00EFDB34 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 95E916752995217600EFDB34 /* PBXTargetDependency */, + ); + name = "ParseLiveQuery-iOS"; + productName = ParseLiveQuery; + productReference = F5A9BFCA1BE0248D00E78326 /* ParseLiveQuery.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F5256FC51BD71F9A0052FB8A /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = Parse; + TargetAttributes = { + 708836712561F502005B32F0 = { + CreatedOnToolsVersion = 12.2; + ProvisioningStyle = Automatic; + }; + 708836932561F55B005B32F0 = { + CreatedOnToolsVersion = 12.2; + ProvisioningStyle = Automatic; + }; + F5903CE91BD999C500C3EFFE = { + CreatedOnToolsVersion = 7.1; + LastSwiftMigration = 1100; + }; + F5A9BFB61BE0248D00E78326 = { + LastSwiftMigration = 1010; + }; + }; + }; + buildConfigurationList = F5256FC81BD71F9A0052FB8A /* Build configuration list for PBXProject "ParseLiveQuery" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F5256FC41BD71F9A0052FB8A; + productRefGroup = F5256FCF1BD71F9A0052FB8A /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 95E9167F299526F200EFDB34 /* Products */; + ProjectRef = 95E9167E299526F200EFDB34 /* BoltsSwift.xcodeproj */; + }, + { + ProductGroup = 39B8579F29D75AE00023ADB0 /* Products */; + ProjectRef = 39B8579E29D75AE00023ADB0 /* LiveQueryDemo-ObjC.xcodeproj */; + }, + { + ProductGroup = 39B8579B29D75AE00023ADB0 /* Products */; + ProjectRef = 39B8579A29D75AE00023ADB0 /* LiveQueryDemo.xcodeproj */; + }, + { + ProductGroup = 95E916542995216A00EFDB34 /* Products */; + ProjectRef = 95E916532995216A00EFDB34 /* Parse.xcodeproj */; + }, + { + ProductGroup = 95E916A02995270900EFDB34 /* Products */; + ProjectRef = 95E9169F2995270900EFDB34 /* Starscream.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + F5A9BFB61BE0248D00E78326 /* ParseLiveQuery-iOS */, + F5903CE91BD999C500C3EFFE /* ParseLiveQuery-OSX */, + 708836712561F502005B32F0 /* ParseLiveQuery-watchOS */, + 708836932561F55B005B32F0 /* ParseLiveQuery-tvOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 39B857B429D75AE00023ADB0 /* LiveQueryDemo-ObjC.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = "LiveQueryDemo-ObjC.app"; + remoteRef = 39B857B329D75AE00023ADB0 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 39B857B729D75AE00023ADB0 /* LiveQueryDemo.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = LiveQueryDemo.app; + remoteRef = 39B857B629D75AE00023ADB0 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916612995216A00EFDB34 /* Parse.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Parse.framework; + remoteRef = 95E916602995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916632995216A00EFDB34 /* Parse.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Parse.framework; + remoteRef = 95E916622995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916652995216A00EFDB34 /* ParseUnitTests-iOS.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "ParseUnitTests-iOS.xctest"; + remoteRef = 95E916642995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916672995216A00EFDB34 /* Parse.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Parse.framework; + remoteRef = 95E916662995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916692995216A00EFDB34 /* ParseUnitTests-macOS.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "ParseUnitTests-macOS.xctest"; + remoteRef = 95E916682995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E9166B2995216A00EFDB34 /* Parse.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Parse.framework; + remoteRef = 95E9166A2995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E9166D2995216A00EFDB34 /* Parse.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Parse.framework; + remoteRef = 95E9166C2995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E9166F2995216A00EFDB34 /* Parse.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Parse.framework; + remoteRef = 95E9166E2995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916712995216A00EFDB34 /* Parse.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Parse.framework; + remoteRef = 95E916702995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916732995216A00EFDB34 /* ParseUnitTests-iOS-host.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = "ParseUnitTests-iOS-host.app"; + remoteRef = 95E916722995216A00EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E91689299526F200EFDB34 /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95E91688299526F200EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E9168B299526F200EFDB34 /* BoltsSwiftTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = BoltsSwiftTests.xctest; + remoteRef = 95E9168A299526F200EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E9168D299526F200EFDB34 /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95E9168C299526F200EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E9168F299526F200EFDB34 /* BoltsSwiftTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = BoltsSwiftTests.xctest; + remoteRef = 95E9168E299526F200EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E91691299526F200EFDB34 /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95E91690299526F200EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E91693299526F200EFDB34 /* BoltsSwiftTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = BoltsSwiftTests.xctest; + remoteRef = 95E91692299526F200EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E91695299526F200EFDB34 /* BoltsSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = BoltsSwift.framework; + remoteRef = 95E91694299526F200EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916A52995270900EFDB34 /* Starscream.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Starscream.framework; + remoteRef = 95E916A42995270900EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 95E916A72995270900EFDB34 /* Starscream Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "Starscream Tests.xctest"; + remoteRef = 95E916A62995270900EFDB34 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 708836702561F502005B32F0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 708836922561F55B005B32F0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5903CE81BD999C500C3EFFE /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5A9BFC51BE0248D00E78326 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7088366E2561F502005B32F0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 708836902561F55B005B32F0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5903CE51BD999C500C3EFFE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F54D58B81C8E3446009F8D6C /* ClientPrivate.swift in Sources */, + F5D965351BD99DA200C3AAFC /* Client.swift in Sources */, + 0632EDD51CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */, + F5D965381BD99DA200C3AAFC /* QueryEncoder.swift in Sources */, + F534A5B21BDAFE0200CBD11A /* Subscription.swift in Sources */, + F59CA92F1C8E496200329737 /* Errors.swift in Sources */, + F534A5B41BDB09CE00CBD11A /* Operation.swift in Sources */, + F5A88F4A1C9B6EBA002F0E0D /* PFQuery+Subscribe.swift in Sources */, + 39506FFC2A3056B6007F9550 /* Common.swift in Sources */, + 4A819D9E1D93786A009C0F61 /* ObjCCompat.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5A9BFBA1BE0248D00E78326 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F5A88F531C9B7341002F0E0D /* Subscription.swift in Sources */, + 0632EDD41CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */, + F5A88F501C9B7341002F0E0D /* ClientPrivate.swift in Sources */, + F5A88F551C9B7341002F0E0D /* Errors.swift in Sources */, + F5A88F4E1C9B7341002F0E0D /* QueryEncoder.swift in Sources */, + F5A88F521C9B7341002F0E0D /* Client.swift in Sources */, + F5A88F4F1C9B7341002F0E0D /* Operation.swift in Sources */, + F5A88F561C9B7341002F0E0D /* PFQuery+Subscribe.swift in Sources */, + 39506FFB2A304E6B007F9550 /* Common.swift in Sources */, + 4A819D9D1D937866009C0F61 /* ObjCCompat.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 9595D6E329AFAAB400D9B731 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Parse-macOS"; + targetProxy = 9595D6E229AFAAB400D9B731 /* PBXContainerItemProxy */; + }; + 95E916752995217600EFDB34 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Parse-iOS"; + targetProxy = 95E916742995217600EFDB34 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 708836772561F503005B32F0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "ParseLiveQuery-watchOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 2.8.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.parse.livequery.watchos.ParseLiveQuery-watchOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 708836782561F503005B32F0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "ParseLiveQuery-watchOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 2.8.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.parse.livequery.watchos.ParseLiveQuery-watchOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 7088369A2561F55B005B32F0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "ParseLiveQuery-tvOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 2.8.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.parse.livequery.tvos.ParseLiveQuery-tvOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 10.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7088369B2561F55B005B32F0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "ParseLiveQuery-tvOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 2.8.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.parse.livequery.tvos.ParseLiveQuery-tvOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 10.0; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + F5256FE01BD71F9A0052FB8A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MACOSX_DEPLOYMENT_TARGET = 10.15; + ONLY_ACTIVE_ARCH = YES; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + F5256FE11BD71F9A0052FB8A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MACOSX_DEPLOYMENT_TARGET = 10.15; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; + F5903CF01BD999C500C3EFFE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGNING_REQUIRED = NO; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + EXCLUDED_ARCHS = ""; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = ParseLiveQuery/Resources/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MARKETING_VERSION = 2.8.1; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.livequery.osx; + PRODUCT_NAME = ParseLiveQuery; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + F5903CF11BD999C500C3EFFE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGNING_REQUIRED = NO; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + EXCLUDED_ARCHS = ""; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = ParseLiveQuery/Resources/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MARKETING_VERSION = 2.8.1; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.livequery.osx; + PRODUCT_NAME = ParseLiveQuery; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + F5A9BFC81BE0248D00E78326 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGNING_REQUIRED = NO; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + EXCLUDED_ARCHS = arm64; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = ParseLiveQuery/Resources/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + MARKETING_VERSION = 2.8.1; + OTHER_LDFLAGS = "-lsqlite3"; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.livequery.ios; + PRODUCT_NAME = ParseLiveQuery; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + F5A9BFC91BE0248D00E78326 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGNING_REQUIRED = NO; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + EXCLUDED_ARCHS = arm64; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = ParseLiveQuery/Resources/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + MARKETING_VERSION = 2.8.1; + OTHER_LDFLAGS = "-lsqlite3"; + PRODUCT_BUNDLE_IDENTIFIER = com.parse.livequery.ios; + PRODUCT_NAME = ParseLiveQuery; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7088368B2561F503005B32F0 /* Build configuration list for PBXNativeTarget "ParseLiveQuery-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 708836772561F503005B32F0 /* Debug */, + 708836782561F503005B32F0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 708836992561F55B005B32F0 /* Build configuration list for PBXNativeTarget "ParseLiveQuery-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7088369A2561F55B005B32F0 /* Debug */, + 7088369B2561F55B005B32F0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F5256FC81BD71F9A0052FB8A /* Build configuration list for PBXProject "ParseLiveQuery" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F5256FE01BD71F9A0052FB8A /* Debug */, + F5256FE11BD71F9A0052FB8A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F5903CEF1BD999C500C3EFFE /* Build configuration list for PBXNativeTarget "ParseLiveQuery-OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F5903CF01BD999C500C3EFFE /* Debug */, + F5903CF11BD999C500C3EFFE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F5A9BFC71BE0248D00E78326 /* Build configuration list for PBXNativeTarget "ParseLiveQuery-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F5A9BFC81BE0248D00E78326 /* Debug */, + F5A9BFC91BE0248D00E78326 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F5256FC51BD71F9A0052FB8A /* Project object */; +} diff --git a/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..71ce19170 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-OSX.xcscheme b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-OSX.xcscheme new file mode 100644 index 000000000..71c9ab194 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-OSX.xcscheme @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-iOS.xcscheme b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-iOS.xcscheme new file mode 100644 index 000000000..31b1f25f7 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-iOS.xcscheme @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-tvOS.xcscheme b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-tvOS.xcscheme new file mode 100644 index 000000000..8c4e08c92 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-tvOS.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-watchOS.xcscheme b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-watchOS.xcscheme new file mode 100644 index 000000000..25b3a19b0 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-watchOS.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ParseLiveQuery/ParseLiveQuery/Client.swift b/ParseLiveQuery/ParseLiveQuery/Client.swift new file mode 100644 index 000000000..7fdf7cb8a --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Client.swift @@ -0,0 +1,263 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation +import BoltsSwift +import Starscream + +/** + This is the 'advanced' view of live query subscriptions. It allows you to customize your subscriptions + to a live query server, have connections to multiple servers, cleanly handle disconnect and reconnect. + */ +@objc(PFLiveQueryClient) +open class Client: NSObject { + let host: URL + let applicationId: String + let clientKey: String? + + var socket: WebSocket? + public var shouldPrintWebSocketLog = true + public var shouldPrintWebSocketTrace = false + public var userDisconnected = false + var isConnecting = false + + // This allows us to easily plug in another request ID generation scheme, or more easily change the request id type + // if needed (technically this could be a string). + let requestIdGenerator: () -> RequestId + var subscriptions = [SubscriptionRecord]() + + let queue = DispatchQueue(label: "com.parse.livequery", attributes: []) + + /** + Creates a Client which automatically attempts to connect to the custom parse-server URL set in Parse.currentConfiguration(). + */ + public override convenience init() { + self.init(server: Parse.validatedCurrentConfiguration().server) + } + + /** + Creates a client which will connect to a specific server with an optional application id and client key + + - parameter server: The server to connect to + - parameter applicationId: The application id to use + - parameter clientKey: The client key to use + */ + @objc(initWithServer:applicationId:clientKey:) + public init(server: String, applicationId: String? = nil, clientKey: String? = nil) { + guard let cmpts = URLComponents(string: server) else { + fatalError("Server should be a valid URL.") + } + var components = cmpts + components.scheme = (components.scheme == "https" || components.scheme == "wss") ? "wss" : "ws" + + // Simple incrementing generator - can't use ++, that operator is deprecated! + var currentRequestId = 0 + requestIdGenerator = { + currentRequestId += 1 + return RequestId(value: currentRequestId) + } + + self.applicationId = applicationId ?? Parse.validatedCurrentConfiguration().applicationId! + self.clientKey = clientKey ?? Parse.validatedCurrentConfiguration().clientKey + + self.host = components.url! + } +} + +extension Client { + // Swift is lame and doesn't allow storage to directly be in extensions. + // So we create an inner struct to wrap it up. + fileprivate class Storage { + private static var __once: () = { + sharedStorage = Storage() + }() + static var onceToken: Int = 0 + static var sharedStorage: Storage! + static var shared: Storage { + _ = Storage.__once + return sharedStorage + } + + let queue: DispatchQueue = DispatchQueue(label: "com.parse.livequery.client.storage", attributes: []) + var client: Client? + } + + /// Gets or sets shared live query client to be used for default subscriptions + @objc(sharedClient) + public static var shared: Client! { + get { + let storage = Storage.shared + var client: Client? + storage.queue.sync { + client = storage.client + if client == nil { + let configuration = Parse.validatedCurrentConfiguration() + client = Client( + server: configuration.server, + applicationId: configuration.applicationId, + clientKey: configuration.clientKey + ) + storage.client = client + } + } + return client + } + set { + let storage = Storage.shared + storage.queue.sync { + storage.client = newValue + } + } + } +} + +extension Client { + /** + Registers a query for live updates, using the default subscription handler + + - parameter query: The query to register for updates. + - parameter subclassType: The subclass of PFObject to be used as the type of the Subscription. + This parameter can be automatically inferred from context most of the time + + - returns: The subscription that has just been registered + */ + public func subscribe( + _ query: PFQuery, + subclassType: T.Type = T.self + ) -> Subscription { + return subscribe(query, handler: Subscription()) + } + + /** + Registers a query for live updates, using a custom subscription handler + + - parameter query: The query to register for updates. + - parameter handler: A custom subscription handler. + + - returns: Your subscription handler, for easy chaining. + */ + public func subscribe( + _ query: PFQuery, + handler: T + ) -> T where T: SubscriptionHandling { + let subscriptionRecord = SubscriptionRecord( + query: query, + requestId: requestIdGenerator(), + handler: handler + ) + + self.subscriptions.append(subscriptionRecord) + + if socket != nil { + _ = self.sendOperationAsync(.subscribe(requestId: subscriptionRecord.requestId, query: query as! PFQuery, + sessionToken: PFUser.current()?.sessionToken)) + } else if !self.userDisconnected { + self.reconnect() + self.subscriptions.removeLast() + return self.subscribe(query, handler: handler) + } else { + NSLog("ParseLiveQuery: Warning: The client was explicitly disconnected! You must explicitly call .reconnect() in order to process your subscriptions.") + } + + return handler + } + + /** + Updates an existing subscription with a new query. + Upon completing the registration, the subscribe handler will be called with the new query + + - parameter handler: The specific handler to update. + - parameter query: The new query for that handler. + */ + public func update( + _ handler: T, + toQuery query: PFQuery + ) where T: SubscriptionHandling { + subscriptions = subscriptions.map { + if $0.subscriptionHandler === handler { + _ = sendOperationAsync(.update(requestId: $0.requestId, query: query as! PFQuery)) + return SubscriptionRecord(query: query, requestId: $0.requestId, handler: $0.subscriptionHandler as! T) + } + return $0 + } + } + + /** + Unsubscribes all current subscriptions for a given query. + + - parameter query: The query to unsubscribe from. + */ + @objc(unsubscribeFromQuery:) + public func unsubscribe(_ query: PFQuery) { + unsubscribe { $0.query == query } + } + + /** + Unsubscribes from a specific query-handler pair. + + - parameter query: The query to unsubscribe from. + - parameter handler: The specific handler to unsubscribe from. + */ + public func unsubscribe(_ query: PFQuery, handler: T) where T: SubscriptionHandling { + unsubscribe { $0.query == query && $0.subscriptionHandler === handler } + } + + func unsubscribe(matching matcher: @escaping (SubscriptionRecord) -> Bool) { + var temp = [SubscriptionRecord]() + subscriptions.forEach { + if matcher($0) { + _ = sendOperationAsync(.unsubscribe(requestId: $0.requestId)) + } else { + temp.append($0) + } + } + subscriptions = temp + } +} + +extension Client { + /** + Reconnects this client to the server. + + This will disconnect and resubscribe all existing subscriptions. This is not required to be called the first time + you use the client, and should usually only be called when an error occurs. + */ + @objc(reconnect) + public func reconnect() { + guard socket == nil || !isConnecting else { return } + socket?.disconnect() + socket = { + let socket = WebSocket(request: .init(url: host)) + socket.delegate = self + socket.callbackQueue = queue + socket.connect() + isConnecting = true + userDisconnected = false + return socket + }() + } + + /** + Explicitly disconnects this client from the server. + + This does not remove any subscriptions - if you `reconnect()` your existing subscriptions will be restored. + Use this if you wish to dispose of the live query client. + */ + @objc(disconnect) + public func disconnect() { + isConnecting = false + guard let socket = socket + else { + return + } + socket.disconnect() + self.socket = nil + userDisconnected = true + } +} diff --git a/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift b/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift new file mode 100644 index 000000000..83fab187a --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Internal/ClientPrivate.swift @@ -0,0 +1,280 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation +import Starscream +import BoltsSwift + +private func parseObject(_ objectDictionary: [String:AnyObject]) throws -> T { + guard let _ = objectDictionary["className"] as? String else { + throw LiveQueryErrors.InvalidJSONError(json: objectDictionary, expectedKey: "parseClassName") + } + guard let _ = objectDictionary["objectId"] as? String else { + throw LiveQueryErrors.InvalidJSONError(json: objectDictionary, expectedKey: "objectId") + } + + guard let object = PFDecoder.object().decode(objectDictionary) as? T else { + throw LiveQueryErrors.InvalidJSONObject(json: objectDictionary, details: "cannot decode json into \(T.self)") + } + + return object +} + +// --------------- +// MARK: Subscriptions +// --------------- + +extension Client { + class SubscriptionRecord { + var subscriptionHandler: AnyObject? + // HandlerClosure captures the generic type info passed into the constructor of SubscriptionRecord, + // and 'unwraps' it so that it can be used with just a 'PFObject' instance. + // Technically, this should be a compiler no-op, as no witness tables should be used as 'PFObject' currently inherits from NSObject. + // Should we make PFObject ever a native swift class without the backing Objective-C runtime however, + // this becomes extremely important to have, and makes a ton more sense than just unsafeBitCast-ing everywhere. + var eventHandlerClosure: (Event, Client) -> Void + var errorHandlerClosure: (Error, Client) -> Void + var subscribeHandlerClosure: (Client) -> Void + var unsubscribeHandlerClosure: (Client) -> Void + + let query: PFQuery + let requestId: RequestId + + init(query: PFQuery, requestId: RequestId, handler: T) where T:SubscriptionHandling { + self.query = query as! PFQuery + self.requestId = requestId + + subscriptionHandler = handler + + // This is needed because swift requires 'handlerClosure' to be fully initialized before we setup the + // capture list for the closure. + eventHandlerClosure = { _, _ in } + errorHandlerClosure = { _, _ in } + subscribeHandlerClosure = { _ in } + unsubscribeHandlerClosure = { _ in } + + eventHandlerClosure = { [weak self] event, client in + guard let handler = self?.subscriptionHandler as? T else { + return + } + + handler.didReceive(Event(event: event), forQuery: query, inClient: client) + } + + errorHandlerClosure = { [weak self] error, client in + guard let handler = self?.subscriptionHandler as? T else { + return + } + + handler.didEncounter(error, forQuery: query, inClient: client) + } + + subscribeHandlerClosure = { [weak self] client in + guard let handler = self?.subscriptionHandler as? T else { + return + } + + handler.didSubscribe(toQuery: query, inClient: client) + } + + unsubscribeHandlerClosure = { [weak self] client in + guard let handler = self?.subscriptionHandler as? T else { + return + } + + handler.didUnsubscribe(fromQuery: query, inClient: client) + } + } + } +} +extension Client { + // An opaque placeholder structed used to ensure that we type-safely create request IDs and don't shoot ourself in + // the foot with array indexes. + struct RequestId: Equatable { + let value: Int + + init(value: Int) { + self.value = value + } + } +} + +func == (first: Client.RequestId, second: Client.RequestId) -> Bool { + return first.value == second.value +} + +// --------------- +// MARK: Web Socket +// --------------- + +extension Client: WebSocketDelegate { + public func didReceive(event: WebSocketEvent, client: WebSocket) { + switch event { + + case .connected(_): + isConnecting = false + let sessionToken = PFUser.current()?.sessionToken ?? "" + _ = self.sendOperationAsync(.connect(applicationId: applicationId, sessionToken: sessionToken, clientKey: clientKey)) + case .disconnected(let reason, let code): + isConnecting = false + if shouldPrintWebSocketLog { NSLog("ParseLiveQuery: WebSocket did disconnect with error: \(reason) code:\(code)") } + + // TODO: Better retry logic, unless `disconnect()` was explicitly called + if !userDisconnected { + reconnect() + } + case .text(let text): + handleOperationAsync(text).continueWith { [weak self] task in + if let error = task.error, self?.shouldPrintWebSocketLog == true { + NSLog("ParseLiveQuery: Error processing message: \(error)") + } + } + case .binary(_): + if shouldPrintWebSocketLog { NSLog("ParseLiveQuery: Received binary data but we don't handle it...") } + case .error(let error): + NSLog("ParseLiveQuery: Error processing message: \(String(describing: error))") + case .viabilityChanged(let isViable): + if shouldPrintWebSocketLog { NSLog("ParseLiveQuery: WebSocket viability channged to \(isViable ? "" : "not-")viable") } + if !isViable { + isConnecting = false + } + // TODO: Better retry logic, unless `disconnect()` was explicitly called + if !userDisconnected, isViable { + reconnect() + } + case .reconnectSuggested(let isSuggested): + if shouldPrintWebSocketLog { NSLog("ParseLiveQuery: WebSocket reconnect is \(isSuggested ? "" : "not ")suggested") } + // TODO: Better retry logic, unless `disconnect()` was explicitly called + if !userDisconnected, isSuggested { + reconnect() + } + case .cancelled: + isConnecting = false + if shouldPrintWebSocketLog { NSLog("ParseLiveQuery: WebSocket connection cancelled...") } + // TODO: Better retry logic, unless `disconnect()` was explicitly called + if !userDisconnected { + reconnect() + } + case .pong(_): + if shouldPrintWebSocketLog { NSLog("ParseLiveQuery: Received pong but we don't handle it...") } + case .ping(_): + if shouldPrintWebSocketLog { NSLog("ParseLiveQuery: Received ping but we don't handle it...") } + } + } +} + +// ------------------- +// MARK: Operations +// ------------------- + +extension Event { + init(serverResponse: ServerResponse, requestId: inout Client.RequestId) throws { + switch serverResponse { + case .enter(let reqId, let object): + requestId = reqId + self = .entered(try parseObject(object)) + + case .leave(let reqId, let object): + requestId = reqId + self = .left(try parseObject(object)) + + case .create(let reqId, let object): + requestId = reqId + self = .created(try parseObject(object)) + + case .update(let reqId, let object): + requestId = reqId + self = .updated(try parseObject(object)) + + case .delete(let reqId, let object): + requestId = reqId + self = .deleted(try parseObject(object)) + + default: fatalError("Invalid state reached") + } + } +} + +extension Client { + fileprivate func subscriptionRecord(_ requestId: RequestId) -> SubscriptionRecord? { + guard + let recordIndex = self.subscriptions.firstIndex(where: { $0.requestId == requestId }) else { + return nil + } + let record = self.subscriptions[recordIndex] + return record.subscriptionHandler != nil ? record : nil + } + + func sendOperationAsync(_ operation: ClientOperation) -> Task { + return Task(.queue(queue)) { + let jsonEncoded = operation.JSONObjectRepresentation + let jsonData = try JSONSerialization.data(withJSONObject: jsonEncoded, options: JSONSerialization.WritingOptions(rawValue: 0)) + let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) + if self.shouldPrintWebSocketTrace { NSLog("ParseLiveQuery: Sending message: \(jsonString!)") } + self.socket?.write(string: jsonString!) + } + } + + func handleOperationAsync(_ string: String) -> Task { + return Task(.queue(queue)) { + if self.shouldPrintWebSocketTrace { NSLog("ParseLiveQuery: Received message: \(string)") } + guard + let jsonData = string.data(using: String.Encoding.utf8), + let jsonDecoded = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions(rawValue: 0)) + as? [String:AnyObject], + let response: ServerResponse = try? ServerResponse(json: jsonDecoded) + else { + throw LiveQueryErrors.InvalidResponseError(response: string) + } + + switch response { + case .connected: + let sessionToken = PFUser.current()?.sessionToken + self.subscriptions.forEach { + _ = self.sendOperationAsync(.subscribe(requestId: $0.requestId, query: $0.query, sessionToken: sessionToken)) + } + + case .redirect: + // TODO: Handle redirect. + break + + case .subscribed(let requestId): + self.subscriptionRecord(requestId)?.subscribeHandlerClosure(self) + + case .unsubscribed(let requestId): + guard + let recordIndex = self.subscriptions.firstIndex(where: { $0.requestId == requestId }) + else { + break + } + let record: SubscriptionRecord = self.subscriptions[recordIndex] + record.unsubscribeHandlerClosure(self) + self.subscriptions.remove(at: recordIndex) + + case .create, .delete, .enter, .leave, .update: + var requestId: RequestId = RequestId(value: 0) + guard + let event: Event = try? Event(serverResponse: response, requestId: &requestId), + let record = self.subscriptionRecord(requestId) + else { + break + } + record.eventHandlerClosure(event, self) + + case .error(let requestId, let code, let error, let reconnect): + let error = LiveQueryErrors.ServerReportedError(code: code, error: error, reconnect: reconnect) + if let requestId = requestId { + self.subscriptionRecord(requestId)?.errorHandlerClosure(error, self) + } else { + throw error + } + } + } + } +} diff --git a/ParseLiveQuery/ParseLiveQuery/Internal/Common.swift b/ParseLiveQuery/ParseLiveQuery/Internal/Common.swift new file mode 100644 index 000000000..673ecc16a --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Internal/Common.swift @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + * Add support for both SPM and Dynamic Framework Imports TODO: (@dplewis) + */ +#if canImport(ParseCore) + @_exported import ParseCore +#else + @_exported import Parse +#endif diff --git a/ParseLiveQuery/ParseLiveQuery/Internal/Errors.swift b/ParseLiveQuery/ParseLiveQuery/Internal/Errors.swift new file mode 100644 index 000000000..d657a1f48 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Internal/Errors.swift @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + Namespace struct for all errors reported by the Live Query SDK. + */ +public struct LiveQueryErrors { + fileprivate init() {} + + /** + An error that is reported when the server returns a response that cannot be parsed. + */ + public struct InvalidResponseError: Error { + /// Response string of the error. + public let response: String + } + + /** + An error that is reported when the server does not accept a query we've sent to it. + */ + public struct InvalidQueryError: Error { + } + + /** + An error that is reported when the server returns valid JSON, but it doesn't match the format we expect. + */ + public struct InvalidJSONError: Error { + /// JSON used for matching. + public let json: [String:AnyObject] + /// Key that was expected to match. + public let expectedKey: String + } + + /** + An error that is reported when the server returns valid JSON, but it doesn't match the format we expect. + */ + public struct InvalidJSONObject: Error { + /// JSON used for matching. + public let json: [String:AnyObject] + /// Details about the error + public let details: String + } + + /** + An error that is reported when the live query server encounters an internal error. + */ + public struct ServerReportedError: Error { + /// Error code reported by the server. + public let code: Int + /// String error reported by the server. + public let error: String + /// Boolean value representing whether a client should reconnect. + public let reconnect: Bool + } +} diff --git a/ParseLiveQuery/ParseLiveQuery/Internal/Operation.swift b/ParseLiveQuery/ParseLiveQuery/Internal/Operation.swift new file mode 100644 index 000000000..ba6325847 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Internal/Operation.swift @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +enum ClientOperation { + case connect(applicationId: String, sessionToken: String, clientKey: String?) + case subscribe(requestId: Client.RequestId, query: PFQuery, sessionToken: String?) + case update(requestId: Client.RequestId, query: PFQuery) + case unsubscribe(requestId: Client.RequestId) + + var JSONObjectRepresentation: [String : Any] { + switch self { + case .connect(let applicationId, let sessionToken, let clientKey): + var message: [String: Any] = [ "op": "connect", "applicationId": applicationId, "sessionToken": sessionToken ] + if let clientKey = clientKey { + message.updateValue(clientKey, forKey: "clientKey") + } + return message + + case .subscribe(let requestId, let query, let sessionToken): + var result: [String: Any] = [ "op": "subscribe", "requestId": requestId.value, "query": Dictionary(query: query) ] + if let sessionToken = sessionToken { + result["sessionToken"] = sessionToken + } + return result + + case .update(let requestId, let query): + return [ "op": "update", "requestId": requestId.value, "query": Dictionary(query: query) ] + + case .unsubscribe(let requestId): + return [ "op": "unsubscribe", "requestId": requestId.value ] + } + } +} + +enum ServerResponse { + case redirect(url: String) + case connected + + case subscribed(requestId: Client.RequestId) + case unsubscribed(requestId: Client.RequestId) + + case enter(requestId: Client.RequestId, object: [String : AnyObject]) + case leave(requestId: Client.RequestId, object: [String : AnyObject]) + case update(requestId: Client.RequestId, object: [String : AnyObject]) + case create(requestId: Client.RequestId, object: [String : AnyObject]) + case delete(requestId: Client.RequestId, object: [String : AnyObject]) + + case error(requestId: Client.RequestId?, code: Int, error: String, reconnect: Bool) + + init(json: [String : AnyObject]) throws { + func jsonValue(_ json: [String:AnyObject], _ key: String) throws -> T { + guard let value = json[key] as? T + else { + throw LiveQueryErrors.InvalidJSONError(json: json, expectedKey: key) + } + return value + } + + func jsonRequestId(_ json: [String:AnyObject]) throws -> Client.RequestId { + let requestId: Int = try jsonValue(json, "requestId") + return Client.RequestId(value: requestId) + } + + func subscriptionEvent( + _ json: [String:AnyObject], + _ eventType: (Client.RequestId, [String : AnyObject]) -> ServerResponse + ) throws -> ServerResponse { + return eventType(try jsonRequestId(json), try jsonValue(json, "object")) + } + + let rawOperation: String = try jsonValue(json, "op") + switch rawOperation { + case "connected": + self = .connected + + case "redirect": + self = .redirect(url: try jsonValue(json, "url")) + + case "subscribed": + self = .subscribed(requestId: try jsonRequestId(json)) + case "unsubscribed": + self = .unsubscribed(requestId: try jsonRequestId(json)) + + case "enter": self = try subscriptionEvent(json, ServerResponse.enter) + case "leave": self = try subscriptionEvent(json, ServerResponse.leave) + case "update": self = try subscriptionEvent(json, ServerResponse.update) + case "create": self = try subscriptionEvent(json, ServerResponse.create) + case "delete": self = try subscriptionEvent(json, ServerResponse.delete) + + case "error": + self = .error( + requestId: try? jsonRequestId(json), + code: try jsonValue(json, "code"), + error: try jsonValue(json, "error"), + reconnect: try jsonValue(json, "reconnect") + ) + + default: + throw LiveQueryErrors.InvalidJSONError(json: json, expectedKey: "op") + } + } +} diff --git a/ParseLiveQuery/ParseLiveQuery/Internal/QueryEncoder.swift b/ParseLiveQuery/ParseLiveQuery/Internal/QueryEncoder.swift new file mode 100644 index 000000000..8d84f0e6c --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Internal/QueryEncoder.swift @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +/** + NOTE: This is super hacky, and we need a better answer for this. + */ +extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject { + init(query: PFQuery) { + self.init() + let queryState = query.value(forKey: "state") as AnyObject? + if let className = queryState?.value(forKey: "parseClassName") { + self["className"] = className as? Value + } + if let conditions = queryState?.value(forKey: "conditions") as? [String:AnyObject] { + self["where"] = conditions.encodedQueryDictionary as? Value + } else { + self["where"] = [:] as? Value + } + } +} + +extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject { + var encodedQueryDictionary: Dictionary { + var encodedQueryDictionary = Dictionary() + for (key, val) in self { + if let array = val as? [PFQuery] { + var queries:[Value] = [] + for query in array { + let queryState = query.value(forKey: "state") as AnyObject? + if let conditions: [String:AnyObject] = queryState?.value(forKey: "conditions") as? [String:AnyObject], let encoded = conditions.encodedQueryDictionary as? Value { + queries.append(encoded) + } + } + encodedQueryDictionary[key] = queries as? Value + } else if let geoPoints = val as? [PFGeoPoint] { + var points:[Value] = [] + for point in geoPoints { + points.append(point.encodedDictionary as! Value) + } + encodedQueryDictionary[key] = points as? Value + } else if let dict = val as? [String:AnyObject] { + encodedQueryDictionary[key] = dict.encodedQueryDictionary as? Value + } else if let geoPoint = val as? PFGeoPoint { + encodedQueryDictionary[key] = geoPoint.encodedDictionary as? Value + } else if let object = val as? PFObject { + encodedQueryDictionary[key] = (try? PFPointerObjectEncoder.object().encode(object)) as? Value + } else if let query = val as? PFQuery { + let queryState = query.value(forKey: "state") as AnyObject? + if let conditions: [String:AnyObject] = queryState?.value(forKey: "conditions") as? [String:AnyObject], let encoded = conditions.encodedQueryDictionary as? Value { + encodedQueryDictionary[key] = encoded + } + } else if let date = val as? Date { + encodedQueryDictionary[key] = ["__type": "Date", "iso": date.encodedString] as? Value + } else { + encodedQueryDictionary[key] = val + } + } + return encodedQueryDictionary + } +} + +extension PFGeoPoint { + var encodedDictionary: [String:Any] { + return ["__type": "GeoPoint", + "latitude": latitude, + "longitude": longitude] + } +} + +fileprivate extension Formatter { + static let iso8601: DateFormatter = { + let formatter = DateFormatter() + formatter.calendar = Calendar(identifier: .iso8601) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" + return formatter + }() +} + +fileprivate extension Date { + var encodedString: String { + return Formatter.iso8601.string(from: self) + } +} diff --git a/ParseLiveQuery/ParseLiveQuery/ObjCCompat.swift b/ParseLiveQuery/ParseLiveQuery/ObjCCompat.swift new file mode 100644 index 000000000..26ab1e192 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/ObjCCompat.swift @@ -0,0 +1,367 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation +import BoltsSwift + +/** + This protocol describes the interface for handling events from a live query client. + + You can use this protocol on any custom class of yours, instead of Subscription, if it fits your use case better. + */ +@objc(PFLiveQuerySubscriptionHandling) +public protocol ObjCCompat_SubscriptionHandling { + + /** + Tells the handler that an event has been received from the live query server. + + - parameter query: The query that the event occurred on. + - parameter event: The event that has been recieved from the server. + - parameter client: The live query client which received this event. + */ + @objc(liveQuery:didRecieveEvent:inClient:) + optional func didRecieveEvent(_ query: PFQuery, event: PFLiveQueryEvent, client: Client) + + /** + Tells the handler that an error has been received from the live query server. + + - parameter query: The query that the error occurred on. + - parameter error: The error that the server has encountered. + - parameter client: The live query client which received this error. + */ + @objc(liveQuery:didEncounterError:inClient:) + optional func didRecieveError(_ query: PFQuery, error: NSError, client: Client) + + /** + Tells the handler that a query has been successfully registered with the server. + + - note: This may be invoked multiple times if the client disconnects/reconnects. + + - parameter query: The query that has been subscribed. + - parameter client: The live query client which subscribed this query. + */ + @objc(liveQuery:didSubscribeInClient:) + optional func didSubscribe(_ query: PFQuery, client: Client) + + /** + Tells the handler that a query has been successfully deregistered from the server. + + - note: This is not called unless `unregister()` is explicitly called. + + - parameter query: The query that has been unsubscribed. + - parameter client: The live query client which unsubscribed this query. + */ + @objc(liveQuery:didUnsubscribeInClient:) + optional func didUnsubscribe(_ query: PFQuery, client: Client) +} + +// HACK: Compiler bug causes enums (and sometimes classes) that are declared in structs that are marked as @objc +// to not actually be emitted by the compiler (lolwut?). Moving this to global scope fixes the problem, but we can't +// change the objc name of an enum either, so we pollute the swift namespace here. +// TODO: Fix this eventually. + +/** + A type of an update event on a specific object from the live query server. + */ +@objc +public enum PFLiveQueryEventType: Int { + /// The object has been updated, and is now included in the query. + case entered + /// The object has been updated, and is no longer included in the query. + case left + /// The object has been created, and is a part of the query. + case created + /// The object has been updated, and is still a part of the query. + case updated + /// The object has been deleted, and is no longer included in the query. + case deleted +} + +/** + Represents an update on a specific object from the live query server. + */ +@objc +open class PFLiveQueryEvent: NSObject { + /// Type of the event. + @objc + public let type: PFLiveQueryEventType + + /// Object this event is for. + @objc + public let object: PFObject + + init(type: PFLiveQueryEventType, object: PFObject) { + self.type = type + self.object = object + } +} + +/** + This struct wraps up all of our Objective-C compatibility layer. You should never need to touch this if you're using Swift. + */ +public struct ObjCCompat { + fileprivate init() { } + + /** + A default implementation of the SubscriptionHandling protocol, using blocks for callbacks. + */ + @objc(PFLiveQuerySubscription) + open class Subscription: NSObject { + public typealias SubscribeHandler = @convention(block) (PFQuery) -> Void + public typealias ErrorHandler = @convention(block) (PFQuery, NSError) -> Void + public typealias EventHandler = @convention(block) (PFQuery, PFLiveQueryEvent) -> Void + public typealias ObjectHandler = @convention(block) (PFQuery, PFObject) -> Void + + var subscribeHandlers = [SubscribeHandler]() + var unsubscribeHandlers = [SubscribeHandler]() + var errorHandlers = [ErrorHandler]() + var eventHandlers = [EventHandler]() + + /** + Register a callback for when a client succesfully subscribes to a query. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addSubscribeHandler:) + open func addSubscribeHandler(_ handler: @escaping SubscribeHandler) -> Subscription { + subscribeHandlers.append(handler) + return self + } + + /** + Register a callback for when a query has been unsubscribed. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addUnsubscribeHandler:) + open func addUnsubscribeHandler(_ handler: @escaping SubscribeHandler) -> Subscription { + unsubscribeHandlers.append(handler) + return self + } + + /** + Register a callback for when an error occurs. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addErrorHandler:) + open func addErrorHandler(_ handler: @escaping ErrorHandler) -> Subscription { + errorHandlers.append(handler) + return self + } + + /** + Register a callback for when an event occurs. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addEventHandler:) + open func addEventHandler(_ handler: @escaping EventHandler) -> Subscription { + eventHandlers.append(handler) + return self + } + + /** + Register a callback for when an object enters a query. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addEnterHandler:) + open func addEnterHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .entered ? handler($0, $1.object) : () } + } + + /** + Register a callback for when an object leaves a query. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addLeaveHandler:) + open func addLeaveHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .left ? handler($0, $1.object) : () } + } + + /** + Register a callback for when an object that matches the query is created. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addCreateHandler:) + open func addCreateHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .created ? handler($0, $1.object) : () } + } + + /** + Register a callback for when an object that matches the query is updated. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addUpdateHandler:) + open func addUpdateHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .updated ? handler($0, $1.object) : () } + } + + /** + Register a callback for when an object that matches the query is deleted. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @objc(addDeleteHandler:) + open func addDeleteHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .deleted ? handler($0, $1.object) : () } + } + } +} + +extension ObjCCompat.Subscription: ObjCCompat_SubscriptionHandling { + public func didRecieveEvent(_ query: PFQuery, event: PFLiveQueryEvent, client: Client) { + eventHandlers.forEach { $0(query, event) } + } + + public func didRecieveError(_ query: PFQuery, error: NSError, client: Client) { + errorHandlers.forEach { $0(query, error) } + } + + public func didSubscribe(_ query: PFQuery, client: Client) { + subscribeHandlers.forEach { $0(query) } + } + + public func didUnsubscribe(_ query: PFQuery, client: Client) { + unsubscribeHandlers.forEach { $0(query) } + } +} + +extension Client { + fileprivate class HandlerConverter: SubscriptionHandling { + typealias T = PFObject + + fileprivate static var associatedObjectKey: Int = 0 + fileprivate weak var handler: ObjCCompat_SubscriptionHandling? + + init(handler: ObjCCompat_SubscriptionHandling) { + self.handler = handler + + objc_setAssociatedObject(handler, &HandlerConverter.associatedObjectKey, self, .OBJC_ASSOCIATION_RETAIN) + } + + fileprivate func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) { + handler?.didRecieveEvent?(query, event: PFLiveQueryEvent(event: event), client: client) + } + + fileprivate func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) { + handler?.didRecieveError?(query, error: error as NSError, client: client) + } + + fileprivate func didSubscribe(toQuery query: PFQuery, inClient client: Client) { + handler?.didSubscribe?(query, client: client) + } + + fileprivate func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) { + handler?.didUnsubscribe?(query, client: client) + } + } + + /** + Registers a query for live updates, using a custom subscription handler. + + - parameter query: The query to register for updates. + - parameter handler: A custom subscription handler. + + - returns: The subscription that has just been registered. + */ + @objc(subscribeToQuery:withHandler:) + public func _PF_objc_subscribe( + _ query: PFQuery, handler: ObjCCompat_SubscriptionHandling + ) -> ObjCCompat_SubscriptionHandling { + let swiftHandler = HandlerConverter(handler: handler) + _ = subscribe(query, handler: swiftHandler) + return handler + } + + /** + Registers a query for live updates, using the default subscription handler. + + - parameter query: The query to register for updates. + + - returns: The subscription that has just been registered. + */ + @objc(subscribeToQuery:) + public func _PF_objc_subscribe(_ query: PFQuery) -> ObjCCompat.Subscription { + let subscription = ObjCCompat.Subscription() + _ = _PF_objc_subscribe(query, handler: subscription) + return subscription + } + + /** + Unsubscribes a specific handler from a query. + + - parameter query: The query to unsubscribe from. + - parameter handler: The specific handler to unsubscribe from. + */ + @objc(unsubscribeFromQuery:withHandler:) + public func _PF_objc_unsubscribe(_ query: PFQuery, subscriptionHandler: ObjCCompat_SubscriptionHandling) { + unsubscribe { record in + guard let handler = record.subscriptionHandler as? HandlerConverter + else { + return false + } + return record.query == query && handler.handler === subscriptionHandler + } + } +} + +// HACK: Another compiler bug - if you have a required initializer with a generic type, the compiler simply refuses to +// emit the entire class altogether. Moving this to an extension for now solves the issue. + +extension PFLiveQueryEvent { + convenience init(event: ParseLiveQuery.Event) { + let results: (type: PFLiveQueryEventType, object: PFObject) = { + switch event { + case .entered(let object): return (.entered, object) + case .left(let object): return (.left, object) + case .created(let object): return (.created, object) + case .updated(let object): return (.updated, object) + case .deleted(let object): return (.deleted, object) + } + }() + + self.init(type: results.type, object: results.object) + } +} + +extension PFQuery { + /** + Register this PFQuery for updates with Live Queries. + This uses the shared live query client, and creates a default subscription handler for you. + + - returns: The created subscription for observing. + */ + @objc(subscribe) + public func _PF_objc_subscribe() -> ObjCCompat.Subscription { + return Client.shared._PF_objc_subscribe(self as! PFQuery) + } +} diff --git a/ParseLiveQuery/ParseLiveQuery/PFQuery+Subscribe.swift b/ParseLiveQuery/ParseLiveQuery/PFQuery+Subscribe.swift new file mode 100644 index 000000000..62e4a12eb --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/PFQuery+Subscribe.swift @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation diff --git a/ParseLiveQuery/ParseLiveQuery/Parse+LiveQuery.swift b/ParseLiveQuery/ParseLiveQuery/Parse+LiveQuery.swift new file mode 100644 index 000000000..06110a609 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Parse+LiveQuery.swift @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +//import ParseCore + +extension Parse { + static func validatedCurrentConfiguration() -> ParseClientConfiguration { + guard let configuration = Parse.currentConfiguration else { + preconditionFailure("Parse SDK is not initialized. Call Parse.initializeWithConfiguration() before loading live query client.") + } + return configuration + } +} diff --git a/ParseLiveQuery/ParseLiveQuery/Resources/Info.plist b/ParseLiveQuery/ParseLiveQuery/Resources/Info.plist new file mode 100644 index 000000000..39fee82e8 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 2.2.0 + CFBundleSignature + ???? + CFBundleVersion + 2.2.0 + + diff --git a/ParseLiveQuery/ParseLiveQuery/Subscription.swift b/ParseLiveQuery/ParseLiveQuery/Subscription.swift new file mode 100644 index 000000000..c0d041e80 --- /dev/null +++ b/ParseLiveQuery/ParseLiveQuery/Subscription.swift @@ -0,0 +1,250 @@ +/** + * Copyright (c) 2016-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation +//import ParseCore +import BoltsSwift + +/** + This protocol describes the interface for handling events from a liveQuery client. + + You can use this protocol on any custom class of yours, instead of Subscription, if it fits your use case better. + */ +public protocol SubscriptionHandling: AnyObject { + /// The type of the PFObject subclass that this handler uses. + associatedtype PFObjectSubclass: PFObject + + /** + Tells the handler that an event has been received from the live query server. + + - parameter event: The event that has been recieved from the server. + - parameter query: The query that the event occurred on. + - parameter client: The live query client which received this event. + */ + func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) + + /** + Tells the handler that an error has been received from the live query server. + + - parameter error: The error that the server has encountered. + - parameter query: The query that the error occurred on. + - parameter client: The live query client which received this error. + */ + func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) + + /** + Tells the handler that a query has been successfully registered with the server. + + - note: This may be invoked multiple times if the client disconnects/reconnects. + + - parameter query: The query that has been subscribed. + - parameter client: The live query client which subscribed this query. + */ + func didSubscribe(toQuery query: PFQuery, inClient client: Client) + + /** + Tells the handler that a query has been successfully deregistered from the server. + + - note: This is not called unless `unregister()` is explicitly called. + + - parameter query: The query that has been unsubscribed. + - parameter client: The live query client which unsubscribed this query. + */ + func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) +} + +/** + Represents an update on a specific object from the live query server. + + - Entered: The object has been updated, and is now included in the query. + - Left: The object has been updated, and is no longer included in the query. + - Created: The object has been created, and is a part of the query. + - Updated: The object has been updated, and is still a part of the query. + - Deleted: The object has been deleted, and is no longer included in the query. + */ +public enum Event where T: PFObject { + /// The object has been updated, and is now included in the query + case entered(T) + + /// The object has been updated, and is no longer included in the query + case left(T) + + /// The object has been created, and is a part of the query + case created(T) + + /// The object has been updated, and is still a part of the query + case updated(T) + + /// The object has been deleted, and is no longer included in the query + case deleted(T) + + init(event: Event) { + switch event { + case .entered(let value as T): self = .entered(value) + case .left(let value as T): self = .left(value) + case .created(let value as T): self = .created(value) + case .updated(let value as T): self = .updated(value) + case .deleted(let value as T): self = .deleted(value) + default: fatalError() + } + } +} + +private func == (lhs: Event, rhs: Event) -> Bool { + switch (lhs, rhs) { + case (.entered(let obj1), .entered(let obj2)): return obj1 == obj2 + case (.left(let obj1), .left(let obj2)): return obj1 == obj2 + case (.created(let obj1), .created(let obj2)): return obj1 == obj2 + case (.updated(let obj1), .updated(let obj2)): return obj1 == obj2 + case (.deleted(let obj1), .deleted(let obj2)): return obj1 == obj2 + default: return false + } +} + +/** + A default implementation of the SubscriptionHandling protocol, using closures for callbacks. + */ +open class Subscription: SubscriptionHandling where T: PFObject { + fileprivate var errorHandlers: [(PFQuery, Error) -> Void] = [] + fileprivate var eventHandlers: [(PFQuery, Event) -> Void] = [] + fileprivate var subscribeHandlers: [(PFQuery) -> Void] = [] + fileprivate var unsubscribeHandlers: [(PFQuery) -> Void] = [] + + /** + Creates a new subscription that can be used to handle updates. + */ + public init() { + } + + /** + Register a callback for when an error occurs. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining + */ + @discardableResult open func handleError(_ handler: @escaping (PFQuery, Error) -> Void) -> Subscription { + errorHandlers.append(handler) + return self + } + + /** + Register a callback for when an event occurs. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @discardableResult open func handleEvent(_ handler: @escaping (PFQuery, Event) -> Void) -> Subscription { + eventHandlers.append(handler) + return self + } + + /** + Register a callback for when a client succesfully subscribes to a query. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @discardableResult open func handleSubscribe(_ handler: @escaping (PFQuery) -> Void) -> Subscription { + subscribeHandlers.append(handler) + return self + } + + /** + Register a callback for when a query has been unsubscribed. + + - parameter handler: The callback to register. + + - returns: The same subscription, for easy chaining. + */ + @discardableResult open func handleUnsubscribe(_ handler: @escaping (PFQuery) -> Void) -> Subscription { + unsubscribeHandlers.append(handler) + return self + } + + // --------------- + // MARK: SubscriptionHandling + // TODO: Move to extension once swift compiler is less crashy + // --------------- + public typealias PFObjectSubclass = T + + open func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) { + eventHandlers.forEach { $0(query, event) } + } + + open func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) { + errorHandlers.forEach { $0(query, error) } + } + + open func didSubscribe(toQuery query: PFQuery, inClient client: Client) { + subscribeHandlers.forEach { $0(query) } + } + + open func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) { + unsubscribeHandlers.forEach { $0(query) } + } +} + +extension Subscription { + /** + Register a callback for when an error occcurs of a specific type + + Example: + + subscription.handle(LiveQueryErrors.InvalidJSONError.self) { query, error in + print(error) + } + + - parameter errorType: The error type to register for + - parameter handler: The callback to register + + - returns: The same subscription, for easy chaining + */ + @discardableResult public func handle( + _ errorType: E.Type = E.self, + _ handler: @escaping (PFQuery, E) -> Void + ) -> Subscription { + errorHandlers.append { query, error in + if let error = error as? E { + handler(query, error) + } + } + return self + } + + /** + Register a callback for when an event occurs of a specific type + + Example: + + subscription.handle(Event.Created) { query, object in + // Called whenever an object is creaated + } + + - parameter eventType: The event type to handle. You should pass one of the enum cases in `Event` + - parameter handler: The callback to register + + - returns: The same subscription, for easy chaining + + */ + @discardableResult public func handle(_ eventType: @escaping (T) -> Event, _ handler: @escaping (PFQuery, T) -> Void) -> Subscription { + return handleEvent { query, event in + switch event { + case .entered(let obj) where eventType(obj) == event: handler(query, obj) + case .left(let obj) where eventType(obj) == event: handler(query, obj) + case .created(let obj) where eventType(obj) == event: handler(query, obj) + case .updated(let obj) where eventType(obj) == event: handler(query, obj) + case .deleted(let obj) where eventType(obj) == event: handler(query, obj) + default: return + } + } + } +} diff --git a/ParseStarterProject/OSX/ParseOSXStarterProject-Swift/ParseOSXStarterProject-Swift.xcodeproj/project.pbxproj b/ParseStarterProject/OSX/ParseOSXStarterProject-Swift/ParseOSXStarterProject-Swift.xcodeproj/project.pbxproj index 4b0a00578..6515f8336 100644 --- a/ParseStarterProject/OSX/ParseOSXStarterProject-Swift/ParseOSXStarterProject-Swift.xcodeproj/project.pbxproj +++ b/ParseStarterProject/OSX/ParseOSXStarterProject-Swift/ParseOSXStarterProject-Swift.xcodeproj/project.pbxproj @@ -575,7 +575,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -622,7 +622,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; diff --git a/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject.xcodeproj/project.pbxproj b/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject.xcodeproj/project.pbxproj index 7802a4ed8..e355fb058 100644 --- a/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject.xcodeproj/project.pbxproj +++ b/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject.xcodeproj/project.pbxproj @@ -605,7 +605,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; @@ -648,7 +648,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; SDKROOT = macosx; }; name = Release; diff --git a/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject/AppDelegate.m b/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject/AppDelegate.m index 497b40d7c..94c118032 100644 --- a/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject/AppDelegate.m +++ b/ParseStarterProject/OSX/ParseOSXStarterProject/ParseOSXStarterProject/AppDelegate.m @@ -9,7 +9,7 @@ #import "AppDelegate.h" -#import +#import @implementation AppDelegate diff --git a/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectAppDelegate.m b/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectAppDelegate.m index adc76983e..3395f01ad 100644 --- a/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectAppDelegate.m +++ b/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectAppDelegate.m @@ -7,7 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#import // If you want to use any of the UI components, uncomment this line // #import diff --git a/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectViewController.m b/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectViewController.m index 4a2382c54..296e4e4f1 100644 --- a/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectViewController.m +++ b/ParseStarterProject/iOS/ParseStarterProject/ParseStarterProject/ParseStarterProjectViewController.m @@ -9,7 +9,7 @@ #import "ParseStarterProjectViewController.h" -#import +#import @implementation ParseStarterProjectViewController diff --git a/Rakefile b/Rakefile index dffb7ae41..3261c8042 100644 --- a/Rakefile +++ b/Rakefile @@ -16,7 +16,8 @@ release_folder = File.join(build_folder, 'release') bolts_build_folder = File.join(script_folder, 'Carthage', 'Build') bolts_folder = File.join(script_folder, 'Carthage', 'Checkouts', 'Bolts-ObjC') ios_simulator = 'platform="iOS Simulator",name="iPhone 14"' -tvos_simulator = 'platform="tvOS Simulator",name="Apple TV 4K"' +tvos_simulator = 'platform="tvOS Simulator",name="Apple TV"' +watchos_simulator = 'platform="watchOS Simulator",name="Apple Watch Series 8 (45mm)"' module Constants require 'plist' @@ -34,6 +35,9 @@ module Constants File.join(script_folder, 'ParseFacebookUtils', 'ParseFacebookUtils', 'Resources', 'Info-tvOS.plist'), File.join(script_folder, 'ParseTwitterUtils', 'ParseTwitterUtils', 'Resources', 'Info-iOS.plist'), File.join(script_folder, 'ParseUI', 'ParseUI', 'Resources', 'Info-iOS.plist'), + File.join(script_folder, 'ParseLiveQuery', 'ParseLiveQuery', 'Resources', 'Info.plist'), + File.join(script_folder, 'ParseLiveQuery', 'ParseLiveQuery-tvOS', 'Info.plist'), + File.join(script_folder, 'ParseLiveQuery', 'ParseLiveQuery-watchOS', 'Info.plist'), File.join(script_folder, 'ParseStarterProject', 'iOS', 'ParseStarterProject', 'Resources', 'Info.plist'), File.join(script_folder, 'ParseStarterProject', 'iOS', 'ParseStarterProject-Swift', 'Resources', 'Info.plist'), File.join(script_folder, 'ParseStarterProject', 'OSX', 'ParseOSXStarterProject', 'Resources', 'Info.plist'), @@ -148,6 +152,80 @@ namespace :build do end end + namespace :parse_live_query do + desc 'Build iOS LiveQuery framework.' + task :ios do + task = XCTask::BuildFrameworkTask.new do |t| + t.directory = script_folder + t.build_directory = File.join(build_folder, 'iOS') + t.framework_type = XCTask::FrameworkType::IOS + t.framework_name = 'ParseLiveQuery.framework' + t.workspace = 'Parse.xcworkspace' + t.scheme = 'ParseLiveQuery-iOS' + t.configuration = 'Release' + end + result = task.execute + unless result + puts 'Failed to build iOS LiveQuery Framework.' + exit(1) + end + end + + desc 'Build macOS LiveQuery framework.' + task :macos do + task = XCTask::BuildFrameworkTask.new do |t| + t.directory = script_folder + t.build_directory = File.join(build_folder, 'macOS') + t.framework_type = XCTask::FrameworkType::OSX + t.framework_name = 'ParseLiveQuery.framework' + t.workspace = 'Parse.xcworkspace' + t.scheme = 'ParseLiveQuery-OSX' + t.configuration = 'Release' + end + result = task.execute + unless result + puts 'Failed to build macOS LiveQuery Framework.' + exit(1) + end + end + + desc 'Build watchOS LiveQuery framework.' + task :watchos do + task = XCTask::BuildFrameworkTask.new do |t| + t.directory = script_folder + t.build_directory = File.join(build_folder, 'watchOS') + t.framework_type = XCTask::FrameworkType::WATCHOS + t.framework_name = 'ParseLiveQuery_watchOS.framework' + t.workspace = 'Parse.xcworkspace' + t.scheme = 'ParseLiveQuery-watchOS' + t.configuration = 'Release' + end + result = task.execute + unless result + puts 'Failed to build watchOS LiveQuery Framework.' + exit(1) + end + end + + desc 'Build tvOS LiveQuery framework.' + task :tvos do + task = XCTask::BuildFrameworkTask.new do |t| + t.directory = script_folder + t.build_directory = File.join(build_folder, 'tvOS') + t.framework_type = XCTask::FrameworkType::TVOS + t.framework_name = 'ParseLiveQuery_tvOS.framework' + t.workspace = 'Parse.xcworkspace' + t.scheme = 'ParseLiveQuery-tvOS' + t.configuration = 'Release' + end + result = task.execute + unless result + puts 'Failed to build tvOS LiveQuery Framework.' + exit(1) + end + end + end + namespace :facebook_utils do desc 'Build iOS FacebookUtils framework.' task :ios do @@ -356,6 +434,23 @@ namespace :package do make_package(release_folder, [parseui_framework_path], package_parseui_name) + + Rake::Task['build:parse_live_query:ios'].invoke + ios_lq_framework_path = File.join(build_folder, 'iOS', 'ParseLiveQuery.framework') + make_package(release_folder, [ios_lq_framework_path], 'ParseLiveQuery-iOS.zip') + + Rake::Task['build:parse_live_query:watchos'].invoke + watchos_lq_fb_utils_framework_path = File.join(build_folder, 'watchOS', 'ParseLiveQuery_watchOS.framework') + make_package(release_folder, [watchos_lq_fb_utils_framework_path], 'ParseLiveQuery-watchOS.zip') + + Rake::Task['build:parse_live_query:tvos'].invoke + tvos_lq_framework_path = File.join(build_folder, 'tvOS', 'ParseLiveQuery_tvOS.framework') + make_package(release_folder, [tvos_lq_framework_path], 'ParseLiveQuery-tvOS.zip') + + Rake::Task['build:parse_live_query:macos'].invoke + macos_lq_utils_framework_path = File.join(build_folder, 'macOS', 'ParseLiveQuery.framework') + make_package(release_folder, [macos_lq_utils_framework_path], 'ParseLiveQuery-OSX.zip') + end desc 'Build and package all starter projects for the release' @@ -610,6 +705,99 @@ namespace :test do end end + namespace :parse_live_query do + task :all do + Rake::Task['test:parse_live_query:ios'].invoke + Rake::Task['test:parse_live_query:tvos'].invoke + Rake::Task['test:parse_live_query:watchos'].invoke + Rake::Task['test:parse_live_query:osx'].invoke + end + + task :ios do + task = XCTask::BuildTask.new do |t| + t.directory = script_folder + t.workspace = 'Parse.xcworkspace' + + t.scheme = 'ParseLiveQuery-iOS' + t.sdk = 'iphonesimulator' + t.destinations = [ios_simulator] + t.configuration = 'Debug' + + t.actions = [XCTask::BuildAction::CLEAN, XCTask::BuildAction::BUILD] + t.formatter = XCTask::BuildFormatter::XCPRETTY + end + + result = task.execute + unless result + puts 'Failed to build ParseLiveQuery' + exit(1) + end + end + + task :tvos do + task = XCTask::BuildTask.new do |t| + t.directory = script_folder + t.workspace = 'Parse.xcworkspace' + + t.scheme = 'ParseLiveQuery-tvOS' + t.destinations = [tvos_simulator] + t.configuration = 'Debug' + + + t.actions = [XCTask::BuildAction::CLEAN, XCTask::BuildAction::BUILD] + t.formatter = XCTask::BuildFormatter::XCPRETTY + end + + result = task.execute + unless result + puts 'Failed to build ParseLiveQuery-tvOS.' + exit(1) + end + end + + task :watchos do + task = XCTask::BuildTask.new do |t| + t.directory = script_folder + t.workspace = 'Parse.xcworkspace' + + t.scheme = 'ParseLiveQuery-watchOS' + t.destinations = [watchos_simulator] + t.configuration = 'Debug' + + + t.actions = [XCTask::BuildAction::CLEAN, XCTask::BuildAction::BUILD] + t.formatter = XCTask::BuildFormatter::XCPRETTY + end + + result = task.execute + unless result + puts 'Failed to build ParseLiveQuery-watchOS.' + exit(1) + end + end + + task :osx do + task = XCTask::BuildTask.new do |t| + t.directory = script_folder + t.workspace = 'Parse.xcworkspace' + + t.scheme = 'ParseLiveQuery-OSX' + t.configuration = 'Debug' + + + t.actions = [XCTask::BuildAction::CLEAN, XCTask::BuildAction::BUILD] + t.formatter = XCTask::BuildFormatter::XCPRETTY + end + + result = task.execute + unless result + puts 'Failed to build ParseLiveQuery-OSX.' + exit(1) + end + end + end + + desc 'Run Starter Project Tests' task :starters do |_| results = [] diff --git a/Tests/Parse-SDK-iOS-OSXTests/Parse_SDK_iOS_OSXTests.swift b/Tests/Parse-SDK-iOS-OSXTests/Parse_SDK_iOS_OSXTests.swift new file mode 100644 index 000000000..60488957a --- /dev/null +++ b/Tests/Parse-SDK-iOS-OSXTests/Parse_SDK_iOS_OSXTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import Parse_SDK_iOS_OSX + +final class Parse_SDK_iOS_OSXTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(Parse_SDK_iOS_OSX().text, "Hello, World!") + } +}