├── .gitignore ├── .travis.yml ├── LICENSE ├── Pool.podspec ├── Pool.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ ├── Pool.xcscheme │ │ └── PoolTests.xcscheme └── xcuserdata │ └── damien.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── README.md ├── Source ├── Message.swift ├── Pool.swift ├── Session.swift ├── SessionDelegate.swift └── Supporting Files │ ├── Info.plist │ ├── Pool.h │ └── Utilities.swift └── Tests ├── MessageTests.swift ├── PoolTests.swift ├── SessionDelegateTests.swift ├── SessionTests.swift └── Supporting Files └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, 4 | # Objective-C.gitignore & Swift.gitignore 5 | 6 | ## Build generated 7 | build/ 8 | DerivedData 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata 20 | 21 | ## Other 22 | *.xccheckout 23 | *.moved-aside 24 | *.xcuserstate 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | 31 | # Carthage 32 | Carthage/Build 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | xcode_project: Pool.xcodeproj 8 | xcode_scheme: PoolTests 9 | osx_image: xcode7.3 10 | xcode_sdk: iphonesimulator9.3 11 | 12 | script: 13 | - xcodebuild test -project Pool.xcodeproj -scheme PoolTests -destination "platform=iOS Simulator,name=iPhone 6s" 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Damien (http://delba.io) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /Pool.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Pool" 3 | s.version = "0.2" 4 | s.license = { :type => "MIT" } 5 | s.homepage = "https://github.com/delba/Pool" 6 | s.author = { "Damien" => "damien@delba.io" } 7 | s.summary = "Seamless data sharing across nearby devices" 8 | s.source = { :git => "https://github.com/delba/Pool.git", :tag => "v0.2" } 9 | 10 | s.ios.deployment_target = "8.0" 11 | 12 | s.source_files = "Source/**/*.{swift, h}" 13 | 14 | s.requires_arc = true 15 | end 16 | -------------------------------------------------------------------------------- /Pool.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6D468C291D4CB85400833E68 /* Pool.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D468C281D4CB85400833E68 /* Pool.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 6D468C301D4CB85400833E68 /* Pool.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D468C251D4CB85400833E68 /* Pool.framework */; }; 12 | 6D468C351D4CB85400833E68 /* PoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D468C341D4CB85400833E68 /* PoolTests.swift */; }; 13 | 6D971FCC1D5BA0AE00D2EEE3 /* MessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D971FCB1D5BA0AE00D2EEE3 /* MessageTests.swift */; }; 14 | 6DDDBEB31D60A523003673EB /* Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDDBEB21D60A523003673EB /* Session.swift */; }; 15 | 6DDDBEB51D60A818003673EB /* SessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDDBEB41D60A818003673EB /* SessionDelegate.swift */; }; 16 | 6DDDBEB71D60C857003673EB /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDDBEB61D60C857003673EB /* Utilities.swift */; }; 17 | 6DDDBEB91D60E1E8003673EB /* SessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDDBEB81D60E1E8003673EB /* SessionTests.swift */; }; 18 | 6DDDBEBB1D60E1FA003673EB /* SessionDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DDDBEBA1D60E1FA003673EB /* SessionDelegateTests.swift */; }; 19 | 6DF0DE2C1D527A8E00082188 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DF0DE2B1D527A8E00082188 /* Message.swift */; }; 20 | 6DF0DE2E1D527DDF00082188 /* Pool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DF0DE2D1D527DDF00082188 /* Pool.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 6D468C311D4CB85400833E68 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 6D468C1C1D4CB85400833E68 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 6D468C241D4CB85400833E68; 29 | remoteInfo = Pool; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 6D468C251D4CB85400833E68 /* Pool.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pool.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 6D468C281D4CB85400833E68 /* Pool.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pool.h; sourceTree = ""; }; 36 | 6D468C2A1D4CB85400833E68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 6D468C2F1D4CB85400833E68 /* PoolTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PoolTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 6D468C341D4CB85400833E68 /* PoolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PoolTests.swift; sourceTree = ""; }; 39 | 6D468C361D4CB85400833E68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 6D971FCB1D5BA0AE00D2EEE3 /* MessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTests.swift; sourceTree = ""; }; 41 | 6DDDBEB21D60A523003673EB /* Session.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Session.swift; sourceTree = ""; }; 42 | 6DDDBEB41D60A818003673EB /* SessionDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionDelegate.swift; sourceTree = ""; }; 43 | 6DDDBEB61D60C857003673EB /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; 44 | 6DDDBEB81D60E1E8003673EB /* SessionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionTests.swift; sourceTree = ""; }; 45 | 6DDDBEBA1D60E1FA003673EB /* SessionDelegateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionDelegateTests.swift; sourceTree = ""; }; 46 | 6DF0DE2B1D527A8E00082188 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; 47 | 6DF0DE2D1D527DDF00082188 /* Pool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pool.swift; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 6D468C211D4CB85400833E68 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | 6D468C2C1D4CB85400833E68 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | 6D468C301D4CB85400833E68 /* Pool.framework in Frameworks */, 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | 6D468C1B1D4CB85400833E68 = { 70 | isa = PBXGroup; 71 | children = ( 72 | 6D468C261D4CB85400833E68 /* Products */, 73 | 6D468C271D4CB85400833E68 /* Source */, 74 | 6D468C331D4CB85400833E68 /* Tests */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 6D468C261D4CB85400833E68 /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 6D468C251D4CB85400833E68 /* Pool.framework */, 82 | 6D468C2F1D4CB85400833E68 /* PoolTests.xctest */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | 6D468C271D4CB85400833E68 /* Source */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 6DF0DE331D53B37600082188 /* Supporting Files */, 91 | 6DF0DE2B1D527A8E00082188 /* Message.swift */, 92 | 6DF0DE2D1D527DDF00082188 /* Pool.swift */, 93 | 6DDDBEB21D60A523003673EB /* Session.swift */, 94 | 6DDDBEB41D60A818003673EB /* SessionDelegate.swift */, 95 | ); 96 | path = Source; 97 | sourceTree = ""; 98 | }; 99 | 6D468C331D4CB85400833E68 /* Tests */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 6DF0DE341D53B3EC00082188 /* Supporting Files */, 103 | 6D971FCB1D5BA0AE00D2EEE3 /* MessageTests.swift */, 104 | 6D468C341D4CB85400833E68 /* PoolTests.swift */, 105 | 6DDDBEBA1D60E1FA003673EB /* SessionDelegateTests.swift */, 106 | 6DDDBEB81D60E1E8003673EB /* SessionTests.swift */, 107 | ); 108 | path = Tests; 109 | sourceTree = ""; 110 | }; 111 | 6DF0DE331D53B37600082188 /* Supporting Files */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 6D468C2A1D4CB85400833E68 /* Info.plist */, 115 | 6D468C281D4CB85400833E68 /* Pool.h */, 116 | 6DDDBEB61D60C857003673EB /* Utilities.swift */, 117 | ); 118 | path = "Supporting Files"; 119 | sourceTree = ""; 120 | }; 121 | 6DF0DE341D53B3EC00082188 /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 6D468C361D4CB85400833E68 /* Info.plist */, 125 | ); 126 | path = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXHeadersBuildPhase section */ 132 | 6D468C221D4CB85400833E68 /* Headers */ = { 133 | isa = PBXHeadersBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | 6D468C291D4CB85400833E68 /* Pool.h in Headers */, 137 | ); 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | /* End PBXHeadersBuildPhase section */ 141 | 142 | /* Begin PBXNativeTarget section */ 143 | 6D468C241D4CB85400833E68 /* Pool */ = { 144 | isa = PBXNativeTarget; 145 | buildConfigurationList = 6D468C391D4CB85400833E68 /* Build configuration list for PBXNativeTarget "Pool" */; 146 | buildPhases = ( 147 | 6D468C201D4CB85400833E68 /* Sources */, 148 | 6D468C211D4CB85400833E68 /* Frameworks */, 149 | 6D468C221D4CB85400833E68 /* Headers */, 150 | 6D468C231D4CB85400833E68 /* Resources */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = Pool; 157 | productName = Pool; 158 | productReference = 6D468C251D4CB85400833E68 /* Pool.framework */; 159 | productType = "com.apple.product-type.framework"; 160 | }; 161 | 6D468C2E1D4CB85400833E68 /* PoolTests */ = { 162 | isa = PBXNativeTarget; 163 | buildConfigurationList = 6D468C3C1D4CB85400833E68 /* Build configuration list for PBXNativeTarget "PoolTests" */; 164 | buildPhases = ( 165 | 6D468C2B1D4CB85400833E68 /* Sources */, 166 | 6D468C2C1D4CB85400833E68 /* Frameworks */, 167 | 6D468C2D1D4CB85400833E68 /* Resources */, 168 | ); 169 | buildRules = ( 170 | ); 171 | dependencies = ( 172 | 6D468C321D4CB85400833E68 /* PBXTargetDependency */, 173 | ); 174 | name = PoolTests; 175 | productName = PoolTests; 176 | productReference = 6D468C2F1D4CB85400833E68 /* PoolTests.xctest */; 177 | productType = "com.apple.product-type.bundle.unit-test"; 178 | }; 179 | /* End PBXNativeTarget section */ 180 | 181 | /* Begin PBXProject section */ 182 | 6D468C1C1D4CB85400833E68 /* Project object */ = { 183 | isa = PBXProject; 184 | attributes = { 185 | LastSwiftUpdateCheck = 0730; 186 | LastUpgradeCheck = 0730; 187 | ORGANIZATIONNAME = delba; 188 | TargetAttributes = { 189 | 6D468C241D4CB85400833E68 = { 190 | CreatedOnToolsVersion = 7.3.1; 191 | }; 192 | 6D468C2E1D4CB85400833E68 = { 193 | CreatedOnToolsVersion = 7.3.1; 194 | }; 195 | }; 196 | }; 197 | buildConfigurationList = 6D468C1F1D4CB85400833E68 /* Build configuration list for PBXProject "Pool" */; 198 | compatibilityVersion = "Xcode 3.2"; 199 | developmentRegion = English; 200 | hasScannedForEncodings = 0; 201 | knownRegions = ( 202 | en, 203 | ); 204 | mainGroup = 6D468C1B1D4CB85400833E68; 205 | productRefGroup = 6D468C261D4CB85400833E68 /* Products */; 206 | projectDirPath = ""; 207 | projectRoot = ""; 208 | targets = ( 209 | 6D468C241D4CB85400833E68 /* Pool */, 210 | 6D468C2E1D4CB85400833E68 /* PoolTests */, 211 | ); 212 | }; 213 | /* End PBXProject section */ 214 | 215 | /* Begin PBXResourcesBuildPhase section */ 216 | 6D468C231D4CB85400833E68 /* Resources */ = { 217 | isa = PBXResourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | 6D468C2D1D4CB85400833E68 /* Resources */ = { 224 | isa = PBXResourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | /* End PBXResourcesBuildPhase section */ 231 | 232 | /* Begin PBXSourcesBuildPhase section */ 233 | 6D468C201D4CB85400833E68 /* Sources */ = { 234 | isa = PBXSourcesBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | 6DF0DE2C1D527A8E00082188 /* Message.swift in Sources */, 238 | 6DF0DE2E1D527DDF00082188 /* Pool.swift in Sources */, 239 | 6DDDBEB31D60A523003673EB /* Session.swift in Sources */, 240 | 6DDDBEB71D60C857003673EB /* Utilities.swift in Sources */, 241 | 6DDDBEB51D60A818003673EB /* SessionDelegate.swift in Sources */, 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | }; 245 | 6D468C2B1D4CB85400833E68 /* Sources */ = { 246 | isa = PBXSourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | 6DDDBEB91D60E1E8003673EB /* SessionTests.swift in Sources */, 250 | 6D468C351D4CB85400833E68 /* PoolTests.swift in Sources */, 251 | 6D971FCC1D5BA0AE00D2EEE3 /* MessageTests.swift in Sources */, 252 | 6DDDBEBB1D60E1FA003673EB /* SessionDelegateTests.swift in Sources */, 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | /* End PBXSourcesBuildPhase section */ 257 | 258 | /* Begin PBXTargetDependency section */ 259 | 6D468C321D4CB85400833E68 /* PBXTargetDependency */ = { 260 | isa = PBXTargetDependency; 261 | target = 6D468C241D4CB85400833E68 /* Pool */; 262 | targetProxy = 6D468C311D4CB85400833E68 /* PBXContainerItemProxy */; 263 | }; 264 | /* End PBXTargetDependency section */ 265 | 266 | /* Begin XCBuildConfiguration section */ 267 | 6D468C371D4CB85400833E68 /* Debug */ = { 268 | isa = XCBuildConfiguration; 269 | buildSettings = { 270 | ALWAYS_SEARCH_USER_PATHS = NO; 271 | CLANG_ANALYZER_NONNULL = YES; 272 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 273 | CLANG_CXX_LIBRARY = "libc++"; 274 | CLANG_ENABLE_MODULES = YES; 275 | CLANG_ENABLE_OBJC_ARC = YES; 276 | CLANG_WARN_BOOL_CONVERSION = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 283 | CLANG_WARN_UNREACHABLE_CODE = YES; 284 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 285 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 286 | COPY_PHASE_STRIP = NO; 287 | CURRENT_PROJECT_VERSION = 1; 288 | DEBUG_INFORMATION_FORMAT = dwarf; 289 | ENABLE_STRICT_OBJC_MSGSEND = YES; 290 | ENABLE_TESTABILITY = YES; 291 | GCC_C_LANGUAGE_STANDARD = gnu99; 292 | GCC_DYNAMIC_NO_PIC = NO; 293 | GCC_NO_COMMON_BLOCKS = YES; 294 | GCC_OPTIMIZATION_LEVEL = 0; 295 | GCC_PREPROCESSOR_DEFINITIONS = ( 296 | "DEBUG=1", 297 | "$(inherited)", 298 | ); 299 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 300 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 301 | GCC_WARN_UNDECLARED_SELECTOR = YES; 302 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 303 | GCC_WARN_UNUSED_FUNCTION = YES; 304 | GCC_WARN_UNUSED_VARIABLE = YES; 305 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 306 | MTL_ENABLE_DEBUG_INFO = YES; 307 | ONLY_ACTIVE_ARCH = YES; 308 | SDKROOT = iphoneos; 309 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 310 | TARGETED_DEVICE_FAMILY = "1,2"; 311 | VERSIONING_SYSTEM = "apple-generic"; 312 | VERSION_INFO_PREFIX = ""; 313 | }; 314 | name = Debug; 315 | }; 316 | 6D468C381D4CB85400833E68 /* Release */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ALWAYS_SEARCH_USER_PATHS = NO; 320 | CLANG_ANALYZER_NONNULL = YES; 321 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 322 | CLANG_CXX_LIBRARY = "libc++"; 323 | CLANG_ENABLE_MODULES = YES; 324 | CLANG_ENABLE_OBJC_ARC = YES; 325 | CLANG_WARN_BOOL_CONVERSION = YES; 326 | CLANG_WARN_CONSTANT_CONVERSION = YES; 327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 328 | CLANG_WARN_EMPTY_BODY = YES; 329 | CLANG_WARN_ENUM_CONVERSION = YES; 330 | CLANG_WARN_INT_CONVERSION = YES; 331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 332 | CLANG_WARN_UNREACHABLE_CODE = YES; 333 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 334 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 335 | COPY_PHASE_STRIP = NO; 336 | CURRENT_PROJECT_VERSION = 1; 337 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 338 | ENABLE_NS_ASSERTIONS = NO; 339 | ENABLE_STRICT_OBJC_MSGSEND = YES; 340 | GCC_C_LANGUAGE_STANDARD = gnu99; 341 | GCC_NO_COMMON_BLOCKS = YES; 342 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 343 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 344 | GCC_WARN_UNDECLARED_SELECTOR = YES; 345 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 346 | GCC_WARN_UNUSED_FUNCTION = YES; 347 | GCC_WARN_UNUSED_VARIABLE = YES; 348 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 349 | MTL_ENABLE_DEBUG_INFO = NO; 350 | SDKROOT = iphoneos; 351 | TARGETED_DEVICE_FAMILY = "1,2"; 352 | VALIDATE_PRODUCT = YES; 353 | VERSIONING_SYSTEM = "apple-generic"; 354 | VERSION_INFO_PREFIX = ""; 355 | }; 356 | name = Release; 357 | }; 358 | 6D468C3A1D4CB85400833E68 /* Debug */ = { 359 | isa = XCBuildConfiguration; 360 | buildSettings = { 361 | CLANG_ENABLE_MODULES = YES; 362 | DEFINES_MODULE = YES; 363 | DYLIB_COMPATIBILITY_VERSION = 1; 364 | DYLIB_CURRENT_VERSION = 1; 365 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 366 | INFOPLIST_FILE = "Source/Supporting Files/Info.plist"; 367 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 368 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 369 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 370 | PRODUCT_BUNDLE_IDENTIFIER = io.delba.Pool; 371 | PRODUCT_NAME = "$(TARGET_NAME)"; 372 | SKIP_INSTALL = YES; 373 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 374 | }; 375 | name = Debug; 376 | }; 377 | 6D468C3B1D4CB85400833E68 /* Release */ = { 378 | isa = XCBuildConfiguration; 379 | buildSettings = { 380 | CLANG_ENABLE_MODULES = YES; 381 | DEFINES_MODULE = YES; 382 | DYLIB_COMPATIBILITY_VERSION = 1; 383 | DYLIB_CURRENT_VERSION = 1; 384 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 385 | INFOPLIST_FILE = "Source/Supporting Files/Info.plist"; 386 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 387 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 388 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 389 | PRODUCT_BUNDLE_IDENTIFIER = io.delba.Pool; 390 | PRODUCT_NAME = "$(TARGET_NAME)"; 391 | SKIP_INSTALL = YES; 392 | }; 393 | name = Release; 394 | }; 395 | 6D468C3D1D4CB85400833E68 /* Debug */ = { 396 | isa = XCBuildConfiguration; 397 | buildSettings = { 398 | INFOPLIST_FILE = "Tests/Supporting Files/Info.plist"; 399 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 400 | PRODUCT_BUNDLE_IDENTIFIER = io.delba.PoolTests; 401 | PRODUCT_NAME = "$(TARGET_NAME)"; 402 | }; 403 | name = Debug; 404 | }; 405 | 6D468C3E1D4CB85400833E68 /* Release */ = { 406 | isa = XCBuildConfiguration; 407 | buildSettings = { 408 | INFOPLIST_FILE = "Tests/Supporting Files/Info.plist"; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 410 | PRODUCT_BUNDLE_IDENTIFIER = io.delba.PoolTests; 411 | PRODUCT_NAME = "$(TARGET_NAME)"; 412 | }; 413 | name = Release; 414 | }; 415 | /* End XCBuildConfiguration section */ 416 | 417 | /* Begin XCConfigurationList section */ 418 | 6D468C1F1D4CB85400833E68 /* Build configuration list for PBXProject "Pool" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | 6D468C371D4CB85400833E68 /* Debug */, 422 | 6D468C381D4CB85400833E68 /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | 6D468C391D4CB85400833E68 /* Build configuration list for PBXNativeTarget "Pool" */ = { 428 | isa = XCConfigurationList; 429 | buildConfigurations = ( 430 | 6D468C3A1D4CB85400833E68 /* Debug */, 431 | 6D468C3B1D4CB85400833E68 /* Release */, 432 | ); 433 | defaultConfigurationIsVisible = 0; 434 | defaultConfigurationName = Release; 435 | }; 436 | 6D468C3C1D4CB85400833E68 /* Build configuration list for PBXNativeTarget "PoolTests" */ = { 437 | isa = XCConfigurationList; 438 | buildConfigurations = ( 439 | 6D468C3D1D4CB85400833E68 /* Debug */, 440 | 6D468C3E1D4CB85400833E68 /* Release */, 441 | ); 442 | defaultConfigurationIsVisible = 0; 443 | defaultConfigurationName = Release; 444 | }; 445 | /* End XCConfigurationList section */ 446 | }; 447 | rootObject = 6D468C1C1D4CB85400833E68 /* Project object */; 448 | } 449 | -------------------------------------------------------------------------------- /Pool.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Pool.xcodeproj/xcshareddata/xcschemes/Pool.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Pool.xcodeproj/xcshareddata/xcschemes/PoolTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Pool.xcodeproj/xcuserdata/damien.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Pool.xcodeproj/xcuserdata/damien.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Pool.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | PoolTests.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 6D468C241D4CB85400833E68 21 | 22 | primary 23 | 24 | 25 | 6D468C2E1D4CB85400833E68 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | ```swift 6 | let pool = Pool(name: "dribbble-shots") 7 | 8 | // On device A 9 | 10 | pool.setObject(image, forKey: "http://example.com/shot.png") 11 | 12 | // On device B 13 | 14 | pool.objectForKey("http://example.com/shot.png") { [weak self] image in 15 | self?.imageView.image = image as? UIImage 16 | } 17 | ``` 18 | 19 | ## Installation 20 | 21 | ### Carthage 22 | 23 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that automates the process of adding frameworks to your Cocoa application. 24 | 25 | You can install Carthage with [Homebrew](http://brew.sh/) using the following command: 26 | 27 | ```bash 28 | $ brew update 29 | $ brew install carthage 30 | ``` 31 | 32 | To integrate Pool into your Xcode project using Carthage, specify it in your `Cartfile`: 33 | 34 | ```ogdl 35 | github "delba/Pool" 36 | ``` 37 | 38 | ### CocoaPods 39 | 40 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. 41 | 42 | You can install it with the following command: 43 | 44 | ```bash 45 | $ gem install cocoapods 46 | ``` 47 | 48 | To integrate Pool into your Xcode project using CocoaPods, specify it in your `Podfile`: 49 | 50 | ```ruby 51 | use_frameworks! 52 | 53 | pod 'Pool' 54 | ``` 55 | 56 | ## License 57 | 58 | Copyright (c) 2016 Damien (http://delba.io) 59 | 60 | Permission is hereby granted, free of charge, to any person obtaining a copy 61 | of this software and associated documentation files (the "Software"), to deal 62 | in the Software without restriction, including without limitation the rights 63 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 64 | copies of the Software, and to permit persons to whom the Software is 65 | furnished to do so, subject to the following conditions: 66 | 67 | The above copyright notice and this permission notice shall be included in all 68 | copies or substantial portions of the Software. 69 | 70 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 71 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 72 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 73 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 74 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 75 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 76 | SOFTWARE. 77 | -------------------------------------------------------------------------------- /Source/Message.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Message.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | // MARK: Message 26 | 27 | internal enum Message { 28 | /// A request message for the given key. 29 | case Request(Key) 30 | 31 | /// A response message with the given key and value. 32 | case Response(Key, Value?) 33 | 34 | /// An insert message for the given keys. 35 | case Insert([Key]) 36 | 37 | /// A delete message for the given keys. 38 | case Delete([Key]) 39 | 40 | /// The message type. 41 | private var type: String { 42 | switch self { 43 | case Request: return "request" 44 | case Response: return "response" 45 | case Insert: return "insert" 46 | case Delete: return "delete" 47 | } 48 | } 49 | 50 | /// The message associated values. 51 | private var args: [AnyObject] { 52 | switch self { 53 | case let Request(key): return [key] 54 | case let Response(k, v): return [k, v].flatMap({ $0 }) 55 | case let Insert(keys): return [keys] 56 | case let Delete(keys): return [keys] 57 | } 58 | } 59 | 60 | /** 61 | Creates and return a new message or nil if not convertible. 62 | 63 | - parameter data: The `NSData` representation of the message. 64 | 65 | - returns: A new message or nil if not convertible. 66 | */ 67 | internal init?(data: NSData) { 68 | guard let dictionary = KeyArchiver.unarchive(data) as? [String: AnyObject], 69 | let type = dictionary["type"] as? String, 70 | let args = dictionary["args"] as? [AnyObject] 71 | else { return nil } 72 | 73 | switch type { 74 | case "request": self.init(request: args) 75 | case "response": self.init(response: args) 76 | case "insert": self.init(insert: args) 77 | case "delete": self.init(delete: args) 78 | default: return nil 79 | } 80 | } 81 | 82 | /** 83 | Returns an `NSData` object containing the encoded form of the message. 84 | 85 | - returns: The `NSData` representation of the message. 86 | */ 87 | internal func toData() -> NSData { 88 | return KeyArchiver.archive([ 89 | "type": type, 90 | "args": args, 91 | ]) 92 | } 93 | } 94 | 95 | // MARK: Request 96 | 97 | private extension Message { 98 | init?(request args: [AnyObject]) { 99 | guard let key = args[safe: 0] as? Key else { return nil } 100 | 101 | self = Request(key) 102 | } 103 | } 104 | 105 | // MARK: Response 106 | 107 | private extension Message { 108 | init?(response args: [AnyObject]) { 109 | guard let key = args[safe: 0] as? Key else { return nil } 110 | 111 | let value = args[safe: 1] 112 | 113 | self = Response(key, value) 114 | } 115 | } 116 | 117 | // MARK: Insert 118 | 119 | private extension Message { 120 | init?(insert args: [AnyObject]) { 121 | guard let keys = args[safe: 0] as? [Key] else { return nil } 122 | 123 | self = Insert(keys) 124 | } 125 | } 126 | 127 | // MARK: Delete 128 | 129 | private extension Message { 130 | init?(delete args: [AnyObject]) { 131 | guard let keys = args[safe: 0] as? [Key] else { return nil } 132 | 133 | self = Delete(keys) 134 | } 135 | } -------------------------------------------------------------------------------- /Source/Pool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pool.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | import MultipeerConnectivity 26 | 27 | internal typealias Key = String 28 | internal typealias Value = AnyObject 29 | 30 | public class Pool { 31 | public let name: String 32 | 33 | private let session: Session 34 | 35 | private var local: [Key: Value] = [:] 36 | private var manifest: [Key: MCPeerID] = [:] 37 | private var callbacks: [Key: (Value?) -> Void] = [:] 38 | 39 | public init(name: String) { 40 | self.name = name 41 | session = Session(name: name) 42 | session.delegate = self 43 | } 44 | 45 | public func objectForKey(key: String, completion: (AnyObject?) -> Void) { 46 | if let object = local[key] { 47 | completion(object) 48 | return 49 | } 50 | 51 | guard let peer = manifest[key] else { 52 | completion(nil) 53 | return 54 | } 55 | 56 | callbacks[key] = completion 57 | 58 | session.sendRequest(key, toPeers: [peer]) 59 | } 60 | 61 | public func setObject(object: AnyObject, forKey key: String) { 62 | if local[key] == nil { 63 | session.sendInsert([key], toPeers: session.peers) 64 | } 65 | 66 | local[key] = object 67 | } 68 | 69 | public func removeObjectForKey(key: String) { 70 | if local[key] != nil { 71 | session.sendDelete([key], toPeers: session.peers) 72 | } 73 | 74 | local[key] = nil 75 | } 76 | 77 | public func removeAllObjects() { 78 | session.sendDelete(Array(local.keys), toPeers: session.peers) 79 | 80 | local.removeAll() 81 | manifest.removeAll() 82 | callbacks.removeAll() 83 | } 84 | } 85 | 86 | // MARK: - SessionDelegate 87 | 88 | extension Pool: SessionDelegate { 89 | func session(session: Session, peerDidConnect peer: MCPeerID) { 90 | session.sendInsert(Array(local.keys), toPeers: [peer]) 91 | } 92 | 93 | func session(session: Session, peerDidDisconnect peer: MCPeerID) { 94 | for (key, value) in manifest where peer == value { 95 | manifest[key] = nil 96 | } 97 | } 98 | 99 | func session(session: Session, didReceiveRequestForKey key: Key, fromPeer peer: MCPeerID) { 100 | session.sendResponse(key, value: local[key], toPeers: [peer]) 101 | } 102 | 103 | func session(session: Session, didReceiveResponseWithKey key: Key, andValue value: Value?, fromPeer peer: MCPeerID) { 104 | callbacks[key]?(value) 105 | callbacks[key] = nil 106 | local[key] = value 107 | } 108 | 109 | func session(session: Session, didReceiveInsertForKeys keys: [Key], fromPeer peer: MCPeerID) { 110 | keys.forEach { manifest[$0] = peer } 111 | } 112 | 113 | func session(session: Session, didReceiveDeleteForKeys keys: [Key], fromPeer peer: MCPeerID) { 114 | keys.forEach { manifest[$0] = nil } 115 | } 116 | } -------------------------------------------------------------------------------- /Source/Session.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Session.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | import MultipeerConnectivity 26 | 27 | internal class Session: NSObject { 28 | internal var delegate: SessionDelegate? 29 | 30 | private let peer: MCPeerID 31 | private let session: MCSession 32 | private let browser: MCNearbyServiceBrowser 33 | private let advertiser: MCNearbyServiceAdvertiser 34 | 35 | internal var peers: [MCPeerID] { 36 | return session.connectedPeers.filter({ $0 != peer }) 37 | } 38 | 39 | internal init(name: String) { 40 | peer = MCPeerID(displayName: UIDevice.currentDevice().name) 41 | session = MCSession(peer: peer, securityIdentity: nil, encryptionPreference: .Required) 42 | browser = MCNearbyServiceBrowser(peer: peer, serviceType: name) 43 | advertiser = MCNearbyServiceAdvertiser(peer: peer, discoveryInfo: nil, serviceType: name) 44 | 45 | super.init() 46 | 47 | session.delegate = self 48 | browser.delegate = self 49 | advertiser.delegate = self 50 | 51 | browser.startBrowsingForPeers() 52 | advertiser.startAdvertisingPeer() 53 | } 54 | 55 | deinit { 56 | browser.stopBrowsingForPeers() 57 | advertiser.stopAdvertisingPeer() 58 | } 59 | 60 | internal func sendRequest(key: Key, toPeers peers: [MCPeerID]) { 61 | let message: Message = .Request(key) 62 | sendMessage(message, toPeers: peers) 63 | } 64 | 65 | internal func sendResponse(key: Key, value: Value?, toPeers peers: [MCPeerID]) { 66 | let message: Message = .Response(key, value) 67 | sendMessage(message, toPeers: peers) 68 | } 69 | 70 | internal func sendInsert(keys: [Key], toPeers peers: [MCPeerID]) { 71 | let message: Message = .Insert(keys) 72 | sendMessage(message, toPeers: peers) 73 | } 74 | 75 | internal func sendDelete(keys: [Key], toPeers peers: [MCPeerID]) { 76 | let message: Message = .Delete(keys) 77 | sendMessage(message, toPeers: peers) 78 | } 79 | 80 | private func sendMessage(message: Message, toPeers peers: [MCPeerID]) { 81 | let data = message.toData() 82 | try? session.sendData(data, toPeers: peers, withMode: .Reliable) 83 | } 84 | } 85 | 86 | // MARK: - MCNearbyServiceAdvertiserDelegate 87 | 88 | extension Session: MCNearbyServiceAdvertiserDelegate { 89 | func advertiser(advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: NSData?, invitationHandler: (Bool, MCSession) -> Void) { 90 | invitationHandler(true, session) 91 | } 92 | } 93 | 94 | // MARK: - MCNearbyServiceBrowserDelegate 95 | 96 | extension Session: MCNearbyServiceBrowserDelegate { 97 | func browser(browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) { 98 | browser.invitePeer(peerID, toSession: session, withContext: nil, timeout: 10) 99 | } 100 | 101 | func browser(browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) { 102 | delegate?.session(self, peerDidDisconnect: peerID) 103 | } 104 | } 105 | 106 | // MARK: - MCSessionDelegate 107 | 108 | extension Session: MCSessionDelegate { 109 | func session(session: MCSession, peer peerID: MCPeerID, didChangeState state: MCSessionState) { 110 | switch state { 111 | case .Connected: delegate?.session(self, peerDidConnect: peerID) 112 | case .NotConnected: delegate?.session(self, peerDidDisconnect: peerID) 113 | default: break 114 | } 115 | } 116 | 117 | func session(session: MCSession, didReceiveData data: NSData, fromPeer peerID: MCPeerID) { 118 | guard let message = Message(data: data) else { return } 119 | 120 | switch message { 121 | case let .Request(key): delegate?.session(self, didReceiveRequestForKey: key, fromPeer: peerID) 122 | case let .Response(k, v): delegate?.session(self, didReceiveResponseWithKey: k, andValue: v, fromPeer: peerID) 123 | case let .Insert(keys): delegate?.session(self, didReceiveInsertForKeys: keys, fromPeer: peerID) 124 | case let .Delete(keys): delegate?.session(self, didReceiveDeleteForKeys: keys, fromPeer: peerID) 125 | } 126 | } 127 | 128 | func session(session: MCSession, didReceiveStream stream: NSInputStream, withName streamName: String, fromPeer peerID: MCPeerID) {} 129 | func session(session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, atURL localURL: NSURL, withError error: NSError?) {} 130 | func session(session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, withProgress progress: NSProgress) {} 131 | } 132 | -------------------------------------------------------------------------------- /Source/SessionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionDelegate.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | import MultipeerConnectivity 26 | 27 | internal protocol SessionDelegate { 28 | func session(session: Session, peerDidConnect peer: MCPeerID) 29 | func session(session: Session, peerDidDisconnect peer: MCPeerID) 30 | func session(session: Session, didReceiveRequestForKey key: Key, fromPeer peer: MCPeerID) 31 | func session(session: Session, didReceiveResponseWithKey key: Key, andValue value: Value?, fromPeer peer: MCPeerID) 32 | func session(session: Session, didReceiveInsertForKeys keys: [Key], fromPeer peer: MCPeerID) 33 | func session(session: Session, didReceiveDeleteForKeys keys: [Key], fromPeer peer: MCPeerID) 34 | } -------------------------------------------------------------------------------- /Source/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Source/Supporting Files/Pool.h: -------------------------------------------------------------------------------- 1 | // 2 | // Pool.h 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | @import Foundation; 26 | 27 | FOUNDATION_EXPORT double PoolVersionNumber; 28 | FOUNDATION_EXPORT const unsigned char PoolVersionString[]; -------------------------------------------------------------------------------- /Source/Supporting Files/Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pool.h 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | // MARK: - Array 26 | 27 | extension Array { 28 | subscript(safe index: Int) -> Element? { 29 | return indices ~= index ? self[index] : nil 30 | } 31 | } 32 | 33 | // MARK: - KeyArchiver 34 | 35 | struct KeyArchiver { 36 | static func archive(object: AnyObject) -> NSData { 37 | return NSKeyedArchiver.archivedDataWithRootObject(object) 38 | } 39 | 40 | static func unarchive(data: NSData) -> AnyObject? { 41 | return NSKeyedUnarchiver.unarchiveObjectWithData(data) 42 | } 43 | } -------------------------------------------------------------------------------- /Tests/MessageTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageTests.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | import XCTest 26 | @testable import Pool 27 | 28 | class MessageTests: XCTestCase { 29 | func testRequest() { 30 | let message: Message = .Request("a") 31 | let data = message.toData() 32 | 33 | guard case .Request("a") = Message(data: data)! else { 34 | XCTFail() 35 | return 36 | } 37 | } 38 | 39 | func testResponse() { 40 | let message: Message = .Response("a", 42) 41 | let data = message.toData() 42 | 43 | guard case .Response("a", let value) = Message(data: data)! else { 44 | XCTFail() 45 | return 46 | } 47 | 48 | XCTAssertEqual(42, value as? Int) 49 | } 50 | 51 | func testInsert() { 52 | let message: Message = .Insert(["a", "b", "c"]) 53 | let data = message.toData() 54 | 55 | guard case .Insert(let keys) = Message(data: data)! else { 56 | XCTFail() 57 | return 58 | } 59 | 60 | XCTAssertEqual(["a", "b", "c"], keys) 61 | } 62 | 63 | func testDelete() { 64 | let message: Message = .Delete(["a", "b", "c"]) 65 | let data = message.toData() 66 | 67 | guard case .Delete(let keys) = Message(data: data)! else { 68 | XCTFail() 69 | return 70 | } 71 | 72 | XCTAssertEqual(["a", "b", "c"], keys) 73 | } 74 | } -------------------------------------------------------------------------------- /Tests/PoolTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PoolTests.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | import XCTest 26 | @testable import Pool 27 | 28 | class PoolTests: XCTestCase { 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Tests/SessionDelegateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionDelegateTests.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | import XCTest 26 | @testable import Pool 27 | 28 | class SessionDelegateTests: XCTestCase { 29 | 30 | } -------------------------------------------------------------------------------- /Tests/SessionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionTests.swift 3 | // 4 | // Copyright (c) 2016 Damien (http://delba.io) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | 25 | import XCTest 26 | @testable import Pool 27 | 28 | class SessionTests: XCTestCase { 29 | 30 | } -------------------------------------------------------------------------------- /Tests/Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | --------------------------------------------------------------------------------