From ed4f859104493122533bbe743121efaecf6f1a8e Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Wed, 21 Sep 2016 23:00:09 -0400 Subject: [PATCH 1/6] Swift3 and Carthage --- .gitmodules | 12 ++ .travis.yml | 3 + Cartfile | 4 + Cartfile.resolved | 4 + Carthage/Checkouts/Bolts-ObjC | 1 + Carthage/Checkouts/Bolts-Swift | 1 + Carthage/Checkouts/Parse-SDK-iOS-OSX | 1 + Carthage/Checkouts/SocketRocket | 1 + .../project.pbxproj | 8 +- .../xcschemes/LiveQueryDemo-ObjC.xcscheme | 2 +- .../LiveQueryDemo.xcodeproj/project.pbxproj | 12 +- .../xcschemes/LiveQueryDemo.xcscheme | 2 +- Examples/LiveQueryDemo/main.swift | 52 +++---- Podfile | 17 ++- Podfile.lock | 18 ++- README.md | 5 + .../ParseLiveQuery.xcodeproj/project.pbxproj | 63 ++++++++- .../xcschemes/ParseLiveQuery-OSX.xcscheme | 2 +- .../xcschemes/ParseLiveQuery-iOS.xcscheme | 2 +- Sources/ParseLiveQuery/Client.swift | 64 ++++----- .../Internal/BoltsHelpers.swift | 14 +- .../Internal/ClientPrivate.swift | 129 +++++++++--------- Sources/ParseLiveQuery/Internal/Errors.swift | 10 +- .../ParseLiveQuery/Internal/Operation.swift | 60 ++++---- .../Internal/QueryEncoder.swift | 14 +- Sources/ParseLiveQuery/ObjCCompat.swift | 111 +++++++-------- .../ParseLiveQuery/PFQuery+Subscribe.swift | 13 -- Sources/ParseLiveQuery/Subscription.swift | 88 ++++++------ 28 files changed, 409 insertions(+), 304 deletions(-) create mode 100644 .gitmodules create mode 100644 Cartfile create mode 100644 Cartfile.resolved create mode 160000 Carthage/Checkouts/Bolts-ObjC create mode 160000 Carthage/Checkouts/Bolts-Swift create mode 160000 Carthage/Checkouts/Parse-SDK-iOS-OSX create mode 160000 Carthage/Checkouts/SocketRocket diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..055eb9d7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "Carthage/Checkouts/Bolts-ObjC"] + path = Carthage/Checkouts/Bolts-ObjC + url = https://github.com/BoltsFramework/Bolts-ObjC.git +[submodule "Carthage/Checkouts/Bolts-Swift"] + path = Carthage/Checkouts/Bolts-Swift + url = https://github.com/BoltsFramework/Bolts-Swift.git +[submodule "Carthage/Checkouts/SocketRocket"] + path = Carthage/Checkouts/SocketRocket + url = https://github.com/facebook/SocketRocket.git +[submodule "Carthage/Checkouts/Parse-SDK-iOS-OSX"] + path = Carthage/Checkouts/Parse-SDK-iOS-OSX + url = https://github.com/ParsePlatform/Parse-SDK-iOS-OSX.git diff --git a/.travis.yml b/.travis.yml index 179f6c23..8f89d5ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ env: - TEST_TYPE=OSXDemoSwift - TEST_TYPE=OSXDemoObjC - TEST_TYPE=CocoaPods + - TEST_TYPE=Carthage install: - | bundle install @@ -36,6 +37,8 @@ script: xcodebuild build -workspace ParseLiveQuery.xcworkspace -scheme LiveQueryDemo-ObjC -configuration Debug | xcpretty -c elif [ "$TEST_TYPE" = CocoaPods ]; then pod lib lint ParseLiveQuery.podspec + elif [ "$TEST_TYPE" = Carthage ]; then + carthage build --no-skip-current --platform iOS fi after_success: - | diff --git a/Cartfile b/Cartfile new file mode 100644 index 00000000..d1bc0598 --- /dev/null +++ b/Cartfile @@ -0,0 +1,4 @@ +github "BoltsFramework/Bolts-Swift" +github "facebook/SocketRocket" "0.4.2" +github "ParsePlatform/Parse-SDK-iOS-OSX" + diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 00000000..c7ea29a4 --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1,4 @@ +github "BoltsFramework/Bolts-ObjC" "1.8.4" +github "BoltsFramework/Bolts-Swift" "1.3.0" +github "facebook/SocketRocket" "0.4.2" +github "ParsePlatform/Parse-SDK-iOS-OSX" "1.14.2" diff --git a/Carthage/Checkouts/Bolts-ObjC b/Carthage/Checkouts/Bolts-ObjC new file mode 160000 index 00000000..e64deecb --- /dev/null +++ b/Carthage/Checkouts/Bolts-ObjC @@ -0,0 +1 @@ +Subproject commit e64deecb2f0e10ac0dbb71f522c7a5b9cafb0b4d diff --git a/Carthage/Checkouts/Bolts-Swift b/Carthage/Checkouts/Bolts-Swift new file mode 160000 index 00000000..bbcbab61 --- /dev/null +++ b/Carthage/Checkouts/Bolts-Swift @@ -0,0 +1 @@ +Subproject commit bbcbab61e3fd11239c6c9a51460db20be26dc9c7 diff --git a/Carthage/Checkouts/Parse-SDK-iOS-OSX b/Carthage/Checkouts/Parse-SDK-iOS-OSX new file mode 160000 index 00000000..7a820b75 --- /dev/null +++ b/Carthage/Checkouts/Parse-SDK-iOS-OSX @@ -0,0 +1 @@ +Subproject commit 7a820b75c6726808475af9ce705053ff0e8cbd11 diff --git a/Carthage/Checkouts/SocketRocket b/Carthage/Checkouts/SocketRocket new file mode 160000 index 00000000..954c9478 --- /dev/null +++ b/Carthage/Checkouts/SocketRocket @@ -0,0 +1 @@ +Subproject commit 954c9478b5710903a485c68fe046e65293e2c900 diff --git a/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj b/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj index 00624c73..9a1ecc23 100644 --- a/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj +++ b/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj @@ -158,7 +158,7 @@ F519CBA91CA9CA04005295C0 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = parse; TargetAttributes = { F509D5311CA9E597007B15B0 = { @@ -292,6 +292,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 46BB59B59BEB1C1B30D1528A /* Pods-LiveQueryDemo-ObjC.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = "$(SRCROOT)/LiveQueryDemo-ObjC/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; @@ -304,6 +305,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = BBA908F914DAEEBB466454E2 /* Pods-LiveQueryDemo-ObjC.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = "$(SRCROOT)/LiveQueryDemo-ObjC/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; @@ -326,8 +328,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -370,8 +374,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; diff --git a/Examples/LiveQueryDemo-ObjC.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo-ObjC.xcscheme b/Examples/LiveQueryDemo-ObjC.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo-ObjC.xcscheme index 99ab4ab4..f6701f97 100644 --- a/Examples/LiveQueryDemo-ObjC.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo-ObjC.xcscheme +++ b/Examples/LiveQueryDemo-ObjC.xcodeproj/xcshareddata/xcschemes/LiveQueryDemo-ObjC.xcscheme @@ -1,6 +1,6 @@ ? + fileprivate var currentChatRoom: Room? + fileprivate var subscription: Subscription? var connected: Bool { return currentChatRoom != nil } - var messagesQuery: PFQuery { + var messagesQuery: PFQuery { return (Message.query()? .whereKey("roomName", equalTo: currentChatRoom!.name!) - .orderByAscending("createdAt"))! + .order(byAscending: "createdAt")) as! PFQuery } - func connectToChatRoom(room: String) { + func connectToChatRoom(_ room: String) { if connected { disconnectFromChatRoom() } - Room.query()?.whereKey("name", equalTo: room).getFirstObjectInBackground().continueWithBlock { task in + Room.query()?.whereKey("name", equalTo: room).getFirstObjectInBackground().continue({ task in self.currentChatRoom = task.result as? Room print("Connected to room \(self.currentChatRoom?.name ?? "null")") @@ -45,16 +45,16 @@ class ChatRoomManager { self.subscribeToUpdates() return nil - } + }) } func disconnectFromChatRoom() { liveQueryClient.unsubscribe(messagesQuery, handler: subscription!) } - func sendMessage(msg: String) { + func sendMessage(_ msg: String) { let message = Message() - message.author = PFUser.currentUser() + message.author = PFUser.current() message.authorName = message.author?.username message.message = msg message.room = currentChatRoom @@ -64,44 +64,44 @@ class ChatRoomManager { } func printPriorMessages() { - messagesQuery.findObjectsInBackground().continueWithBlock() { task in + messagesQuery.findObjectsInBackground().continue({ task in (task.result as? [Message])?.forEach(self.printMessage) return nil - } + }) } func subscribeToUpdates() { subscription = liveQueryClient .subscribe(messagesQuery) - .handle(Event.Created) { _, message in + .handle(Event.created) { _, message in self.printMessage(message) } } - private func printMessage(message: Message) { - let createdAt = message.createdAt ?? NSDate() + fileprivate func printMessage(_ message: Message) { + let createdAt = message.createdAt ?? Date() print("\(createdAt) \(message.authorName ?? "unknown"): \(message.message ?? "")") } } class InputManager { - let stdinChannel = dispatch_io_create(DISPATCH_IO_STREAM, STDIN_FILENO, dispatch_get_main_queue()) { _ in } + let stdinChannel = DispatchIO(__type: DispatchIO.StreamType.stream.rawValue, fd: STDIN_FILENO, queue: DispatchQueue.main) { _ in } let chatManager: ChatRoomManager init(chatManager: ChatRoomManager) { self.chatManager = chatManager - dispatch_io_set_low_water(stdinChannel, 1) - dispatch_io_read(stdinChannel, 0, Int.max, dispatch_get_main_queue(), handleInput) + stdinChannel.setLimit(lowWater: 1) + stdinChannel.read(offset: 0, length: Int.max, queue: DispatchQueue.main, ioHandler: handleInput) } - private func handleInput(done: Bool, data: dispatch_data_t?, error: Int32) { + fileprivate func handleInput(_ done: Bool, data: DispatchData?, error: Int32) { guard - let data = data as? NSData, - let inputString = String(data: data, encoding: NSUTF8StringEncoding)? - .stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) else { + let inputString = data?.withUnsafeBytes(body: {(b: UnsafePointer) -> String? in + return String(cString: b) + })?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) else { return } @@ -117,15 +117,15 @@ print("Enter username: ") let username = readLine()! let password = "Enter password for \(username): ".withCString { - String(UTF8String: getpass($0))! + String(validatingUTF8: getpass($0))! } let chatManager = ChatRoomManager() let inputManager = InputManager(chatManager: chatManager) -PFUser.logInWithUsernameInBackground(username, password: password).continueWithBlock { task in +PFUser.logInWithUsername(inBackground: username, password: password).continue({ task in print("Enter chat room to connect to: ") return nil -} +}) -dispatch_main() +dispatchMain() diff --git a/Podfile b/Podfile index e0d3f5fe..62692f7e 100644 --- a/Podfile +++ b/Podfile @@ -3,13 +3,22 @@ workspace 'ParseLiveQuery.xcworkspace' def commonPods pod 'Parse' - pod 'Bolts-Swift' + pod 'Bolts-Swift', :git => 'https://github.com/BoltsFramework/Bolts-Swift.git', tag: '1.3.0' pod 'SocketRocket' end +post_install do |installer| + # Disable bitcode for now. Specifically needed for HockeySDK and ARAnalytics. + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['SWIFT_VERSION'] = '3.0' + end + end +end + target 'ParseLiveQuery-OSX' do project 'Sources/ParseLiveQuery.xcodeproj' - platform :osx, '10.9' + platform :osx, '10.10' commonPods end @@ -23,14 +32,14 @@ end target 'LiveQueryDemo' do project 'Examples/LiveQueryDemo.xcodeproj' - platform :osx, '10.9' + platform :osx, '10.10' commonPods end target 'LiveQueryDemo-ObjC' do project 'Examples/LiveQueryDemo-ObjC.xcodeproj' - platform :osx, '10.9' + platform :osx, '10.10' commonPods end diff --git a/Podfile.lock b/Podfile.lock index 95ea07a5..5b4ac929 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,21 +1,31 @@ PODS: - - Bolts-Swift (1.2.0) + - Bolts-Swift (1.3.0) - Bolts/Tasks (1.8.4) - Parse (1.14.2): - Bolts/Tasks (~> 1.8) - SocketRocket (0.5.1) DEPENDENCIES: - - Bolts-Swift + - Bolts-Swift (from `https://github.com/BoltsFramework/Bolts-Swift.git`, tag `1.3.0`) - Parse - SocketRocket +EXTERNAL SOURCES: + Bolts-Swift: + :git: https://github.com/BoltsFramework/Bolts-Swift.git + :tag: 1.3.0 + +CHECKOUT OPTIONS: + Bolts-Swift: + :git: https://github.com/BoltsFramework/Bolts-Swift.git + :tag: 1.3.0 + SPEC CHECKSUMS: Bolts: 8a7995239dbe724f9cba2248b766d48b7ebdd322 - Bolts-Swift: ac4e7d26719ed0f73aa85b9310da1648105fbde3 + Bolts-Swift: fa98d1b59fc1acea9b21a21306dcdca1c85e3737 Parse: 4335d65f40cb3d43190d723144bbe1afb9c38230 SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531 -PODFILE CHECKSUM: f78cfa7c25dd713e93d9018d0086646c1d4623bc +PODFILE CHECKSUM: 6e85eacd328c6d22732f2290677ff90162634615 COCOAPODS: 1.0.1 diff --git a/README.md b/README.md index 8f2742a2..8ce00fe0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Parse LiveQuery Client for iOS/OSX [![Platforms][platforms-svg]][platforms-link] +[![Carthage compatible][carthage-svg]][carthage-link] [![Podspec][podspec-svg]][podspec-link] [![License][license-svg]][license-link] @@ -79,3 +80,7 @@ We want to make contributing to this project as easy and transparent as possible [platforms-svg]: http://img.shields.io/cocoapods/p/ParseLiveQuery.svg?style=flat [platforms-link]: https://github.com/ParsePlatform/ParseLiveQuery-iOS-OSX + + [carthage-svg]:https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat + [carthage-link]:https://github.com/Carthage/Carthage + diff --git a/Sources/ParseLiveQuery.xcodeproj/project.pbxproj b/Sources/ParseLiveQuery.xcodeproj/project.pbxproj index e4d798c3..ac2412a1 100644 --- a/Sources/ParseLiveQuery.xcodeproj/project.pbxproj +++ b/Sources/ParseLiveQuery.xcodeproj/project.pbxproj @@ -9,11 +9,12 @@ /* Begin PBXBuildFile section */ 0632EDD41CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0632EDD31CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift */; }; 0632EDD51CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0632EDD31CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift */; }; + 4A819D9D1D937866009C0F61 /* ObjCCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */; }; + 4A819D9E1D93786A009C0F61 /* ObjCCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */; }; 629DC3BE90DA87A7857677D2 /* Pods_ParseLiveQuery_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2643D85A7565FC20EE144C /* Pods_ParseLiveQuery_iOS.framework */; }; DE7126BDB27E5DDB1C21490A /* Pods_ParseLiveQuery_OSX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF5A55E51D52E372CD28FF08 /* Pods_ParseLiveQuery_OSX.framework */; }; F534A5B21BDAFE0200CBD11A /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534A5B11BDAFE0200CBD11A /* Subscription.swift */; }; F534A5B41BDB09CE00CBD11A /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534A5B31BDB09CE00CBD11A /* Operation.swift */; }; - F54D58B61C8E33D9009F8D6C /* ObjCCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */; }; F54D58B81C8E3446009F8D6C /* ClientPrivate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B71C8E3446009F8D6C /* ClientPrivate.swift */; }; F54D58BA1C8E345F009F8D6C /* BoltsHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B91C8E345F009F8D6C /* BoltsHelpers.swift */; }; F59CA92F1C8E496200329737 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59CA92E1C8E496200329737 /* Errors.swift */; }; @@ -24,7 +25,6 @@ F5A88F511C9B7341002F0E0D /* BoltsHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B91C8E345F009F8D6C /* BoltsHelpers.swift */; }; F5A88F521C9B7341002F0E0D /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5591BA31BD720E10072F966 /* Client.swift */; }; F5A88F531C9B7341002F0E0D /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534A5B11BDAFE0200CBD11A /* Subscription.swift */; }; - F5A88F541C9B7341002F0E0D /* ObjCCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54D58B51C8E33D9009F8D6C /* ObjCCompat.swift */; }; F5A88F551C9B7341002F0E0D /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59CA92E1C8E496200329737 /* Errors.swift */; }; F5A88F561C9B7341002F0E0D /* PFQuery+Subscribe.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A88F491C9B6EBA002F0E0D /* PFQuery+Subscribe.swift */; }; F5D965351BD99DA200C3AAFC /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5591BA31BD720E10072F966 /* Client.swift */; }; @@ -222,11 +222,15 @@ F5256FC51BD71F9A0052FB8A /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0710; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Parse; TargetAttributes = { F5903CE91BD999C500C3EFFE = { CreatedOnToolsVersion = 7.1; + LastSwiftMigration = 0800; + }; + F5A9BFB61BE0248D00E78326 = { + LastSwiftMigration = 0800; }; }; }; @@ -337,13 +341,13 @@ F54D58B81C8E3446009F8D6C /* ClientPrivate.swift in Sources */, F5D965351BD99DA200C3AAFC /* Client.swift in Sources */, 0632EDD51CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */, - F54D58B61C8E33D9009F8D6C /* ObjCCompat.swift in Sources */, F54D58BA1C8E345F009F8D6C /* BoltsHelpers.swift in Sources */, F5D965381BD99DA200C3AAFC /* QueryEncoder.swift in Sources */, F534A5B21BDAFE0200CBD11A /* Subscription.swift in Sources */, F59CA92F1C8E496200329737 /* Errors.swift in Sources */, F534A5B41BDB09CE00CBD11A /* Operation.swift in Sources */, F5A88F4A1C9B6EBA002F0E0D /* PFQuery+Subscribe.swift in Sources */, + 4A819D9E1D93786A009C0F61 /* ObjCCompat.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -351,7 +355,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - F5A88F541C9B7341002F0E0D /* ObjCCompat.swift in Sources */, F5A88F531C9B7341002F0E0D /* Subscription.swift in Sources */, 0632EDD41CA1A6DB00DD3CB8 /* Parse+LiveQuery.swift in Sources */, F5A88F511C9B7341002F0E0D /* BoltsHelpers.swift in Sources */, @@ -361,6 +364,7 @@ F5A88F521C9B7341002F0E0D /* Client.swift in Sources */, F5A88F4F1C9B7341002F0E0D /* Operation.swift in Sources */, F5A88F561C9B7341002F0E0D /* PFQuery+Subscribe.swift in Sources */, + 4A819D9D1D937866009C0F61 /* ObjCCompat.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -371,7 +375,24 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.10; ONLY_ACTIVE_ARCH = YES; @@ -382,8 +403,26 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.10; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -391,6 +430,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 89BFA3478A42D22F84D9F19C /* Pods-ParseLiveQuery-OSX.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGNING_REQUIRED = NO; COMBINE_HIDPI_IMAGES = YES; @@ -402,12 +442,13 @@ INFOPLIST_FILE = ParseLiveQuery/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = com.parse.livequery.osx; PRODUCT_NAME = ParseLiveQuery; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -415,6 +456,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9A79B9CA1B493BADC66AE15A /* Pods-ParseLiveQuery-OSX.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGNING_REQUIRED = NO; COMBINE_HIDPI_IMAGES = YES; @@ -426,11 +468,12 @@ INFOPLIST_FILE = ParseLiveQuery/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = com.parse.livequery.osx; PRODUCT_NAME = ParseLiveQuery; SDKROOT = macosx; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -438,6 +481,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = FC3C8121FAAE363257898195 /* Pods-ParseLiveQuery-iOS.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGNING_REQUIRED = NO; DEFINES_MODULE = YES; @@ -453,7 +497,9 @@ PRODUCT_NAME = ParseLiveQuery; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_INSTALL_OBJC_HEADER = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -462,6 +508,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7A40A16386D0D6B38F8B2F07 /* Pods-ParseLiveQuery-iOS.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGNING_REQUIRED = NO; DEFINES_MODULE = YES; @@ -477,6 +524,8 @@ PRODUCT_NAME = ParseLiveQuery; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Sources/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-OSX.xcscheme b/Sources/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-OSX.xcscheme index ebc61a42..14f6d441 100644 --- a/Sources/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-OSX.xcscheme +++ b/Sources/ParseLiveQuery.xcodeproj/xcshareddata/xcschemes/ParseLiveQuery-OSX.xcscheme @@ -1,6 +1,6 @@ RequestId var subscriptions = [SubscriptionRecord]() - let queue = dispatch_queue_create("com.parse.livequery", DISPATCH_QUEUE_SERIAL) + 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(). @@ -47,9 +47,10 @@ public class Client: NSObject { - parameter clientKey: The client key to use */ public init(server: String, applicationId: String? = nil, clientKey: String? = nil) { - guard let components = NSURLComponents(string: server) else { + guard let cmpts = URLComponents(string: server) else { fatalError("Server should be a valid URL.") } + var components = cmpts components.scheme = components.scheme == "https" ? "wss" : "ws" // Simple incrementing generator - can't use ++, that operator is deprecated! @@ -62,24 +63,25 @@ public class Client: NSObject { self.applicationId = applicationId ?? Parse.validatedCurrentConfiguration().applicationId! self.clientKey = clientKey ?? Parse.validatedCurrentConfiguration().clientKey - self.host = components.URL! + 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. - private class Storage { - static var onceToken: dispatch_once_t = 0 + fileprivate class Storage { + private static var __once: () = { + sharedStorage = Storage() + }() + static var onceToken: Int = 0 static var sharedStorage: Storage! static var shared: Storage { - dispatch_once(&onceToken) { - sharedStorage = Storage() - } + _ = Storage.__once return sharedStorage } - let queue: dispatch_queue_t = dispatch_queue_create("com.parse.livequery.client.storage", DISPATCH_QUEUE_SERIAL) + let queue: DispatchQueue = DispatchQueue(label: "com.parse.livequery.client.storage", attributes: []) var client: Client? } @@ -89,7 +91,7 @@ extension Client { get { let storage = Storage.shared var client: Client? - dispatch_sync(storage.queue) { + storage.queue.sync { client = storage.client if client == nil { let configuration = Parse.validatedCurrentConfiguration() @@ -105,7 +107,7 @@ extension Client { } set { let storage = Storage.shared - dispatch_sync(storage.queue) { + storage.queue.sync { storage.client = newValue } } @@ -122,11 +124,12 @@ extension Client { - returns: The subscription that has just been registered */ - public func subscribe( - query: PFQuery, + public func subscribe( + _ query: PFQuery, subclassType: T.Type = T.self - ) -> Subscription { - return subscribe(query, handler: Subscription()) + ) -> Subscription where T: PFObject { + return Subscription() + //return subscribe(query, handler: Subscription()) } /** @@ -136,11 +139,11 @@ extension Client { - parameter handler: A custom subscription handler. - returns: Your subscription handler, for easy chaining. - */ - public func subscribe( - query: PFQuery, - handler: T - ) -> T { + */ + public func subscribe( + _ query: PFQuery, + handler: U + ) -> U where T: PFObject, U: SubscriptionHandling, U.PFGenericObject == T { let subscriptionRecord = SubscriptionRecord( query: query, requestId: requestIdGenerator(), @@ -149,7 +152,7 @@ extension Client { subscriptions.append(subscriptionRecord) if socket?.readyState == .OPEN { - sendOperationAsync(.Subscribe(requestId: subscriptionRecord.requestId, query: query)) + _ = sendOperationAsync(.subscribe(requestId: subscriptionRecord.requestId, query: query as! PFQuery)) } else if socket == nil || socket?.readyState != .CONNECTING { if !userDisconnected { reconnect() @@ -166,8 +169,7 @@ extension Client { - parameter query: The query to unsubscribe from. */ - @objc(unsubscribeFromQuery:) - public func unsubscribe(query: PFQuery) { + public func unsubscribe(_ query: PFQuery) where T: PFObject { unsubscribe { $0.query == query } } @@ -177,15 +179,15 @@ extension Client { - parameter query: The query to unsubscribe from. - parameter handler: The specific handler to unsubscribe from. */ - public func unsubscribe(query: PFQuery, handler: T) { + public func unsubscribe(_ query: PFQuery, handler: T) where T: SubscriptionHandling, U: PFObject { unsubscribe { $0.query == query && $0.subscriptionHandler === handler } } - func unsubscribe(@noescape matching matcher: SubscriptionRecord -> Bool) { + func unsubscribe(matching matcher: @escaping (SubscriptionRecord) -> Bool) { subscriptions.filter { matcher($0) }.forEach { - sendOperationAsync(.Unsubscribe(requestId: $0.requestId)) + _ = sendOperationAsync(.unsubscribe(requestId: $0.requestId)) } } @@ -201,13 +203,13 @@ extension Client { public func reconnect() { socket?.close() socket = { - let socket = SRWebSocket(URL: host) + let socket: SRWebSocket = SRWebSocket(url: host) socket.delegate = self socket.setDelegateDispatchQueue(queue) socket.open() userDisconnected = false return socket - }() + }() } /** @@ -225,4 +227,4 @@ extension Client { self.socket = nil userDisconnected = true } -} \ No newline at end of file +} diff --git a/Sources/ParseLiveQuery/Internal/BoltsHelpers.swift b/Sources/ParseLiveQuery/Internal/BoltsHelpers.swift index 68b24a15..b57c6d5b 100644 --- a/Sources/ParseLiveQuery/Internal/BoltsHelpers.swift +++ b/Sources/ParseLiveQuery/Internal/BoltsHelpers.swift @@ -12,8 +12,8 @@ import BoltsSwift let unknownDomain = "unknown" -func objcTask(task: Task) -> BFTask { - let taskCompletionSource = BFTaskCompletionSource() +func objcTask(_ task: Task) -> BFTask where T: AnyObject { + let taskCompletionSource = BFTaskCompletionSource() task.continueWith { task in if task.cancelled { taskCompletionSource.trySetCancelled() @@ -27,12 +27,12 @@ func objcTask(task: Task) -> BFTask { return taskCompletionSource.task } -func swiftTask(task: BFTask) -> Task { +func swiftTask(_ task: BFTask) -> Task { let taskCompletionSource = TaskCompletionSource() - task.continueWithBlock { task in - if task.cancelled { + task.continue({ task in + if task.isCancelled { taskCompletionSource.tryCancel() - } else if let error = task.error where task.faulted { + } else if let error = task.error , task.isFaulted { taskCompletionSource.trySet(error: error) } else if let result = task.result { taskCompletionSource.trySet(result: result) @@ -40,6 +40,6 @@ func swiftTask(task: BFTask) -> Task { fatalError("Unknown task state") } return nil - } + }) return taskCompletionSource.task } diff --git a/Sources/ParseLiveQuery/Internal/ClientPrivate.swift b/Sources/ParseLiveQuery/Internal/ClientPrivate.swift index ce23c122..92935918 100644 --- a/Sources/ParseLiveQuery/Internal/ClientPrivate.swift +++ b/Sources/ParseLiveQuery/Internal/ClientPrivate.swift @@ -12,7 +12,7 @@ import Parse import SocketRocket import BoltsSwift -private func parseObject(objectDictionary: [String:AnyObject]) throws -> T { +private func parseObject(_ objectDictionary: [String:AnyObject]) throws -> T { guard let parseClassName = objectDictionary["className"] as? String else { throw LiveQueryErrors.InvalidJSONError(json: objectDictionary, expectedKey: "parseClassName") } @@ -24,7 +24,7 @@ private func parseObject(objectDictionary: [String:AnyObject]) thro // Map of strings to closures to determine if the key is valid. Allows for more advanced checking of // classnames and such. - let invalidKeys: [String:Void->Bool] = [ + let invalidKeys: [String:(Void)->Bool] = [ "objectId": { true }, "parseClassName": { true }, "sessionToken": { parseClassName == "_User" } @@ -45,22 +45,21 @@ private func parseObject(objectDictionary: [String:AnyObject]) thro extension Client { class SubscriptionRecord { weak var subscriptionHandler: AnyObject? - // HandlerClosure captures the generic type info passed into the constructor of SubscriptionRecord, // and 'unwraps' it so that it can be used with just a 'PFObject' instance. // Technically, this should be a compiler no-op, as no witness tables should be used as 'PFObject' currently inherits from NSObject. // Should we make PFObject ever a native swift class without the backing Objective-C runtime however, // this becomes extremely important to have, and makes a ton more sense than just unsafeBitCast-ing everywhere. var eventHandlerClosure: (Event, Client) -> Void - var errorHandlerClosure: (ErrorType, Client) -> Void - var subscribeHandlerClosure: Client -> Void - var unsubscribeHandlerClosure: Client -> Void + var errorHandlerClosure: (Error, Client) -> Void + var subscribeHandlerClosure: (Client) -> Void + var unsubscribeHandlerClosure: (Client) -> Void - let query: PFQuery + let query: PFQuery let requestId: RequestId - init(query: PFQuery, requestId: RequestId, handler: T) { - self.query = query + init(query: PFQuery, requestId: RequestId, handler: T) where T:SubscriptionHandling { + self.query = query as! PFQuery self.requestId = requestId subscriptionHandler = handler @@ -105,7 +104,8 @@ extension 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 { @@ -126,12 +126,23 @@ func == (first: Client.RequestId, second: Client.RequestId) -> Bool { // --------------- extension Client: SRWebSocketDelegate { - public func webSocketDidOpen(webSocket: SRWebSocket!) { + public func webSocket(_ webSocket: SRWebSocket!, didReceiveMessage message: Any!) { + guard let messageString = message as? String else { + fatalError("Socket got into inconsistent state and received \(message) instead.") + } + handleOperationAsync(messageString).continueWith { task in + if let error = task.error { + print("Error: \(error)") + } + } + } + + public func webSocketDidOpen(_ webSocket: SRWebSocket!) { // TODO: Add support for session token and user authetication. - self.sendOperationAsync(.Connect(applicationId: applicationId, sessionToken: "")) + _ = self.sendOperationAsync(.connect(applicationId: applicationId, sessionToken: "")) } - public func webSocket(webSocket: SRWebSocket!, didFailWithError error: NSError!) { + public func webSocket(_ webSocket: SRWebSocket!, didFailWithError error: Error!) { print("Error: \(error)") if !userDisconnected { @@ -139,7 +150,7 @@ extension Client: SRWebSocketDelegate { } } - public func webSocket(webSocket: SRWebSocket!, didCloseWithCode code: Int, reason: String!, wasClean: Bool) { + public func webSocket(_ webSocket: SRWebSocket!, didCloseWithCode code: Int, reason: String!, wasClean: Bool) { print("code: \(code) reason: \(reason)") // TODO: Better retry logic, unless `disconnect()` was explicitly called @@ -147,17 +158,6 @@ extension Client: SRWebSocketDelegate { reconnect() } } - - public func webSocket(webSocket: SRWebSocket!, didReceiveMessage message: AnyObject?) { - guard let messageString = message as? String else { - fatalError("Socket got into inconsistent state and received \(message) instead.") - } - handleOperationAsync(messageString).continueWith { task in - if let error = task.error { - print("Error: \(error)") - } - } - } } // ------------------- @@ -165,27 +165,27 @@ extension Client: SRWebSocketDelegate { // ------------------- extension Event { - init(serverResponse: ServerResponse, inout requestId: Client.RequestId) throws { + init(serverResponse: ServerResponse, requestId: inout Client.RequestId) throws { switch serverResponse { - case .Enter(let reqId, let object): + case .enter(let reqId, let object): requestId = reqId - self = .Entered(try parseObject(object)) + self = .entered(try parseObject(object)) - case .Leave(let reqId, let object): + case .leave(let reqId, let object): requestId = reqId - self = .Left(try parseObject(object)) + self = .left(try parseObject(object)) - case .Create(let reqId, let object): + case .create(let reqId, let object): requestId = reqId - self = .Created(try parseObject(object)) + self = .created(try parseObject(object)) - case .Update(let reqId, let object): + case .update(let reqId, let object): requestId = reqId - self = .Updated(try parseObject(object)) + self = .updated(try parseObject(object)) - case .Delete(let reqId, let object): + case .delete(let reqId, let object): requestId = reqId - self = .Deleted(try parseObject(object)) + self = .deleted(try parseObject(object)) default: fatalError("Invalid state reached") } @@ -193,73 +193,72 @@ extension Event { } extension Client { - private func subscriptionRecord(requestId: RequestId) -> SubscriptionRecord? { + fileprivate func subscriptionRecord(_ requestId: RequestId) -> SubscriptionRecord? { guard - let recordIndex = self.subscriptions.indexOf({ $0.requestId == requestId }), - let record: SubscriptionRecord = self.subscriptions[recordIndex] - where record.subscriptionHandler != nil else { + let recordIndex = self.subscriptions.index(where: { $0.requestId == requestId }) else { return nil } - - return record + let record = self.subscriptions[recordIndex] + return record.subscriptionHandler != nil ? record : nil } - func sendOperationAsync(operation: ClientOperation) -> Task { - return Task(.Queue(queue)) { + func sendOperationAsync(_ operation: ClientOperation) -> Task { + return Task(.queue(queue)) { let jsonEncoded = operation.JSONObjectRepresentation - let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonEncoded, options: NSJSONWritingOptions(rawValue: 0)) - let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding) + let jsonData = try JSONSerialization.data(withJSONObject: jsonEncoded, options: JSONSerialization.WritingOptions(rawValue: 0)) + let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) self.socket?.send(jsonString) } } - func handleOperationAsync(string: String) -> Task { - return Task(.Queue(queue)) { + func handleOperationAsync(_ string: String) -> Task { + return Task(.queue(queue)) { guard - let jsonData = string.dataUsingEncoding(NSUTF8StringEncoding), - let jsonDecoded = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions(rawValue: 0)) + 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) + let response: ServerResponse = try? ServerResponse(json: jsonDecoded) else { throw LiveQueryErrors.InvalidResponseError(response: string) } + + switch response { - case .Connected: + case .connected: self.subscriptions.forEach { - self.sendOperationAsync(.Subscribe(requestId: $0.requestId, query: $0.query)) + _ = self.sendOperationAsync(.subscribe(requestId: $0.requestId, query: $0.query)) } - case .Redirect: + case .redirect: // TODO: Handle redirect. break - case .Subscribed(let requestId): + case .subscribed(let requestId): self.subscriptionRecord(requestId)?.subscribeHandlerClosure(self) - case .Unsubscribed(let requestId): + case .unsubscribed(let requestId): guard - let recordIndex = self.subscriptions.indexOf({ $0.requestId == requestId }), - let record: SubscriptionRecord = self.subscriptions[recordIndex] else { + let recordIndex = self.subscriptions.index(where: { $0.requestId == requestId }) + else { break } - + let record: SubscriptionRecord = self.subscriptions[recordIndex] record.unsubscribeHandlerClosure(self) - self.subscriptions.removeAtIndex(recordIndex) + self.subscriptions.remove(at: recordIndex) - case .Create, .Delete, .Enter, .Leave, .Update: + case .create, .delete, .enter, .leave, .update: + var requestId: RequestId = RequestId(value: 0) guard - var requestId: RequestId = RequestId(value: 0), - let event: Event = try Event(serverResponse: response, requestId: &requestId), + let event: Event = try? Event(serverResponse: response, requestId: &requestId), let record = self.subscriptionRecord(requestId) else { break } - record.eventHandlerClosure(event, self) - case .Error(let requestId, let code, let error, let reconnect): + 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) diff --git a/Sources/ParseLiveQuery/Internal/Errors.swift b/Sources/ParseLiveQuery/Internal/Errors.swift index f54340a9..3ec35a22 100644 --- a/Sources/ParseLiveQuery/Internal/Errors.swift +++ b/Sources/ParseLiveQuery/Internal/Errors.swift @@ -11,12 +11,12 @@ Namespace struct for all errors reported by the Live Query SDK. */ public struct LiveQueryErrors { - private init() {} + fileprivate init() {} /** An error that is reported when the server returns a response that cannot be parsed. */ - public struct InvalidResponseError: ErrorType { + public struct InvalidResponseError: Error { /// Response string of the error. public let response: String } @@ -24,13 +24,13 @@ public struct LiveQueryErrors { /** An error that is reported when the server does not accept a query we've sent to it. */ - public struct InvalidQueryError: ErrorType { + 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: ErrorType { + public struct InvalidJSONError: Error { /// JSON used for matching. public let json: [String:AnyObject] /// Key that was expected to match. @@ -40,7 +40,7 @@ public struct LiveQueryErrors { /** An error that is reported when the live query server encounters an internal error. */ - public struct ServerReportedError: ErrorType { + public struct ServerReportedError: Error { /// Error code reported by the server. public let code: Int /// String error reported by the server. diff --git a/Sources/ParseLiveQuery/Internal/Operation.swift b/Sources/ParseLiveQuery/Internal/Operation.swift index d5debbaa..27984d34 100644 --- a/Sources/ParseLiveQuery/Internal/Operation.swift +++ b/Sources/ParseLiveQuery/Internal/Operation.swift @@ -11,41 +11,41 @@ import Foundation import Parse enum ClientOperation { - case Connect(applicationId: String, sessionToken: String) - case Subscribe(requestId: Client.RequestId, query: PFQuery) - case Unsubscribe(requestId: Client.RequestId) + case connect(applicationId: String, sessionToken: String) + case subscribe(requestId: Client.RequestId, query: PFQuery) + case unsubscribe(requestId: Client.RequestId) - var JSONObjectRepresentation: [String : AnyObject] { + var JSONObjectRepresentation: [String : Any] { switch self { - case .Connect(let applicationId, let sessionToken): + case .connect(let applicationId, let sessionToken): return [ "op": "connect", "applicationId": applicationId, "sessionToken": sessionToken ] - case .Subscribe(let requestId, let query): + case .subscribe(let requestId, let query): return [ "op": "subscribe", "requestId": requestId.value, "query": Dictionary(query: query) ] - case .Unsubscribe(let requestId): + case .unsubscribe(let requestId): return [ "op": "unsubscribe", "requestId": requestId.value ] } } } enum ServerResponse { - case Redirect(url: String) - case Connected() + case redirect(url: String) + case connected() - case Subscribed(requestId: Client.RequestId) - case Unsubscribed(requestId: Client.RequestId) + 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 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) + case error(requestId: Client.RequestId?, code: Int, error: String, reconnect: Bool) init(json: [String : AnyObject]) throws { - func jsonValue(json: [String:AnyObject], _ key: String) throws -> T { + func jsonValue(_ json: [String:AnyObject], _ key: String) throws -> T { guard let value = json[key] as? T else { throw LiveQueryErrors.InvalidJSONError(json: json, expectedKey: key) @@ -53,13 +53,13 @@ enum ServerResponse { return value } - func jsonRequestId(json: [String:AnyObject]) throws -> Client.RequestId { + 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], + _ json: [String:AnyObject], _ eventType: (Client.RequestId, [String : AnyObject]) -> ServerResponse ) throws -> ServerResponse { return eventType(try jsonRequestId(json), try jsonValue(json, "object")) @@ -68,24 +68,24 @@ enum ServerResponse { let rawOperation: String = try jsonValue(json, "op") switch rawOperation { case "connected": - self = .Connected() + self = .connected() case "redirect": - self = .Redirect(url: try jsonValue(json, "url")) + self = .redirect(url: try jsonValue(json, "url")) case "subscribed": - self = .Subscribed(requestId: try jsonRequestId(json)) + self = .subscribed(requestId: try jsonRequestId(json)) case "unsubscribed": - self = .Unsubscribed(requestId: try jsonRequestId(json)) + 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 "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( + self = .error( requestId: try? jsonRequestId(json), code: try jsonValue(json, "code"), error: try jsonValue(json, "error"), diff --git a/Sources/ParseLiveQuery/Internal/QueryEncoder.swift b/Sources/ParseLiveQuery/Internal/QueryEncoder.swift index d2d17d71..9a2b5472 100644 --- a/Sources/ParseLiveQuery/Internal/QueryEncoder.swift +++ b/Sources/ParseLiveQuery/Internal/QueryEncoder.swift @@ -13,20 +13,20 @@ import Parse /** NOTE: This is super hacky, and we need a better answer for this. */ -extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject { - init(query: PFQuery) { +extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject { + init(query: PFQuery) where T: PFObject { self.init() - let queryState = query.valueForKey("state") - if let className = queryState?.valueForKey("parseClassName") { + let queryState = query.value(forKey: "state") as AnyObject? + if let className = queryState?.value(forKey: "parseClassName") { self["className"] = className as? Value } - if let conditions: [String:AnyObject] = queryState?.valueForKey("conditions") as? [String:AnyObject] { + if let conditions: [String:AnyObject] = queryState?.value(forKey: "conditions") as? [String:AnyObject] { self["where"] = conditions.encodedQueryDictionary as? Value } } } -extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject { +extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject { var encodedQueryDictionary: Dictionary { var encodedQueryDictionary = Dictionary() for (key, val) in self { @@ -43,7 +43,7 @@ extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject { } extension PFGeoPoint { - var encodedDictionary: [String:AnyObject] { + var encodedDictionary: [String:Any] { return ["__type": "GeoPoint", "latitude": latitude, "longitude": longitude] diff --git a/Sources/ParseLiveQuery/ObjCCompat.swift b/Sources/ParseLiveQuery/ObjCCompat.swift index 0ac1374b..200a06ee 100644 --- a/Sources/ParseLiveQuery/ObjCCompat.swift +++ b/Sources/ParseLiveQuery/ObjCCompat.swift @@ -18,6 +18,7 @@ import BoltsSwift */ @objc(PFLiveQuerySubscriptionHandling) public protocol ObjCCompat_SubscriptionHandling { + /** Tells the handler that an event has been received from the live query server. @@ -26,7 +27,7 @@ public protocol ObjCCompat_SubscriptionHandling { - parameter client: The live query client which received this event. */ @objc(liveQuery:didRecieveEvent:inClient:) - optional func didRecieveEvent(query: PFQuery, event: ObjCCompat.Event, client: Client) + optional func didRecieveEvent(_ query: PFQuery, event: ObjCCompat.Event, client: Client) /** Tells the handler that an error has been received from the live query server. @@ -36,7 +37,7 @@ public protocol ObjCCompat_SubscriptionHandling { - parameter client: The live query client which received this error. */ @objc(liveQuery:didEncounterError:inClient:) - optional func didRecieveError(query: PFQuery, error: NSError, client: Client) + optional func didRecieveError(_ query: PFQuery, error: NSError, client: Client) /** Tells the handler that a query has been successfully registered with the server. @@ -47,7 +48,7 @@ public protocol ObjCCompat_SubscriptionHandling { - parameter client: The live query client which subscribed this query. */ @objc(liveQuery:didSubscribeInClient:) - optional func didSubscribe(query: PFQuery, client: Client) + optional func didSubscribe(_ query: PFQuery, client: Client) /** Tells the handler that a query has been successfully deregistered from the server. @@ -58,7 +59,7 @@ public protocol ObjCCompat_SubscriptionHandling { - parameter client: The live query client which unsubscribed this query. */ @objc(liveQuery:didUnsubscribeInClient:) - optional func didUnsubscribe(query: PFQuery, client: Client) + optional func didUnsubscribe(_ query: PFQuery, client: Client) } // HACK: Compiler bug causes enums that are declared in structs that are marked as @objc to not actually be emitted by @@ -72,35 +73,35 @@ public protocol ObjCCompat_SubscriptionHandling { @objc public enum PFLiveQueryEventType: Int { /// The object has been updated, and is now included in the query. - case Entered + case entered /// The object has been updated, and is no longer included in the query. - case Left + case left /// The object has been created, and is a part of the query. - case Created + case created /// The object has been updated, and is still a part of the query. - case Updated + case updated /// The object has been deleted, and is no longer included in the query. - case Deleted + case deleted } /** 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 { - private init() { } + fileprivate init() { } /** Represents an update on a specific object from the live query server. */ @objc(PFLiveQueryEvent) - public class Event: NSObject { + open class Event: NSObject { /// Type of the event. @objc - public let type: PFLiveQueryEventType + open let type: PFLiveQueryEventType /// Object this event is for. @objc - public let object: PFObject + open let object: PFObject init(type: PFLiveQueryEventType, object: PFObject) { self.type = type @@ -112,11 +113,11 @@ public struct ObjCCompat { A default implementation of the SubscriptionHandling protocol, using blocks for callbacks. */ @objc(PFLiveQuerySubscription) - public class Subscription: NSObject { - public typealias SubscribeHandler = @convention(block) PFQuery -> Void - public typealias ErrorHandler = @convention(block) (PFQuery, NSError) -> Void - public typealias EventHandler = @convention(block) (PFQuery, Event) -> Void - public typealias ObjectHandler = @convention(block) (PFQuery, PFObject) -> Void + open class Subscription: NSObject { + public typealias SubscribeHandler = @convention(block) (PFQuery) -> Void + public typealias ErrorHandler = @convention(block) (PFQuery, NSError) -> Void + public typealias EventHandler = @convention(block) (PFQuery, Event) -> Void + public typealias ObjectHandler = @convention(block) (PFQuery, PFObject) -> Void var subscribeHandlers = [SubscribeHandler]() var unsubscribeHandlers = [SubscribeHandler]() @@ -130,7 +131,7 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addSubscribeHandler(handler: SubscribeHandler) -> Subscription { + open func addSubscribeHandler(_ handler: @escaping SubscribeHandler) -> Subscription { subscribeHandlers.append(handler) return self } @@ -142,7 +143,7 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addUnsubscribeHandler(handler: SubscribeHandler) -> Subscription { + open func addUnsubscribeHandler(_ handler: @escaping SubscribeHandler) -> Subscription { unsubscribeHandlers.append(handler) return self } @@ -154,7 +155,7 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addErrorHandler(handler: ErrorHandler) -> Subscription { + open func addErrorHandler(_ handler: @escaping ErrorHandler) -> Subscription { errorHandlers.append(handler) return self } @@ -166,7 +167,7 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addEventHandler(handler: EventHandler) -> Subscription { + open func addEventHandler(_ handler: @escaping EventHandler) -> Subscription { eventHandlers.append(handler) return self } @@ -178,8 +179,8 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addEnterHandler(handler: ObjectHandler) -> Subscription { - return addEventHandler { $1.type == .Entered ? handler($0, $1.object) : () } + open func addEnterHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .entered ? handler($0, $1.object) : () } } /** @@ -189,8 +190,8 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addLeaveHandler(handler: ObjectHandler) -> Subscription { - return addEventHandler { $1.type == .Left ? handler($0, $1.object) : () } + open func addLeaveHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .left ? handler($0, $1.object) : () } } /** @@ -200,8 +201,8 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addCreateHandler(handler: ObjectHandler) -> Subscription { - return addEventHandler { $1.type == .Created ? handler($0, $1.object) : () } + open func addCreateHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .created ? handler($0, $1.object) : () } } /** @@ -211,8 +212,8 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addUpdateHandler(handler: ObjectHandler) -> Subscription { - return addEventHandler { $1.type == .Updated ? handler($0, $1.object) : () } + open func addUpdateHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .updated ? handler($0, $1.object) : () } } /** @@ -222,36 +223,36 @@ public struct ObjCCompat { - returns: The same subscription, for easy chaining. */ - public func addDeleteHandler(handler: ObjectHandler) -> Subscription { - return addEventHandler { $1.type == .Deleted ? handler($0, $1.object) : () } + open func addDeleteHandler(_ handler: @escaping ObjectHandler) -> Subscription { + return addEventHandler { $1.type == .deleted ? handler($0, $1.object) : () } } } } extension ObjCCompat.Subscription: ObjCCompat_SubscriptionHandling { - func didRecieveEvent(query: PFQuery, event: ObjCCompat.Event, client: Client) { + public func didRecieveEvent(_ query: PFQuery, event: ObjCCompat.Event, client: Client) { eventHandlers.forEach { $0(query, event) } } - func didRecieveError(query: PFQuery, error: NSError, client: Client) { + public func didRecieveError(_ query: PFQuery, error: NSError, client: Client) { errorHandlers.forEach { $0(query, error) } } - func didSubscribe(query: PFQuery, client: Client) { + public func didSubscribe(_ query: PFQuery, client: Client) { subscribeHandlers.forEach { $0(query) } } - func didUnsubscribe(query: PFQuery, client: Client) { + public func didUnsubscribe(_ query: PFQuery, client: Client) { unsubscribeHandlers.forEach { $0(query) } } } extension Client { - private class HandlerConverter: SubscriptionHandling { - typealias PFObjectSubclass = PFObject + fileprivate class HandlerConverter: SubscriptionHandling { + typealias T = PFObject - private static var associatedObjectKey: Int = 0 - private weak var handler: ObjCCompat_SubscriptionHandling? + fileprivate static var associatedObjectKey: Int = 0 + fileprivate weak var handler: ObjCCompat_SubscriptionHandling? init(handler: ObjCCompat_SubscriptionHandling) { self.handler = handler @@ -259,19 +260,19 @@ extension Client { objc_setAssociatedObject(handler, &HandlerConverter.associatedObjectKey, self, .OBJC_ASSOCIATION_RETAIN) } - private func didReceive(event: Event, forQuery query: PFQuery, inClient client: Client) { + fileprivate func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) { handler?.didRecieveEvent?(query, event: ObjCCompat.Event(event: event), client: client) } - private func didEncounter(error: ErrorType, forQuery query: PFQuery, inClient client: Client) { + fileprivate func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) { handler?.didRecieveError?(query, error: error as NSError, client: client) } - private func didSubscribe(toQuery query: PFQuery, inClient client: Client) { + fileprivate func didSubscribe(toQuery query: PFQuery, inClient client: Client) { handler?.didSubscribe?(query, client: client) } - private func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) { + fileprivate func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) { handler?.didUnsubscribe?(query, client: client) } } @@ -286,10 +287,10 @@ extension Client { */ @objc(subscribeToQuery:withHandler:) public func _PF_objc_subscribe( - query: PFQuery, handler: ObjCCompat_SubscriptionHandling + _ query: PFQuery, handler: ObjCCompat_SubscriptionHandling ) -> ObjCCompat_SubscriptionHandling { let swiftHandler = HandlerConverter(handler: handler) - subscribe(query, handler: swiftHandler) + _ = subscribe(query, handler: swiftHandler) return handler } @@ -301,9 +302,9 @@ extension Client { - returns: The subscription that has just been registered. */ @objc(subscribeToQuery:) - public func _PF_objc_subscribe(query: PFQuery) -> ObjCCompat.Subscription { + public func _PF_objc_subscribe(_ query: PFQuery) -> ObjCCompat.Subscription { let subscription = ObjCCompat.Subscription() - _PF_objc_subscribe(query, handler: subscription) + _ = _PF_objc_subscribe(query, handler: subscription) return subscription } @@ -314,7 +315,7 @@ extension Client { - parameter handler: The specific handler to unsubscribe from. */ @objc(unsubscribeFromQuery:withHandler:) - public func _PF_objc_unsubscribe(query: PFQuery, subscriptionHandler: ObjCCompat_SubscriptionHandling) { + public func _PF_objc_unsubscribe(_ query: PFQuery, subscriptionHandler: ObjCCompat_SubscriptionHandling) { unsubscribe { record in guard let handler = record.subscriptionHandler as? HandlerConverter else { @@ -332,11 +333,11 @@ extension ObjCCompat.Event { convenience init(event: ParseLiveQuery.Event) { let results: (type: PFLiveQueryEventType, object: PFObject) = { switch event { - case .Entered(let object): return (.Entered, object) - case .Left(let object): return (.Left, object) - case .Created(let object): return (.Created, object) - case .Updated(let object): return (.Updated, object) - case .Deleted(let object): return (.Deleted, object) + 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) } }() @@ -353,6 +354,6 @@ extension PFQuery { */ @objc(subscribe) public func _PF_objc_subscribe() -> ObjCCompat.Subscription { - return Client.shared._PF_objc_subscribe(self) + return Client.shared._PF_objc_subscribe(self as! PFQuery) } } diff --git a/Sources/ParseLiveQuery/PFQuery+Subscribe.swift b/Sources/ParseLiveQuery/PFQuery+Subscribe.swift index b209ddfb..a8ebedb5 100644 --- a/Sources/ParseLiveQuery/PFQuery+Subscribe.swift +++ b/Sources/ParseLiveQuery/PFQuery+Subscribe.swift @@ -10,17 +10,4 @@ import Foundation import Parse -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. - - parameter subclassType: The type of the subscription to register for. - This can usually be inferred from the context and rarely should be set. - - - returns: The created subscription for observing. - */ - public func subscribe(subclassType: T.Type = T.self) -> Subscription { - return Client.shared.subscribe(self) - } -} diff --git a/Sources/ParseLiveQuery/Subscription.swift b/Sources/ParseLiveQuery/Subscription.swift index 38a72498..451da315 100644 --- a/Sources/ParseLiveQuery/Subscription.swift +++ b/Sources/ParseLiveQuery/Subscription.swift @@ -18,7 +18,7 @@ import BoltsSwift */ public protocol SubscriptionHandling: AnyObject { /// The type of the PFObject subclass that this handler uses. - associatedtype PFObjectSubclass: PFObject + associatedtype PFGenericObject: PFObject /** Tells the handler that an event has been received from the live query server. @@ -27,7 +27,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that the event occurred on. - parameter client: The live query client which received this event. */ - func didReceive(event: Event, forQuery query: PFQuery, inClient client: Client) + func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) /** Tells the handler that an error has been received from the live query server. @@ -36,7 +36,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that the error occurred on. - parameter client: The live query client which received this error. */ - func didEncounter(error: ErrorType, forQuery query: PFQuery, inClient client: Client) + func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) /** Tells the handler that a query has been successfully registered with the server. @@ -46,7 +46,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that has been subscribed. - parameter client: The live query client which subscribed this query. */ - func didSubscribe(toQuery query: PFQuery, inClient client: Client) + func didSubscribe(toQuery query: PFQuery, inClient client: Client) /** Tells the handler that a query has been successfully deregistered from the server. @@ -56,7 +56,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that has been unsubscribed. - parameter client: The live query client which unsubscribed this query. */ - func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) + func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) } /** @@ -68,29 +68,29 @@ public protocol SubscriptionHandling: AnyObject { - 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 { +public enum Event where T: PFObject { /// The object has been updated, and is now included in the query - case Entered(T) + case entered(T) /// The object has been updated, and is no longer included in the query - case Left(T) + case left(T) /// The object has been created, and is a part of the query - case Created(T) + case created(T) /// The object has been updated, and is still a part of the query - case Updated(T) + case updated(T) /// The object has been deleted, and is no longer included in the query - case Deleted(T) + case deleted(T) - init(event: Event) { + init(event: Event) where V: PFObject { 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) + 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() } } @@ -98,11 +98,11 @@ public enum Event { private func == (lhs: Event, rhs: Event) -> Bool { switch (lhs, rhs) { - case (.Entered(let obj1), .Entered(let obj2)): return obj1 == obj2 - case (.Left(let obj1), .Left(let obj2)): return obj1 == obj2 - case (.Created(let obj1), .Created(let obj2)): return obj1 == obj2 - case (.Updated(let obj1), .Updated(let obj2)): return obj1 == obj2 - case (.Deleted(let obj1), .Deleted(let obj2)): return obj1 == obj2 + 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 } } @@ -110,11 +110,11 @@ private func == (lhs: Event, rhs: Event) -> Bool { /** A default implementation of the SubscriptionHandling protocol, using closures for callbacks. */ -public class Subscription: SubscriptionHandling { - private var errorHandlers: [(PFQuery, ErrorType) -> Void] = [] - private var eventHandlers: [(PFQuery, Event) -> Void] = [] - private var subscribeHandlers: [PFQuery -> Void] = [] - private var unsubscribeHandlers: [PFQuery -> Void] = [] +open class Subscription: SubscriptionHandling where T: PFObject { + fileprivate var errorHandlers: [(PFQuery, Error) -> Void] = [] + fileprivate var eventHandlers: [(PFQuery, Event) -> Void] = [] + fileprivate var subscribeHandlers: [(PFQuery) -> Void] = [] + fileprivate var unsubscribeHandlers: [(PFQuery) -> Void] = [] /** Creates a new subscription that can be used to handle updates. @@ -129,7 +129,7 @@ public class Subscription: SubscriptionHandling { - returns: The same subscription, for easy chaining */ - public func handleError(handler: (PFQuery, ErrorType) -> Void) -> Subscription { + open func handleError(_ handler: @escaping (PFQuery, Error) -> Void) -> Subscription { errorHandlers.append(handler) return self } @@ -141,7 +141,7 @@ public class Subscription: SubscriptionHandling { - returns: The same subscription, for easy chaining. */ - public func handleEvent(handler: (PFQuery, Event) -> Void) -> Subscription { + open func handleEvent(_ handler: @escaping (PFQuery, Event) -> Void) -> Subscription { eventHandlers.append(handler) return self } @@ -153,7 +153,7 @@ public class Subscription: SubscriptionHandling { - returns: The same subscription, for easy chaining. */ - public func handleSubscribe(handler: PFQuery -> Void) -> Subscription { + open func handleSubscribe(_ handler: @escaping (PFQuery) -> Void) -> Subscription { subscribeHandlers.append(handler) return self } @@ -165,7 +165,7 @@ public class Subscription: SubscriptionHandling { - returns: The same subscription, for easy chaining. */ - public func handleUnsubscribe(handler: PFQuery -> Void) -> Subscription { + open func handleUnsubscribe(_ handler: @escaping (PFQuery) -> Void) -> Subscription { unsubscribeHandlers.append(handler) return self } @@ -176,19 +176,19 @@ public class Subscription: SubscriptionHandling { // --------------- public typealias PFObjectSubclass = T - public func didReceive(event: Event, forQuery query: PFQuery, inClient client: Client) { + open func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) { eventHandlers.forEach { $0(query, event) } } - public func didEncounter(error: ErrorType, forQuery query: PFQuery, inClient client: Client) { + open func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) { errorHandlers.forEach { $0(query, error) } } - public func didSubscribe(toQuery query: PFQuery, inClient client: Client) { + open func didSubscribe(toQuery query: PFQuery, inClient client: Client) { subscribeHandlers.forEach { $0(query) } } - public func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) { + open func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) { unsubscribeHandlers.forEach { $0(query) } } } @@ -208,9 +208,9 @@ extension Subscription { - returns: The same subscription, for easy chaining */ - public func handle( - errorType: E.Type = E.self, - _ handler: (PFQuery, E) -> Void + public func handle( + _ errorType: E.Type = E.self, + _ handler: @escaping (PFQuery, E) -> Void ) -> Subscription { errorHandlers.append { query, error in if let error = error as? E { @@ -235,14 +235,14 @@ extension Subscription { - returns: The same subscription, for easy chaining */ - public func handle(eventType: T -> Event, _ handler: (PFQuery, T) -> Void) -> Subscription { + public func handle(_ eventType: @escaping (T) -> Event, _ handler: @escaping (PFQuery, T) -> Void) -> Subscription { return handleEvent { query, event in switch event { - case .Entered(let obj) where eventType(obj) == event: handler(query, obj) - case .Left(let obj) where eventType(obj) == event: handler(query, obj) - case .Created(let obj) where eventType(obj) == event: handler(query, obj) - case .Updated(let obj) where eventType(obj) == event: handler(query, obj) - case .Deleted(let obj) where eventType(obj) == event: handler(query, obj) + 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 } } From 05cfbeee7155e93bb8e913458a39fdda85117272 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Thu, 22 Sep 2016 01:46:41 -0400 Subject: [PATCH 2/6] nits --- Sources/ParseLiveQuery/Client.swift | 12 ++++++------ Sources/ParseLiveQuery/Internal/ClientPrivate.swift | 2 +- Sources/ParseLiveQuery/Subscription.swift | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Sources/ParseLiveQuery/Client.swift b/Sources/ParseLiveQuery/Client.swift index 42d09ce1..418d2c24 100644 --- a/Sources/ParseLiveQuery/Client.swift +++ b/Sources/ParseLiveQuery/Client.swift @@ -128,8 +128,7 @@ extension Client { _ query: PFQuery, subclassType: T.Type = T.self ) -> Subscription where T: PFObject { - return Subscription() - //return subscribe(query, handler: Subscription()) + return subscribe(query, handler: Subscription()) } /** @@ -140,10 +139,10 @@ extension Client { - returns: Your subscription handler, for easy chaining. */ - public func subscribe( + public func subscribe( _ query: PFQuery, handler: U - ) -> U where T: PFObject, U: SubscriptionHandling, U.PFGenericObject == T { + ) -> U where T: PFObject, U: SubscriptionHandling, U.PFObjectSubclass == T { let subscriptionRecord = SubscriptionRecord( query: query, requestId: requestIdGenerator(), @@ -169,7 +168,8 @@ extension Client { - parameter query: The query to unsubscribe from. */ - public func unsubscribe(_ query: PFQuery) where T: PFObject { + @objc(unsubscribeFromQuery:) + public func unsubscribe(_ query: PFQuery) { unsubscribe { $0.query == query } } @@ -179,7 +179,7 @@ extension Client { - parameter query: The query to unsubscribe from. - parameter handler: The specific handler to unsubscribe from. */ - public func unsubscribe(_ query: PFQuery, handler: T) where T: SubscriptionHandling, U: PFObject { + public func unsubscribe(_ query: PFQuery, handler: U) where T: PFObject, U: SubscriptionHandling, U.PFObjectSubclass == T { unsubscribe { $0.query == query && $0.subscriptionHandler === handler } } diff --git a/Sources/ParseLiveQuery/Internal/ClientPrivate.swift b/Sources/ParseLiveQuery/Internal/ClientPrivate.swift index 92935918..2b442e2f 100644 --- a/Sources/ParseLiveQuery/Internal/ClientPrivate.swift +++ b/Sources/ParseLiveQuery/Internal/ClientPrivate.swift @@ -58,7 +58,7 @@ extension Client { let query: PFQuery let requestId: RequestId - init(query: PFQuery, requestId: RequestId, handler: T) where T:SubscriptionHandling { + init(query: PFQuery, requestId: RequestId, handler: T) where T:SubscriptionHandling { self.query = query as! PFQuery self.requestId = requestId diff --git a/Sources/ParseLiveQuery/Subscription.swift b/Sources/ParseLiveQuery/Subscription.swift index 451da315..96141467 100644 --- a/Sources/ParseLiveQuery/Subscription.swift +++ b/Sources/ParseLiveQuery/Subscription.swift @@ -18,7 +18,7 @@ import BoltsSwift */ public protocol SubscriptionHandling: AnyObject { /// The type of the PFObject subclass that this handler uses. - associatedtype PFGenericObject: PFObject + associatedtype PFObjectSubclass: PFObject /** Tells the handler that an event has been received from the live query server. @@ -27,7 +27,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that the event occurred on. - parameter client: The live query client which received this event. */ - func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) + func didReceive(_ event: Event, forQuery query: PFQuery, inClient client: Client) /** Tells the handler that an error has been received from the live query server. @@ -36,7 +36,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that the error occurred on. - parameter client: The live query client which received this error. */ - func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) + func didEncounter(_ error: Error, forQuery query: PFQuery, inClient client: Client) /** Tells the handler that a query has been successfully registered with the server. @@ -46,7 +46,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that has been subscribed. - parameter client: The live query client which subscribed this query. */ - func didSubscribe(toQuery query: PFQuery, inClient client: Client) + func didSubscribe(toQuery query: PFQuery, inClient client: Client) /** Tells the handler that a query has been successfully deregistered from the server. @@ -56,7 +56,7 @@ public protocol SubscriptionHandling: AnyObject { - parameter query: The query that has been unsubscribed. - parameter client: The live query client which unsubscribed this query. */ - func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) + func didUnsubscribe(fromQuery query: PFQuery, inClient client: Client) } /** From 422d3f716162c025edba43be575918f685bb7372 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Wed, 21 Sep 2016 23:01:33 -0400 Subject: [PATCH 3/6] Run on xcode8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8f89d5ee..1f6bf44e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ branches: - master language: objective-c os: osx -osx_image: xcode7.3 +osx_image: xcode8 cache: - cocoapods env: From 364134be96bad073f9788832e300b149577fd28f Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Thu, 22 Sep 2016 00:48:37 -0400 Subject: [PATCH 4/6] Improves carthage settings --- Cartfile | 6 +- Cartfile.resolved | 2 +- Carthage/Checkouts/SocketRocket | 2 +- .../project.pbxproj | 50 +++++++++++++++ .../LiveQueryDemo.xcodeproj/project.pbxproj | 48 ++++++++++++++ Gemfile | 3 +- Gemfile.lock | 45 +++++++------ ParseLiveQuery.podspec | 6 +- Podfile | 2 +- Podfile.lock | 4 +- .../ParseLiveQuery.xcodeproj/project.pbxproj | 64 +++++++++++++++++++ 11 files changed, 199 insertions(+), 33 deletions(-) diff --git a/Cartfile b/Cartfile index d1bc0598..3c369a21 100644 --- a/Cartfile +++ b/Cartfile @@ -1,4 +1,4 @@ -github "BoltsFramework/Bolts-Swift" -github "facebook/SocketRocket" "0.4.2" -github "ParsePlatform/Parse-SDK-iOS-OSX" +github "BoltsFramework/Bolts-Swift" == 1.3.0 +github "facebook/SocketRocket" "master" +github "ParsePlatform/Parse-SDK-iOS-OSX" == 1.14.2 diff --git a/Cartfile.resolved b/Cartfile.resolved index c7ea29a4..593e0aca 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,4 +1,4 @@ github "BoltsFramework/Bolts-ObjC" "1.8.4" github "BoltsFramework/Bolts-Swift" "1.3.0" -github "facebook/SocketRocket" "0.4.2" +github "facebook/SocketRocket" "41b57bb2fc292a814f758441a05243eb38457027" github "ParsePlatform/Parse-SDK-iOS-OSX" "1.14.2" diff --git a/Carthage/Checkouts/SocketRocket b/Carthage/Checkouts/SocketRocket index 954c9478..41b57bb2 160000 --- a/Carthage/Checkouts/SocketRocket +++ b/Carthage/Checkouts/SocketRocket @@ -1 +1 @@ -Subproject commit 954c9478b5710903a485c68fe046e65293e2c900 +Subproject commit 41b57bb2fc292a814f758441a05243eb38457027 diff --git a/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj b/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj index 9a1ecc23..5b76e859 100644 --- a/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj +++ b/Examples/LiveQueryDemo-ObjC.xcodeproj/project.pbxproj @@ -135,12 +135,15 @@ isa = PBXNativeTarget; buildConfigurationList = F509D5431CA9E597007B15B0 /* Build configuration list for PBXNativeTarget "LiveQueryDemo-ObjC" */; buildPhases = ( + 208FAA4977FAE6125655600F /* [CP] Check Pods Manifest.lock */, 87DA45B46CF98727F2E13351 /* [CP] Check Pods Manifest.lock */, F509D52E1CA9E597007B15B0 /* Sources */, F509D52F1CA9E597007B15B0 /* Frameworks */, F509D5301CA9E597007B15B0 /* Resources */, EA41B3F790AE39BE08641EBB /* [CP] Embed Pods Frameworks */, A8851B9B8AD727FB055366F2 /* [CP] Copy Pods Resources */, + AEF3C7E9E62737C95CCEDF15 /* 📦 Embed Pods Frameworks */, + 6527F5DEB5EFD1866B2614D7 /* 📦 Copy Pods Resources */, ); buildRules = ( ); @@ -218,6 +221,36 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 208FAA4977FAE6125655600F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 6527F5DEB5EFD1866B2614D7 /* 📦 Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-LiveQueryDemo-ObjC/Pods-LiveQueryDemo-ObjC-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 87DA45B46CF98727F2E13351 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -248,6 +281,21 @@ shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-LiveQueryDemo-ObjC/Pods-LiveQueryDemo-ObjC-resources.sh\"\n"; showEnvVarsInLog = 0; }; + AEF3C7E9E62737C95CCEDF15 /* 📦 Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-LiveQueryDemo-ObjC/Pods-LiveQueryDemo-ObjC-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; EA41B3F790AE39BE08641EBB /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -298,6 +346,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.parse.LiveQueryDemo; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -311,6 +360,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.parse.LiveQueryDemo; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Examples/LiveQueryDemo.xcodeproj/project.pbxproj b/Examples/LiveQueryDemo.xcodeproj/project.pbxproj index faed07f9..8972e023 100644 --- a/Examples/LiveQueryDemo.xcodeproj/project.pbxproj +++ b/Examples/LiveQueryDemo.xcodeproj/project.pbxproj @@ -123,12 +123,15 @@ isa = PBXNativeTarget; buildConfigurationList = F509D5251CA9E4AE007B15B0 /* Build configuration list for PBXNativeTarget "LiveQueryDemo" */; buildPhases = ( + 9D539417025C30ADB0E1A1F6 /* [CP] Check Pods Manifest.lock */, E6F699DDDA9E6B861F705AD5 /* [CP] Check Pods Manifest.lock */, F509D5131CA9E4AE007B15B0 /* Sources */, F509D5141CA9E4AE007B15B0 /* Frameworks */, F509D5151CA9E4AE007B15B0 /* Resources */, 045C33FD1807E3932888A2F9 /* [CP] Embed Pods Frameworks */, D9EF05A29B9F1AAC9B62408C /* [CP] Copy Pods Resources */, + EAD62EF23FE70C6E3984EDE6 /* 📦 Embed Pods Frameworks */, + E3F143CFD9CCD46782420827 /* 📦 Copy Pods Resources */, ); buildRules = ( ); @@ -222,6 +225,21 @@ shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-LiveQueryDemo/Pods-LiveQueryDemo-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + 9D539417025C30ADB0E1A1F6 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; D9EF05A29B9F1AAC9B62408C /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -237,6 +255,21 @@ shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-LiveQueryDemo/Pods-LiveQueryDemo-resources.sh\"\n"; showEnvVarsInLog = 0; }; + E3F143CFD9CCD46782420827 /* 📦 Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-LiveQueryDemo/Pods-LiveQueryDemo-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; E6F699DDDA9E6B861F705AD5 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -252,6 +285,21 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; + EAD62EF23FE70C6E3984EDE6 /* 📦 Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-LiveQueryDemo/Pods-LiveQueryDemo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/Gemfile b/Gemfile index 4618115d..9be29567 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,5 @@ source 'https://rubygems.org' gem 'xcpretty' -gem 'cocoapods' +# xcode8 compat +gem 'cocoapods', '1.1.0.rc.2' diff --git a/Gemfile.lock b/Gemfile.lock index e57b1914..eb587398 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,35 +1,37 @@ GEM remote: https://rubygems.org/ specs: - activesupport (5.0.0) - concurrent-ruby (~> 1.0, >= 1.0.2) + activesupport (4.2.7.1) i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) claide (1.0.0) - cocoapods (1.0.1) - activesupport (>= 4.0.2) + cocoapods (1.1.0.rc.2) + activesupport (>= 4.0.2, < 5) claide (>= 1.0.0, < 2.0) - cocoapods-core (= 1.0.1) - cocoapods-deintegrate (>= 1.0.0, < 2.0) - cocoapods-downloader (>= 1.0.0, < 2.0) + cocoapods-core (= 1.1.0.rc.2) + cocoapods-deintegrate (>= 1.0.1, < 2.0) + cocoapods-downloader (>= 1.1.1, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) cocoapods-stats (>= 1.0.0, < 2.0) cocoapods-trunk (>= 1.0.0, < 2.0) - cocoapods-try (>= 1.0.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) colored (~> 1.2) escape (~> 0.0.4) - fourflusher (~> 0.3.0) - molinillo (~> 0.4.5) + fourflusher (~> 1.0.1) + gh_inspector (~> 1.0) + molinillo (~> 0.5.1) nap (~> 1.0) - xcodeproj (>= 1.1.0, < 2.0) - cocoapods-core (1.0.1) - activesupport (>= 4.0.2) + xcodeproj (>= 1.3.1, < 2.0) + cocoapods-core (1.1.0.rc.2) + activesupport (>= 4.0.2, < 5) fuzzy_match (~> 2.0.4) nap (~> 1.0) - cocoapods-deintegrate (1.0.0) - cocoapods-downloader (1.1.0) + cocoapods-deintegrate (1.0.1) + cocoapods-downloader (1.1.1) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.0) @@ -39,20 +41,21 @@ GEM netrc (= 0.7.8) cocoapods-try (1.1.0) colored (1.2) - concurrent-ruby (1.0.2) escape (0.0.4) - fourflusher (0.3.2) + fourflusher (1.0.1) fuzzy_match (2.0.4) + gh_inspector (1.0.2) i18n (0.7.0) + json (1.8.3) minitest (5.9.0) - molinillo (0.4.5) + molinillo (0.5.1) nap (1.1.0) netrc (0.7.8) rouge (1.11.1) thread_safe (0.3.5) tzinfo (1.2.2) thread_safe (~> 0.1) - xcodeproj (1.2.0) + xcodeproj (1.3.1) activesupport (>= 3) claide (>= 1.0.0, < 2.0) colored (~> 1.2) @@ -63,8 +66,8 @@ PLATFORMS ruby DEPENDENCIES - cocoapods + cocoapods (= 1.1.0.rc.2) xcpretty BUNDLED WITH - 1.12.5 + 1.13.1 diff --git a/ParseLiveQuery.podspec b/ParseLiveQuery.podspec index 683225d3..afd30915 100644 --- a/ParseLiveQuery.podspec +++ b/ParseLiveQuery.podspec @@ -11,12 +11,12 @@ Pod::Spec.new do |s| s.requires_arc = true s.ios.deployment_target = '8.0' - s.osx.deployment_target = '10.9' + s.osx.deployment_target = '10.10' s.source_files = 'Sources/ParseLiveQuery/**/*.swift' s.module_name = 'ParseLiveQuery' - s.dependency 'Parse', '~> 1.14' - s.dependency 'Bolts-Swift', '~> 1.2' + s.dependency 'Parse', '~> 1.14.2' + s.dependency 'Bolts-Swift', '~> 1.3' s.dependency 'SocketRocket', '~> 0.5' end diff --git a/Podfile b/Podfile index 62692f7e..ace66cd6 100644 --- a/Podfile +++ b/Podfile @@ -8,7 +8,7 @@ def commonPods end post_install do |installer| - # Disable bitcode for now. Specifically needed for HockeySDK and ARAnalytics. + # Force Swift version for Xcode 8 installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '3.0' diff --git a/Podfile.lock b/Podfile.lock index 5b4ac929..665f4ccb 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -26,6 +26,6 @@ SPEC CHECKSUMS: Parse: 4335d65f40cb3d43190d723144bbe1afb9c38230 SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531 -PODFILE CHECKSUM: 6e85eacd328c6d22732f2290677ff90162634615 +PODFILE CHECKSUM: ccd9b68a1b8b06aee68db55ab458175ae7383cef -COCOAPODS: 1.0.1 +COCOAPODS: 1.1.0.rc.2 diff --git a/Sources/ParseLiveQuery.xcodeproj/project.pbxproj b/Sources/ParseLiveQuery.xcodeproj/project.pbxproj index ac2412a1..1c3bd90b 100644 --- a/Sources/ParseLiveQuery.xcodeproj/project.pbxproj +++ b/Sources/ParseLiveQuery.xcodeproj/project.pbxproj @@ -180,12 +180,14 @@ isa = PBXNativeTarget; buildConfigurationList = F5903CEF1BD999C500C3EFFE /* Build configuration list for PBXNativeTarget "ParseLiveQuery-OSX" */; buildPhases = ( + 42957978F8F9CAAE6BE3FE9C /* [CP] Check Pods Manifest.lock */, 432EB76C64066D923373DC45 /* [CP] Check Pods Manifest.lock */, F5903CE51BD999C500C3EFFE /* Sources */, F5903CE61BD999C500C3EFFE /* Frameworks */, F5903CE71BD999C500C3EFFE /* Headers */, F5903CE81BD999C500C3EFFE /* Resources */, 458C6F69E79D3F67465FC4DB /* [CP] Copy Pods Resources */, + 8D6D42D741753A8DA3FEBB44 /* 📦 Copy Pods Resources */, ); buildRules = ( ); @@ -200,12 +202,14 @@ isa = PBXNativeTarget; buildConfigurationList = F5A9BFC71BE0248D00E78326 /* Build configuration list for PBXNativeTarget "ParseLiveQuery-iOS" */; buildPhases = ( + 12BD489D413AD268FF85A8FA /* [CP] Check Pods Manifest.lock */, 0779A1A9A8C094A6EC98CD51 /* [CP] Check Pods Manifest.lock */, F5A9BFBA1BE0248D00E78326 /* Sources */, F5A9BFC01BE0248D00E78326 /* Frameworks */, F5A9BFC31BE0248D00E78326 /* Headers */, F5A9BFC51BE0248D00E78326 /* Resources */, 89E3C0C052352147C9B80227 /* [CP] Copy Pods Resources */, + 23E82A71A220B624E9EEDD3B /* 📦 Copy Pods Resources */, ); buildRules = ( ); @@ -286,6 +290,51 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; + 12BD489D413AD268FF85A8FA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 23E82A71A220B624E9EEDD3B /* 📦 Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-ParseLiveQuery-iOS/Pods-ParseLiveQuery-iOS-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 42957978F8F9CAAE6BE3FE9C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; 432EB76C64066D923373DC45 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -331,6 +380,21 @@ shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-ParseLiveQuery-iOS/Pods-ParseLiveQuery-iOS-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 8D6D42D741753A8DA3FEBB44 /* 📦 Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-ParseLiveQuery-OSX/Pods-ParseLiveQuery-OSX-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ From ce3b2ff5cb7080eeb7b6cf16e88ada0e503ba6e4 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Thu, 22 Sep 2016 01:19:21 -0400 Subject: [PATCH 5/6] Adds .swift-version to force pods to use 3.0 --- .swift-version | 1 + .travis.yml | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 00000000..9f55b2cc --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +3.0 diff --git a/.travis.yml b/.travis.yml index 1f6bf44e..94cb33d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,9 +36,10 @@ script: xcodebuild clean -workspace ParseLiveQuery.xcworkspace -scheme LiveQueryDemo-ObjC | xcpretty -c xcodebuild build -workspace ParseLiveQuery.xcworkspace -scheme LiveQueryDemo-ObjC -configuration Debug | xcpretty -c elif [ "$TEST_TYPE" = CocoaPods ]; then - pod lib lint ParseLiveQuery.podspec + # SocketRocket produces warnings on xcode8 + pod lib lint ParseLiveQuery.podspec --allow-warnings elif [ "$TEST_TYPE" = Carthage ]; then - carthage build --no-skip-current --platform iOS + carthage build --no-skip-current fi after_success: - | From 58d30b8a3363f9e7b4a6e2353d4ca53efc2f9fb7 Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Thu, 22 Sep 2016 01:54:42 -0400 Subject: [PATCH 6/6] more nits --- Sources/ParseLiveQuery/Client.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/ParseLiveQuery/Client.swift b/Sources/ParseLiveQuery/Client.swift index 418d2c24..6cff996b 100644 --- a/Sources/ParseLiveQuery/Client.swift +++ b/Sources/ParseLiveQuery/Client.swift @@ -139,10 +139,10 @@ extension Client { - returns: Your subscription handler, for easy chaining. */ - public func subscribe( - _ query: PFQuery, - handler: U - ) -> U where T: PFObject, U: SubscriptionHandling, U.PFObjectSubclass == T { + public func subscribe( + _ query: PFQuery, + handler: T + ) -> T where T: SubscriptionHandling { let subscriptionRecord = SubscriptionRecord( query: query, requestId: requestIdGenerator(), @@ -179,7 +179,7 @@ extension Client { - parameter query: The query to unsubscribe from. - parameter handler: The specific handler to unsubscribe from. */ - public func unsubscribe(_ query: PFQuery, handler: U) where T: PFObject, U: SubscriptionHandling, U.PFObjectSubclass == T { + public func unsubscribe(_ query: PFQuery, handler: T) where T: SubscriptionHandling { unsubscribe { $0.query == query && $0.subscriptionHandler === handler } }