feat: Add LiveQuery module to SDK; this deprecates the separate [Parse LiveQuery SDK](https://github.com/parse-community/ParseLiveQuery-iOS-OSX) (#1712)
This commit is contained in:
parent
cbab34c66a
commit
154da34b02
|
@ -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' }}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
2
Cartfile
2
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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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")])
|
||||
]
|
||||
)
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
<FileRef
|
||||
location = "group:ParseTwitterUtils/ParseTwitterUtils.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:ParseLiveQuery/ParseLiveQuery.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:ParseUI/ParseUI.xcodeproj">
|
||||
</FileRef>
|
||||
|
|
|
@ -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 = "<group>"; };
|
||||
91DF24951A09BAF100CFC7D4 /* PFPinningEventuallyQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFPinningEventuallyQueue.m; sourceTree = "<group>"; };
|
||||
91DF24981A0B0FF200CFC7D4 /* PFEventuallyQueue_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFEventuallyQueue_Private.h; sourceTree = "<group>"; };
|
||||
9575FF10299136C60057B4CE /* Starscream.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Starscream.xcodeproj; path = ../Carthage/Checkouts/Starscream/Starscream.xcodeproj; sourceTree = "<group>"; };
|
||||
95AEEB0F2991373F00165C0D /* BoltsSwift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = BoltsSwift.xcodeproj; path = "../Carthage/Checkouts/Bolts-Swift/BoltsSwift.xcodeproj"; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
97E18AE41623835600B17A67 /* PFLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PFLocationManager.h; sourceTree = "<group>"; };
|
||||
|
@ -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 = "<group>";
|
||||
};
|
||||
9575FF11299136C60057B4CE /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9575FF1F299136C60057B4CE /* Starscream.framework */,
|
||||
9575FF21299136C60057B4CE /* Starscream Tests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
F519CBB41CA9CA04005295C0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
F519CBBB1CA9CA2B005295C0 /* Message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Message.h; sourceTree = "<group>"; };
|
||||
F519CBBC1CA9CA2B005295C0 /* Message.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Message.m; sourceTree = "<group>"; };
|
||||
F519CBBE1CA9CA34005295C0 /* Room.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Room.h; sourceTree = "<group>"; };
|
||||
F519CBBF1CA9CA34005295C0 /* Room.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Room.m; sourceTree = "<group>"; };
|
||||
F519CBCE1CA9CC4D005295C0 /* ChatRoomManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatRoomManager.h; sourceTree = "<group>"; };
|
||||
F519CBCF1CA9CC4D005295C0 /* ChatRoomManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatRoomManager.m; sourceTree = "<group>"; };
|
||||
/* 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 = "<group>";
|
||||
};
|
||||
E0B5CD933BEBE8518E7750F2 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
395FFA3A29D75F1F006502C5 /* ParseLiveQuery.xcodeproj */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F519CBA81CA9CA04005295C0 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F519CBB31CA9CA04005295C0 /* LiveQueryDemo-ObjC */,
|
||||
F519CBB21CA9CA04005295C0 /* Products */,
|
||||
E0B5CD933BEBE8518E7750F2 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F519CBB21CA9CA04005295C0 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F509D5321CA9E597007B15B0 /* LiveQueryDemo-ObjC.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
/* 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 */;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1120"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5311CA9E597007B15B0"
|
||||
BuildableName = "LiveQueryDemo-ObjC.app"
|
||||
BlueprintName = "LiveQueryDemo-ObjC"
|
||||
ReferencedContainer = "container:LiveQueryDemo-ObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5311CA9E597007B15B0"
|
||||
BuildableName = "LiveQueryDemo-ObjC.app"
|
||||
BlueprintName = "LiveQueryDemo-ObjC"
|
||||
ReferencedContainer = "container:LiveQueryDemo-ObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5311CA9E597007B15B0"
|
||||
BuildableName = "LiveQueryDemo-ObjC.app"
|
||||
BlueprintName = "LiveQueryDemo-ObjC"
|
||||
ReferencedContainer = "container:LiveQueryDemo-ObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5311CA9E597007B15B0"
|
||||
BuildableName = "LiveQueryDemo-ObjC.app"
|
||||
BlueprintName = "LiveQueryDemo-ObjC"
|
||||
ReferencedContainer = "container:LiveQueryDemo-ObjC.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -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 <NSObject>
|
||||
|
||||
- (PFQuery *)queryForChatRoomManager:(ChatRoomManager *)manager;
|
||||
- (PFLiveQueryClient *)liveQueryClientForChatRoomManager:(ChatRoomManager *)manager;
|
||||
|
||||
@end
|
||||
|
||||
@protocol ChatRoomManagerDelegate <NSObject>
|
||||
|
||||
- (void)chatRoomManager:(ChatRoomManager *)manager didReceiveMessage:(Message *)message;
|
||||
|
||||
@end
|
||||
|
||||
@interface ChatRoomManager : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly, getter=isConnected) BOOL connected;
|
||||
@property (nonatomic, weak, readonly) id<ChatRoomManagerDataSource> dataSource;
|
||||
@property (nonatomic, weak, readonly) id<ChatRoomManagerDelegate> delegate;
|
||||
|
||||
- (instancetype)initWithDataSource:(id<ChatRoomManagerDataSource>)dataSource delegate:(id<ChatRoomManagerDelegate>)delegate;
|
||||
|
||||
- (void)connect;
|
||||
- (void)disconnect;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -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<ChatRoomManagerDataSource>)dataSource delegate:(id<ChatRoomManagerDelegate>)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
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016 Parse. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -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 <PFSubclassing>
|
||||
|
||||
@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
|
|
@ -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
|
|
@ -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 <Parse/Parse.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface Room : PFObject <PFSubclassing>
|
||||
|
||||
@property (nullable, nonatomic, strong) NSString *name;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -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
|
|
@ -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<PFUser *> *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<PFUser *> *task) {
|
||||
if (task.result) {
|
||||
return task.result;
|
||||
}
|
||||
|
||||
puts("Login failed, please try again.");
|
||||
return AttemptLogin();
|
||||
}];
|
||||
}
|
||||
|
||||
BFTask<Room *> *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 <ChatRoomManagerDataSource, ChatRoomManagerDelegate>
|
||||
|
||||
@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<ParseMutableClientConfiguration> configuration) {
|
||||
configuration.applicationId = @"myAppId";
|
||||
// configuration.clientKey = @"myClientKey";
|
||||
configuration.server = @"http://localhost:1337/parse";
|
||||
}]];
|
||||
|
||||
[[AttemptLogin() continueWithBlock:^id (BFTask<PFUser *> *task) {
|
||||
return AttemptRoom();
|
||||
}] continueWithBlock:^id (BFTask<Room *> *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;
|
||||
}
|
|
@ -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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
F59F85AF1C9BB48200566A29 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
F59F85B61C9BB4B600566A29 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
|
||||
F59F85B71C9BB4B600566A29 /* Room.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Room.swift; sourceTree = "<group>"; };
|
||||
/* 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 = "<group>";
|
||||
};
|
||||
395FFA8B29D7740B006502C5 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
395FFA9229D7740B006502C5 /* ParseLiveQuery.framework */,
|
||||
395FFA9429D7740B006502C5 /* ParseLiveQuery.framework */,
|
||||
395FFA9629D7740B006502C5 /* ParseLiveQuery_watchOS.framework */,
|
||||
395FFA9829D7740B006502C5 /* ParseLiveQuery_tvOS.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F59F85A31C9BB48200566A29 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F59F85AE1C9BB48200566A29 /* LiveQueryDemo */,
|
||||
F59F85AD1C9BB48200566A29 /* Products */,
|
||||
2E2DAD338FCB65EC95CB7AA9 /* Frameworks */,
|
||||
);
|
||||
indentWidth = 4;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 4;
|
||||
};
|
||||
F59F85AD1C9BB48200566A29 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F509D5171CA9E4AE007B15B0 /* LiveQueryDemo.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F59F85AE1C9BB48200566A29 /* LiveQueryDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F509D5241CA9E4AE007B15B0 /* Info.plist */,
|
||||
F59F85B61C9BB4B600566A29 /* Message.swift */,
|
||||
F59F85B71C9BB4B600566A29 /* Room.swift */,
|
||||
F59F85AF1C9BB48200566A29 /* main.swift */,
|
||||
);
|
||||
path = LiveQueryDemo;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* 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 */;
|
||||
}
|
7
ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
ParseLiveQuery/Examples/LiveQueryDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1120"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5161CA9E4AE007B15B0"
|
||||
BuildableName = "LiveQueryDemo.app"
|
||||
BlueprintName = "LiveQueryDemo"
|
||||
ReferencedContainer = "container:LiveQueryDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5161CA9E4AE007B15B0"
|
||||
BuildableName = "LiveQueryDemo.app"
|
||||
BlueprintName = "LiveQueryDemo"
|
||||
ReferencedContainer = "container:LiveQueryDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5161CA9E4AE007B15B0"
|
||||
BuildableName = "LiveQueryDemo.app"
|
||||
BlueprintName = "LiveQueryDemo"
|
||||
ReferencedContainer = "container:LiveQueryDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F509D5161CA9E4AE007B15B0"
|
||||
BuildableName = "LiveQueryDemo.app"
|
||||
BlueprintName = "LiveQueryDemo"
|
||||
ReferencedContainer = "container:LiveQueryDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016 Parse. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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<Message>?
|
||||
|
||||
var connected: Bool { return currentChatRoom != nil }
|
||||
var messagesQuery: PFQuery<Message> {
|
||||
return (Message.query()?
|
||||
.whereKey("roomName", equalTo: currentChatRoom!.name!)
|
||||
.order(byAscending: "createdAt")) as! PFQuery<Message>
|
||||
}
|
||||
|
||||
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<UInt8>) -> 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()
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.2.0</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// ParseLiveQuery_tvOS.h
|
||||
// ParseLiveQuery-tvOS
|
||||
//
|
||||
// Created by Corey Baker on 11/15/20.
|
||||
// Copyright © 2020 Parse. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! 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 <ParseLiveQuery_tvOS/PublicHeader.h>
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.2.0</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// ParseLiveQuery_watchOS.h
|
||||
// ParseLiveQuery-watchOS
|
||||
//
|
||||
// Created by Corey Baker on 11/15/20.
|
||||
// Copyright © 2020 Parse. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! 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 <ParseLiveQuery_watchOS/PublicHeader.h>
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
7
ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
ParseLiveQuery/ParseLiveQuery.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:ParseLiveQuery.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1120"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F5903CE91BD999C500C3EFFE"
|
||||
BuildableName = "ParseLiveQuery.framework"
|
||||
BlueprintName = "ParseLiveQuery-OSX"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F5903CE91BD999C500C3EFFE"
|
||||
BuildableName = "ParseLiveQuery.framework"
|
||||
BlueprintName = "ParseLiveQuery-OSX"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F5903CE91BD999C500C3EFFE"
|
||||
BuildableName = "ParseLiveQuery.framework"
|
||||
BlueprintName = "ParseLiveQuery-OSX"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1120"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F5A9BFB61BE0248D00E78326"
|
||||
BuildableName = "ParseLiveQuery.framework"
|
||||
BlueprintName = "ParseLiveQuery-iOS"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F5A9BFB61BE0248D00E78326"
|
||||
BuildableName = "ParseLiveQuery.framework"
|
||||
BlueprintName = "ParseLiveQuery-iOS"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F5A9BFB61BE0248D00E78326"
|
||||
BuildableName = "ParseLiveQuery.framework"
|
||||
BlueprintName = "ParseLiveQuery-iOS"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1220"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "708836932561F55B005B32F0"
|
||||
BuildableName = "ParseLiveQuery_tvOS.framework"
|
||||
BlueprintName = "ParseLiveQuery-tvOS"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "708836932561F55B005B32F0"
|
||||
BuildableName = "ParseLiveQuery_tvOS.framework"
|
||||
BlueprintName = "ParseLiveQuery-tvOS"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1220"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "708836712561F502005B32F0"
|
||||
BuildableName = "ParseLiveQuery_watchOS.framework"
|
||||
BlueprintName = "ParseLiveQuery-watchOS"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "708836712561F502005B32F0"
|
||||
BuildableName = "ParseLiveQuery_watchOS.framework"
|
||||
BlueprintName = "ParseLiveQuery-watchOS"
|
||||
ReferencedContainer = "container:ParseLiveQuery.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -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<T>(
|
||||
_ query: PFQuery<T>,
|
||||
subclassType: T.Type = T.self
|
||||
) -> Subscription<T> {
|
||||
return subscribe(query, handler: Subscription<T>())
|
||||
}
|
||||
|
||||
/**
|
||||
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<T>(
|
||||
_ query: PFQuery<T.PFObjectSubclass>,
|
||||
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<PFObject>,
|
||||
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<T>(
|
||||
_ handler: T,
|
||||
toQuery query: PFQuery<T.PFObjectSubclass>
|
||||
) where T: SubscriptionHandling {
|
||||
subscriptions = subscriptions.map {
|
||||
if $0.subscriptionHandler === handler {
|
||||
_ = sendOperationAsync(.update(requestId: $0.requestId, query: query as! PFQuery<PFObject>))
|
||||
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<PFObject>) {
|
||||
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<T>(_ query: PFQuery<T.PFObjectSubclass>, 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
|
||||
}
|
||||
}
|
|
@ -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<T: PFObject>(_ 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<PFObject>, Client) -> Void
|
||||
var errorHandlerClosure: (Error, Client) -> Void
|
||||
var subscribeHandlerClosure: (Client) -> Void
|
||||
var unsubscribeHandlerClosure: (Client) -> Void
|
||||
|
||||
let query: PFQuery<PFObject>
|
||||
let requestId: RequestId
|
||||
|
||||
init<T>(query: PFQuery<T.PFObjectSubclass>, requestId: RequestId, handler: T) where T:SubscriptionHandling {
|
||||
self.query = query as! PFQuery<PFObject>
|
||||
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<Void> {
|
||||
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<Void> {
|
||||
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<PFObject> = 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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<PFObject>, sessionToken: String?)
|
||||
case update(requestId: Client.RequestId, query: PFQuery<PFObject>)
|
||||
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<String, AnyObject>(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<String, AnyObject>(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<T>(_ 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")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<T>(query: PFQuery<T>) {
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -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<PFObject>, 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<PFObject>, 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<PFObject>, 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<PFObject>, 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<PFObject>) -> Void
|
||||
public typealias ErrorHandler = @convention(block) (PFQuery<PFObject>, NSError) -> Void
|
||||
public typealias EventHandler = @convention(block) (PFQuery<PFObject>, PFLiveQueryEvent) -> Void
|
||||
public typealias ObjectHandler = @convention(block) (PFQuery<PFObject>, 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<PFObject>, event: PFLiveQueryEvent, client: Client) {
|
||||
eventHandlers.forEach { $0(query, event) }
|
||||
}
|
||||
|
||||
public func didRecieveError(_ query: PFQuery<PFObject>, error: NSError, client: Client) {
|
||||
errorHandlers.forEach { $0(query, error) }
|
||||
}
|
||||
|
||||
public func didSubscribe(_ query: PFQuery<PFObject>, client: Client) {
|
||||
subscribeHandlers.forEach { $0(query) }
|
||||
}
|
||||
|
||||
public func didUnsubscribe(_ query: PFQuery<PFObject>, 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<T>, forQuery query: PFQuery<T>, inClient client: Client) {
|
||||
handler?.didRecieveEvent?(query, event: PFLiveQueryEvent(event: event), client: client)
|
||||
}
|
||||
|
||||
fileprivate func didEncounter(_ error: Error, forQuery query: PFQuery<T>, inClient client: Client) {
|
||||
handler?.didRecieveError?(query, error: error as NSError, client: client)
|
||||
}
|
||||
|
||||
fileprivate func didSubscribe(toQuery query: PFQuery<T>, inClient client: Client) {
|
||||
handler?.didSubscribe?(query, client: client)
|
||||
}
|
||||
|
||||
fileprivate func didUnsubscribe(fromQuery query: PFQuery<T>, 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<PFObject>, 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<PFObject>) -> 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<PFObject>, 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<T>(event: ParseLiveQuery.Event<T>) {
|
||||
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<PFObject>)
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.2.0</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -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<PFObjectSubclass>, forQuery query: PFQuery<PFObjectSubclass>, 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<PFObjectSubclass>, 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<PFObjectSubclass>, 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<PFObjectSubclass>, 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<T> 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<V>(event: Event<V>) {
|
||||
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 == <T>(lhs: Event<T>, rhs: Event<T>) -> 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<T>: SubscriptionHandling where T: PFObject {
|
||||
fileprivate var errorHandlers: [(PFQuery<T>, Error) -> Void] = []
|
||||
fileprivate var eventHandlers: [(PFQuery<T>, Event<T>) -> Void] = []
|
||||
fileprivate var subscribeHandlers: [(PFQuery<T>) -> Void] = []
|
||||
fileprivate var unsubscribeHandlers: [(PFQuery<T>) -> 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<T>, 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<T>, Event<T>) -> 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<T>) -> 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<T>) -> 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<PFObjectSubclass>, forQuery query: PFQuery<T>, inClient client: Client) {
|
||||
eventHandlers.forEach { $0(query, event) }
|
||||
}
|
||||
|
||||
open func didEncounter(_ error: Error, forQuery query: PFQuery<T>, inClient client: Client) {
|
||||
errorHandlers.forEach { $0(query, error) }
|
||||
}
|
||||
|
||||
open func didSubscribe(toQuery query: PFQuery<T>, inClient client: Client) {
|
||||
subscribeHandlers.forEach { $0(query) }
|
||||
}
|
||||
|
||||
open func didUnsubscribe(fromQuery query: PFQuery<T>, 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<E: Error>(
|
||||
_ errorType: E.Type = E.self,
|
||||
_ handler: @escaping (PFQuery<T>, 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<T>, _ handler: @escaping (PFQuery<T>, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <Parse/Parse.h>
|
||||
#import <Parse.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <Parse/Parse.h>
|
||||
#import <Parse.h>
|
||||
|
||||
// If you want to use any of the UI components, uncomment this line
|
||||
// #import <ParseUI/ParseUI.h>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#import "ParseStarterProjectViewController.h"
|
||||
|
||||
#import <Parse/Parse.h>
|
||||
#import <Parse.h>
|
||||
|
||||
@implementation ParseStarterProjectViewController
|
||||
|
||||
|
|
190
Rakefile
190
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 = []
|
||||
|
|
|
@ -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!")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue