├── .gitignore ├── .swift-version ├── .travis.yml ├── Continuum.playground ├── Contents.swift └── contents.xcplayground ├── Continuum.podspec ├── Continuum.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── Continuum.xcscheme │ └── ContinuumTests.xcscheme ├── Continuum.xcworkspace └── contents.xcworkspacedata ├── Continuum ├── Constant.swift ├── Continuum.h ├── Continuum.swift ├── Info.plist ├── Internal │ ├── AnyKeyPath.extension.swift │ └── PThreadMutex.swift ├── Variable.swift └── Wrappable.swift ├── ContinuumTests ├── ConstantTests.swift ├── ContinuumTests.swift ├── Info.plist ├── OnValueChangeClosureTests.swift └── VariableTests.swift ├── Example ├── ContinuumSample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── ContinuumSample.xcworkspace │ └── contents.xcworkspacedata ├── ContinuumSample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift ├── Podfile ├── Podfile.lock └── Pods │ ├── Local Podspecs │ └── Continuum.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ └── project.pbxproj │ └── Target Support Files │ ├── Continuum │ ├── Continuum-dummy.m │ ├── Continuum-prefix.pch │ ├── Continuum-umbrella.h │ ├── Continuum.modulemap │ ├── Continuum.xcconfig │ └── Info.plist │ └── Pods-ContinuumSample │ ├── Info.plist │ ├── Pods-ContinuumSample-acknowledgements.markdown │ ├── Pods-ContinuumSample-acknowledgements.plist │ ├── Pods-ContinuumSample-dummy.m │ ├── Pods-ContinuumSample-frameworks.sh │ ├── Pods-ContinuumSample-resources.sh │ ├── Pods-ContinuumSample-umbrella.h │ ├── Pods-ContinuumSample.debug.xcconfig │ ├── Pods-ContinuumSample.modulemap │ └── Pods-ContinuumSample.release.xcconfig ├── Images ├── example.png └── playground.png ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | .DS_Store 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | .build/ 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots 69 | fastlane/test_output 70 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | matrix: 3 | include: 4 | - osx_image: xcode9.2 5 | env: 6 | global: 7 | - LC_CTYPE=en_US.UTF-8 8 | git: 9 | submodules: false 10 | branches: 11 | only: 12 | - master 13 | script: 14 | - xcodebuild test -workspace Continuum.xcworkspace -scheme ContinuumTests -configuration Debug -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 7" | xcpretty -c 15 | notifications: 16 | email: 17 | on_success: never 18 | on_failure: always 19 | -------------------------------------------------------------------------------- /Continuum.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //: Playground - noun: a place where people can play 2 | 3 | import UIKit 4 | import Continuum 5 | import PlaygroundSupport 6 | 7 | PlaygroundPage.current.needsIndefiniteExecution = true 8 | 9 | // KeyPath 10 | do { 11 | class ViewModel { 12 | var text = "" 13 | } 14 | 15 | let center = NotificationCenter() 16 | let viewModel = ViewModel() 17 | let label = UILabel() 18 | 19 | _ = center.continuum.observe(viewModel, \.text, bindTo: label, \.text) 20 | print("After observe: label.text = \(String(describing: label.text))") 21 | 22 | viewModel.text = "Great Scott!" 23 | center.continuum.post(keyPath: \ViewModel.text) 24 | print("After post: label.text = \(String(describing: label.text))") 25 | } 26 | 27 | // Constant and Variable 28 | do { 29 | let center = NotificationCenter() 30 | 31 | let variable = Variable(value: "") 32 | let label = UILabel() 33 | 34 | let constant = Constant(variable: variable) 35 | let label2 = UILabel() 36 | 37 | _ = center.continuum.observe(variable, bindTo: label, \.text) 38 | _ = center.continuum.observe(constant, bindTo: label2, \.text) 39 | print("After observe: label.text = \(String(describing: label.text))") 40 | print("After observe: label2.text = \(String(describing: label2.text))") 41 | 42 | variable.value = "Nobody calls me chicken!" 43 | print("After post: label.text = \(String(describing: label.text))") 44 | print("After post: label2.text = \(String(describing: label2.text))") 45 | 46 | let v2 = Variable(value: "") 47 | _ = center.continuum.observe(constant, bindTo: v2, \Variable.value) 48 | print("After observe: v2.value = \(v2.value)") 49 | 50 | variable.value = "Back to the future!" 51 | print("After post: label.text = \(String(describing: label.text))") 52 | print("After post: label2.text = \(String(describing: label2.text))") 53 | print("After post: v2.value = \(v2.value)") 54 | } 55 | -------------------------------------------------------------------------------- /Continuum.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Continuum.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint Continuum.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'Continuum' 11 | s.version = '0.3.0' 12 | s.summary = 'NotificationCenter based Lightweight UI / AnyObject binder.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | # s.description = <<-DESC 21 | # TODO: Add long description of the pod here. 22 | # DESC 23 | 24 | s.homepage = 'https://github.com/marty-suzuki/Continuum' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'marty-suzuki' => 's1180183@gmail.com' } 28 | s.source = { :git => 'https://github.com/marty-suzuki/Continuum.git', :tag => s.version.to_s } 29 | s.social_media_url = 'https://twitter.com/marty_suzuki' 30 | 31 | s.ios.deployment_target = '10.0' 32 | 33 | s.source_files = 'Continuum/**/*.{swift}' 34 | 35 | # s.resource_bundles = { 36 | # 'Continuum' => ['Continuum/Assets/*.png'] 37 | # } 38 | 39 | # s.public_header_files = 'Pod/Classes/**/*.h' 40 | # s.frameworks = 'UIKit', 'MapKit' 41 | # s.dependency 'AFNetworking', '~> 2.3' 42 | end 43 | -------------------------------------------------------------------------------- /Continuum.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1F95662A2042681800039EB2 /* OnValueChangeClosureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F9566292042681800039EB2 /* OnValueChangeClosureTests.swift */; }; 11 | 3700DEE0202A17630010408B /* PThreadMutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700DEDF202A17630010408B /* PThreadMutex.swift */; }; 12 | 379BCD192029FF9600450632 /* Continuum.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 379BCD0F2029FF9600450632 /* Continuum.framework */; }; 13 | 379BCD1E2029FF9600450632 /* ContinuumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379BCD1D2029FF9600450632 /* ContinuumTests.swift */; }; 14 | 379BCD202029FF9600450632 /* Continuum.h in Headers */ = {isa = PBXBuildFile; fileRef = 379BCD122029FF9600450632 /* Continuum.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 379BCD2B202A00AE00450632 /* Wrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379BCD2A202A00AE00450632 /* Wrappable.swift */; }; 16 | 379BCD2D202A00F700450632 /* AnyKeyPath.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379BCD2C202A00F700450632 /* AnyKeyPath.extension.swift */; }; 17 | 379BCD2F202A016600450632 /* Continuum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379BCD2E202A016600450632 /* Continuum.swift */; }; 18 | 9DF34AC2202C490A00809EF1 /* VariableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF34AC1202C490A00809EF1 /* VariableTests.swift */; }; 19 | 9DF34AC4202C493B00809EF1 /* ConstantTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF34AC3202C493B00809EF1 /* ConstantTests.swift */; }; 20 | ED03FD7F202B52300084D73B /* Variable.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED03FD7E202B52300084D73B /* Variable.swift */; }; 21 | ED03FD81202B548A0084D73B /* Constant.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED03FD80202B548A0084D73B /* Constant.swift */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | 379BCD1A2029FF9600450632 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = 379BCD062029FF9600450632 /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = 379BCD0E2029FF9600450632; 30 | remoteInfo = Continuum; 31 | }; 32 | /* End PBXContainerItemProxy section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 1F9566292042681800039EB2 /* OnValueChangeClosureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnValueChangeClosureTests.swift; sourceTree = ""; }; 36 | 3700DEDF202A17630010408B /* PThreadMutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PThreadMutex.swift; sourceTree = ""; }; 37 | 379BCD0F2029FF9600450632 /* Continuum.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Continuum.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 379BCD122029FF9600450632 /* Continuum.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Continuum.h; sourceTree = ""; }; 39 | 379BCD132029FF9600450632 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 379BCD182029FF9600450632 /* ContinuumTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ContinuumTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 379BCD1D2029FF9600450632 /* ContinuumTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinuumTests.swift; sourceTree = ""; }; 42 | 379BCD1F2029FF9600450632 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | 379BCD2A202A00AE00450632 /* Wrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wrappable.swift; sourceTree = ""; }; 44 | 379BCD2C202A00F700450632 /* AnyKeyPath.extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyKeyPath.extension.swift; sourceTree = ""; }; 45 | 379BCD2E202A016600450632 /* Continuum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Continuum.swift; sourceTree = ""; }; 46 | 9DF34AC1202C490A00809EF1 /* VariableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariableTests.swift; sourceTree = ""; }; 47 | 9DF34AC3202C493B00809EF1 /* ConstantTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantTests.swift; sourceTree = ""; }; 48 | ED03FD7E202B52300084D73B /* Variable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Variable.swift; sourceTree = ""; }; 49 | ED03FD80202B548A0084D73B /* Constant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constant.swift; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 379BCD0B2029FF9600450632 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | 379BCD152029FF9600450632 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | 379BCD192029FF9600450632 /* Continuum.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 379BCD052029FF9600450632 = { 72 | isa = PBXGroup; 73 | children = ( 74 | 379BCD112029FF9600450632 /* Continuum */, 75 | 379BCD1C2029FF9600450632 /* ContinuumTests */, 76 | 379BCD102029FF9600450632 /* Products */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 379BCD102029FF9600450632 /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 379BCD0F2029FF9600450632 /* Continuum.framework */, 84 | 379BCD182029FF9600450632 /* ContinuumTests.xctest */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | 379BCD112029FF9600450632 /* Continuum */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 379BCD29202A009E00450632 /* Internal */, 93 | 379BCD122029FF9600450632 /* Continuum.h */, 94 | 379BCD132029FF9600450632 /* Info.plist */, 95 | 379BCD2A202A00AE00450632 /* Wrappable.swift */, 96 | 379BCD2E202A016600450632 /* Continuum.swift */, 97 | ED03FD7E202B52300084D73B /* Variable.swift */, 98 | ED03FD80202B548A0084D73B /* Constant.swift */, 99 | ); 100 | path = Continuum; 101 | sourceTree = ""; 102 | }; 103 | 379BCD1C2029FF9600450632 /* ContinuumTests */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 379BCD1D2029FF9600450632 /* ContinuumTests.swift */, 107 | 379BCD1F2029FF9600450632 /* Info.plist */, 108 | 9DF34AC1202C490A00809EF1 /* VariableTests.swift */, 109 | 9DF34AC3202C493B00809EF1 /* ConstantTests.swift */, 110 | 1F9566292042681800039EB2 /* OnValueChangeClosureTests.swift */, 111 | ); 112 | path = ContinuumTests; 113 | sourceTree = ""; 114 | }; 115 | 379BCD29202A009E00450632 /* Internal */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 379BCD2C202A00F700450632 /* AnyKeyPath.extension.swift */, 119 | 3700DEDF202A17630010408B /* PThreadMutex.swift */, 120 | ); 121 | path = Internal; 122 | sourceTree = ""; 123 | }; 124 | /* End PBXGroup section */ 125 | 126 | /* Begin PBXHeadersBuildPhase section */ 127 | 379BCD0C2029FF9600450632 /* Headers */ = { 128 | isa = PBXHeadersBuildPhase; 129 | buildActionMask = 2147483647; 130 | files = ( 131 | 379BCD202029FF9600450632 /* Continuum.h in Headers */, 132 | ); 133 | runOnlyForDeploymentPostprocessing = 0; 134 | }; 135 | /* End PBXHeadersBuildPhase section */ 136 | 137 | /* Begin PBXNativeTarget section */ 138 | 379BCD0E2029FF9600450632 /* Continuum */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = 379BCD232029FF9600450632 /* Build configuration list for PBXNativeTarget "Continuum" */; 141 | buildPhases = ( 142 | 379BCD0A2029FF9600450632 /* Sources */, 143 | 379BCD0B2029FF9600450632 /* Frameworks */, 144 | 379BCD0C2029FF9600450632 /* Headers */, 145 | 379BCD0D2029FF9600450632 /* Resources */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | ); 151 | name = Continuum; 152 | productName = Continuum; 153 | productReference = 379BCD0F2029FF9600450632 /* Continuum.framework */; 154 | productType = "com.apple.product-type.framework"; 155 | }; 156 | 379BCD172029FF9600450632 /* ContinuumTests */ = { 157 | isa = PBXNativeTarget; 158 | buildConfigurationList = 379BCD262029FF9600450632 /* Build configuration list for PBXNativeTarget "ContinuumTests" */; 159 | buildPhases = ( 160 | 379BCD142029FF9600450632 /* Sources */, 161 | 379BCD152029FF9600450632 /* Frameworks */, 162 | 379BCD162029FF9600450632 /* Resources */, 163 | ); 164 | buildRules = ( 165 | ); 166 | dependencies = ( 167 | 379BCD1B2029FF9600450632 /* PBXTargetDependency */, 168 | ); 169 | name = ContinuumTests; 170 | productName = ContinuumTests; 171 | productReference = 379BCD182029FF9600450632 /* ContinuumTests.xctest */; 172 | productType = "com.apple.product-type.bundle.unit-test"; 173 | }; 174 | /* End PBXNativeTarget section */ 175 | 176 | /* Begin PBXProject section */ 177 | 379BCD062029FF9600450632 /* Project object */ = { 178 | isa = PBXProject; 179 | attributes = { 180 | LastSwiftUpdateCheck = 0920; 181 | LastUpgradeCheck = 0920; 182 | ORGANIZATIONNAME = "marty-suzuki"; 183 | TargetAttributes = { 184 | 379BCD0E2029FF9600450632 = { 185 | CreatedOnToolsVersion = 9.2; 186 | LastSwiftMigration = 0920; 187 | ProvisioningStyle = Automatic; 188 | }; 189 | 379BCD172029FF9600450632 = { 190 | CreatedOnToolsVersion = 9.2; 191 | ProvisioningStyle = Automatic; 192 | }; 193 | }; 194 | }; 195 | buildConfigurationList = 379BCD092029FF9600450632 /* Build configuration list for PBXProject "Continuum" */; 196 | compatibilityVersion = "Xcode 8.0"; 197 | developmentRegion = en; 198 | hasScannedForEncodings = 0; 199 | knownRegions = ( 200 | en, 201 | ); 202 | mainGroup = 379BCD052029FF9600450632; 203 | productRefGroup = 379BCD102029FF9600450632 /* Products */; 204 | projectDirPath = ""; 205 | projectRoot = ""; 206 | targets = ( 207 | 379BCD0E2029FF9600450632 /* Continuum */, 208 | 379BCD172029FF9600450632 /* ContinuumTests */, 209 | ); 210 | }; 211 | /* End PBXProject section */ 212 | 213 | /* Begin PBXResourcesBuildPhase section */ 214 | 379BCD0D2029FF9600450632 /* Resources */ = { 215 | isa = PBXResourcesBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | 379BCD162029FF9600450632 /* Resources */ = { 222 | isa = PBXResourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXResourcesBuildPhase section */ 229 | 230 | /* Begin PBXSourcesBuildPhase section */ 231 | 379BCD0A2029FF9600450632 /* Sources */ = { 232 | isa = PBXSourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 3700DEE0202A17630010408B /* PThreadMutex.swift in Sources */, 236 | 379BCD2D202A00F700450632 /* AnyKeyPath.extension.swift in Sources */, 237 | 379BCD2F202A016600450632 /* Continuum.swift in Sources */, 238 | 379BCD2B202A00AE00450632 /* Wrappable.swift in Sources */, 239 | ED03FD7F202B52300084D73B /* Variable.swift in Sources */, 240 | ED03FD81202B548A0084D73B /* Constant.swift in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | 379BCD142029FF9600450632 /* Sources */ = { 245 | isa = PBXSourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | 379BCD1E2029FF9600450632 /* ContinuumTests.swift in Sources */, 249 | 9DF34AC4202C493B00809EF1 /* ConstantTests.swift in Sources */, 250 | 1F95662A2042681800039EB2 /* OnValueChangeClosureTests.swift in Sources */, 251 | 9DF34AC2202C490A00809EF1 /* VariableTests.swift in Sources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | /* End PBXSourcesBuildPhase section */ 256 | 257 | /* Begin PBXTargetDependency section */ 258 | 379BCD1B2029FF9600450632 /* PBXTargetDependency */ = { 259 | isa = PBXTargetDependency; 260 | target = 379BCD0E2029FF9600450632 /* Continuum */; 261 | targetProxy = 379BCD1A2029FF9600450632 /* PBXContainerItemProxy */; 262 | }; 263 | /* End PBXTargetDependency section */ 264 | 265 | /* Begin XCBuildConfiguration section */ 266 | 379BCD212029FF9600450632 /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_SEARCH_USER_PATHS = NO; 270 | CLANG_ANALYZER_NONNULL = YES; 271 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 272 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 273 | CLANG_CXX_LIBRARY = "libc++"; 274 | CLANG_ENABLE_MODULES = YES; 275 | CLANG_ENABLE_OBJC_ARC = YES; 276 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 277 | CLANG_WARN_BOOL_CONVERSION = YES; 278 | CLANG_WARN_COMMA = YES; 279 | CLANG_WARN_CONSTANT_CONVERSION = YES; 280 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 281 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 282 | CLANG_WARN_EMPTY_BODY = YES; 283 | CLANG_WARN_ENUM_CONVERSION = YES; 284 | CLANG_WARN_INFINITE_RECURSION = YES; 285 | CLANG_WARN_INT_CONVERSION = YES; 286 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 287 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 288 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 289 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 290 | CLANG_WARN_STRICT_PROTOTYPES = YES; 291 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 292 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 293 | CLANG_WARN_UNREACHABLE_CODE = YES; 294 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 295 | CODE_SIGN_IDENTITY = "iPhone Developer"; 296 | COPY_PHASE_STRIP = NO; 297 | CURRENT_PROJECT_VERSION = 1; 298 | DEBUG_INFORMATION_FORMAT = dwarf; 299 | ENABLE_STRICT_OBJC_MSGSEND = YES; 300 | ENABLE_TESTABILITY = YES; 301 | GCC_C_LANGUAGE_STANDARD = gnu11; 302 | GCC_DYNAMIC_NO_PIC = NO; 303 | GCC_NO_COMMON_BLOCKS = YES; 304 | GCC_OPTIMIZATION_LEVEL = 0; 305 | GCC_PREPROCESSOR_DEFINITIONS = ( 306 | "DEBUG=1", 307 | "$(inherited)", 308 | ); 309 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 310 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 311 | GCC_WARN_UNDECLARED_SELECTOR = YES; 312 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 313 | GCC_WARN_UNUSED_FUNCTION = YES; 314 | GCC_WARN_UNUSED_VARIABLE = YES; 315 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 316 | MTL_ENABLE_DEBUG_INFO = YES; 317 | ONLY_ACTIVE_ARCH = YES; 318 | SDKROOT = iphoneos; 319 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 320 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 321 | VERSIONING_SYSTEM = "apple-generic"; 322 | VERSION_INFO_PREFIX = ""; 323 | }; 324 | name = Debug; 325 | }; 326 | 379BCD222029FF9600450632 /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ALWAYS_SEARCH_USER_PATHS = NO; 330 | CLANG_ANALYZER_NONNULL = YES; 331 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 333 | CLANG_CXX_LIBRARY = "libc++"; 334 | CLANG_ENABLE_MODULES = YES; 335 | CLANG_ENABLE_OBJC_ARC = YES; 336 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 337 | CLANG_WARN_BOOL_CONVERSION = YES; 338 | CLANG_WARN_COMMA = YES; 339 | CLANG_WARN_CONSTANT_CONVERSION = YES; 340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 341 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 342 | CLANG_WARN_EMPTY_BODY = YES; 343 | CLANG_WARN_ENUM_CONVERSION = YES; 344 | CLANG_WARN_INFINITE_RECURSION = YES; 345 | CLANG_WARN_INT_CONVERSION = YES; 346 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 347 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 348 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 349 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 350 | CLANG_WARN_STRICT_PROTOTYPES = YES; 351 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 352 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 353 | CLANG_WARN_UNREACHABLE_CODE = YES; 354 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 355 | CODE_SIGN_IDENTITY = "iPhone Developer"; 356 | COPY_PHASE_STRIP = NO; 357 | CURRENT_PROJECT_VERSION = 1; 358 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 359 | ENABLE_NS_ASSERTIONS = NO; 360 | ENABLE_STRICT_OBJC_MSGSEND = YES; 361 | GCC_C_LANGUAGE_STANDARD = gnu11; 362 | GCC_NO_COMMON_BLOCKS = YES; 363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 365 | GCC_WARN_UNDECLARED_SELECTOR = YES; 366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 367 | GCC_WARN_UNUSED_FUNCTION = YES; 368 | GCC_WARN_UNUSED_VARIABLE = YES; 369 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 370 | MTL_ENABLE_DEBUG_INFO = NO; 371 | SDKROOT = iphoneos; 372 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 373 | VALIDATE_PRODUCT = YES; 374 | VERSIONING_SYSTEM = "apple-generic"; 375 | VERSION_INFO_PREFIX = ""; 376 | }; 377 | name = Release; 378 | }; 379 | 379BCD242029FF9600450632 /* Debug */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | CLANG_ENABLE_MODULES = YES; 383 | CODE_SIGN_IDENTITY = ""; 384 | CODE_SIGN_STYLE = Automatic; 385 | DEFINES_MODULE = YES; 386 | DYLIB_COMPATIBILITY_VERSION = 1; 387 | DYLIB_CURRENT_VERSION = 1; 388 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 389 | INFOPLIST_FILE = Continuum/Info.plist; 390 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 391 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 393 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.Continuum"; 394 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 395 | SKIP_INSTALL = YES; 396 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 397 | SWIFT_VERSION = 4.0; 398 | TARGETED_DEVICE_FAMILY = "1,2"; 399 | }; 400 | name = Debug; 401 | }; 402 | 379BCD252029FF9600450632 /* Release */ = { 403 | isa = XCBuildConfiguration; 404 | buildSettings = { 405 | CLANG_ENABLE_MODULES = YES; 406 | CODE_SIGN_IDENTITY = ""; 407 | CODE_SIGN_STYLE = Automatic; 408 | DEFINES_MODULE = YES; 409 | DYLIB_COMPATIBILITY_VERSION = 1; 410 | DYLIB_CURRENT_VERSION = 1; 411 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 412 | INFOPLIST_FILE = Continuum/Info.plist; 413 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 414 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 415 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 416 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.Continuum"; 417 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 418 | SKIP_INSTALL = YES; 419 | SWIFT_VERSION = 4.0; 420 | TARGETED_DEVICE_FAMILY = "1,2"; 421 | }; 422 | name = Release; 423 | }; 424 | 379BCD272029FF9600450632 /* Debug */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 428 | CODE_SIGN_STYLE = Automatic; 429 | INFOPLIST_FILE = ContinuumTests/Info.plist; 430 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 431 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.ContinuumTests"; 432 | PRODUCT_NAME = "$(TARGET_NAME)"; 433 | SWIFT_VERSION = 4.0; 434 | TARGETED_DEVICE_FAMILY = "1,2"; 435 | }; 436 | name = Debug; 437 | }; 438 | 379BCD282029FF9600450632 /* Release */ = { 439 | isa = XCBuildConfiguration; 440 | buildSettings = { 441 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 442 | CODE_SIGN_STYLE = Automatic; 443 | INFOPLIST_FILE = ContinuumTests/Info.plist; 444 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 445 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.ContinuumTests"; 446 | PRODUCT_NAME = "$(TARGET_NAME)"; 447 | SWIFT_VERSION = 4.0; 448 | TARGETED_DEVICE_FAMILY = "1,2"; 449 | }; 450 | name = Release; 451 | }; 452 | /* End XCBuildConfiguration section */ 453 | 454 | /* Begin XCConfigurationList section */ 455 | 379BCD092029FF9600450632 /* Build configuration list for PBXProject "Continuum" */ = { 456 | isa = XCConfigurationList; 457 | buildConfigurations = ( 458 | 379BCD212029FF9600450632 /* Debug */, 459 | 379BCD222029FF9600450632 /* Release */, 460 | ); 461 | defaultConfigurationIsVisible = 0; 462 | defaultConfigurationName = Release; 463 | }; 464 | 379BCD232029FF9600450632 /* Build configuration list for PBXNativeTarget "Continuum" */ = { 465 | isa = XCConfigurationList; 466 | buildConfigurations = ( 467 | 379BCD242029FF9600450632 /* Debug */, 468 | 379BCD252029FF9600450632 /* Release */, 469 | ); 470 | defaultConfigurationIsVisible = 0; 471 | defaultConfigurationName = Release; 472 | }; 473 | 379BCD262029FF9600450632 /* Build configuration list for PBXNativeTarget "ContinuumTests" */ = { 474 | isa = XCConfigurationList; 475 | buildConfigurations = ( 476 | 379BCD272029FF9600450632 /* Debug */, 477 | 379BCD282029FF9600450632 /* Release */, 478 | ); 479 | defaultConfigurationIsVisible = 0; 480 | defaultConfigurationName = Release; 481 | }; 482 | /* End XCConfigurationList section */ 483 | }; 484 | rootObject = 379BCD062029FF9600450632 /* Project object */; 485 | } 486 | -------------------------------------------------------------------------------- /Continuum.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Continuum.xcodeproj/xcshareddata/xcschemes/Continuum.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Continuum.xcodeproj/xcshareddata/xcschemes/ContinuumTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 41 | 42 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Continuum.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Continuum/Constant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constant.swift 3 | // Continuum 4 | // 5 | // Created by 鈴木大貴 on 2018/02/08. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Constant is wrapper for value that has getter. 12 | public final class Constant: ValueRepresentable, NotificationCenterSettable { 13 | /// Gets current value of constant. 14 | public var value: Element { 15 | return _variable.value 16 | } 17 | 18 | /// Represents unique Notification.Name for each constants. 19 | public var uniqueName: Notification.Name { 20 | return _variable.uniqueName 21 | } 22 | 23 | private let _variable: Variable 24 | 25 | /// Initializes Constant with a Variable. 26 | /// 27 | /// - parameter value: Variable. 28 | public init(variable: Variable) { 29 | self._variable = variable 30 | } 31 | 32 | func setCenter(_ center: NotificationCenter) { 33 | _variable.setCenter(center) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Continuum/Continuum.h: -------------------------------------------------------------------------------- 1 | // 2 | // Continuum.h 3 | // Continuum 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Continuum. 12 | FOUNDATION_EXPORT double ContinuumVersionNumber; 13 | 14 | //! Project version string for Continuum. 15 | FOUNDATION_EXPORT const unsigned char ContinuumVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Continuum/Continuum.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Continuum.swift 3 | // Continuum 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct NotificationCenterContinuum { 12 | fileprivate let center: NotificationCenter 13 | } 14 | 15 | extension NotificationCenter { 16 | /// Continuum extensions. 17 | public var continuum: NotificationCenterContinuum { 18 | return .init(center: self) 19 | } 20 | } 21 | 22 | /// Reresents typealias of NotificationCenterContinuum.Observer. 23 | public typealias ContinuumObserver = NotificationCenterContinuum.Observer 24 | /// Reresents typealias of NotificationCenterContinuum.Bag. 25 | public typealias ContinuumBag = NotificationCenterContinuum.Bag 26 | 27 | extension NotificationCenterContinuum { 28 | /// Reprisents Continuum Observer. 29 | public class Observer { 30 | private let rawObserver: NSObjectProtocol 31 | private let center: NotificationCenter 32 | private let mutex = PThreadMutex() 33 | 34 | /// Represents observation is cannceld or not. 35 | public private(set) var isCancelled: Bool = false 36 | 37 | fileprivate init(rawObserver: NSObjectProtocol, center: NotificationCenter) { 38 | self.rawObserver = rawObserver 39 | self.center = center 40 | } 41 | 42 | /// Cancel observation. 43 | public func cancel() { 44 | mutex.lock() 45 | center.removeObserver(rawObserver) 46 | isCancelled = true 47 | mutex.unlock() 48 | } 49 | 50 | /// Adds observer to a bag. 51 | /// 52 | /// - parameter bag: baguage for observer. 53 | public func disposed(by bag: Bag) { 54 | bag.add(self) 55 | } 56 | } 57 | 58 | /// Reprisents Bag for Observer. 59 | public class Bag { 60 | private var observers: [Observer] = [] 61 | private let mutex = PThreadMutex() 62 | 63 | deinit { 64 | mutex.lock() 65 | observers.forEach { $0.cancel() } 66 | observers.removeAll() 67 | mutex.unlock() 68 | } 69 | 70 | /// Initialize 71 | public init() {} 72 | 73 | func add(_ observer: Observer) { 74 | mutex.lock() 75 | observers.append(observer) 76 | mutex.unlock() 77 | } 78 | } 79 | } 80 | 81 | extension NotificationCenterContinuum { 82 | public func post(keyPath: KeyPath) { 83 | center.post(name: keyPath.notificationName, object: nil) 84 | } 85 | } 86 | 87 | extension NotificationCenterContinuum { 88 | /// Binds property of source object to property of target object. 89 | /// 90 | /// - parameter source: Observed object. 91 | /// - parameter keyPath1: KeyPath for source. 92 | /// - parameter queue: Binding execution qeueue. 93 | /// - parameter target: Binding target. 94 | /// - parameter keyPath2: KeyPath for target. 95 | /// - returns: Observer that observes a object. 96 | public func observe(_ source: S, 97 | _ keyPath1: KeyPath, 98 | on queue: OperationQueue? = nil, 99 | bindTo target: T, 100 | _ keyPath2: ReferenceWritableKeyPath) -> Observer { 101 | return _observe(source, keyPath1, on: queue, bindTo: target, keyPath2) 102 | } 103 | 104 | /// Binds property of source object to property of target object. 105 | /// 106 | /// - parameter source: Observed object. 107 | /// - parameter keyPath1: KeyPath for source. 108 | /// - parameter queue: Binding execution qeueue. 109 | /// - parameter target: Binding target. 110 | /// - parameter keyPath2: KeyPath for target that comfirms Wrappable. 111 | /// - returns: Observer that observes a object. 112 | public func observe(_ source: S, 113 | _ keyPath1: KeyPath, 114 | on queue: OperationQueue? = nil, 115 | bindTo target: T, 116 | _ keyPath2: ReferenceWritableKeyPath) -> Observer where V1 == V2.Wrapped { 117 | return _observe(source, keyPath1, on: queue, bindTo: target, keyPath2) 118 | } 119 | 120 | /// Binds source.value to property of target object. 121 | /// 122 | /// - parameter source: Observed object. 123 | /// - parameter keyPath1: KeyPath for source that confirms Wrappable. 124 | /// - parameter queue: Binding execution qeueue. 125 | /// - parameter target: Binding target. 126 | /// - parameter keyPath2: KeyPath for target. 127 | /// - returns: Observer that observes a object. 128 | public func observe(_ source: S, 129 | _ keyPath1: KeyPath, 130 | on queue: OperationQueue? = nil, 131 | bindTo target: T, 132 | _ keyPath2: ReferenceWritableKeyPath) -> Observer where V1.Wrapped == V2 { 133 | return _observe(source, keyPath1, on: queue, bindTo: target, keyPath2) 134 | } 135 | 136 | /// Binds source.value to property of target object. 137 | /// 138 | /// - parameter source: Observed object. 139 | /// - parameter keyPath1: KeyPath for source that confirms Wrappable. 140 | /// - parameter queue: Binding execution qeueue. 141 | /// - parameter target: Binding target. 142 | /// - parameter keyPath2: KeyPath for target that confirms Wrappable. 143 | /// - returns: Observer that observes a object. 144 | public func observe(_ source: S, 145 | _ keyPath1: KeyPath, 146 | on queue: OperationQueue? = nil, 147 | bindTo target: T, 148 | _ keyPath2: ReferenceWritableKeyPath) -> Observer where V1.Wrapped == V2.Wrapped { 149 | return _observe(source, keyPath1, on: queue, bindTo: target, keyPath2) 150 | } 151 | 152 | /// Binds source.value to property of target object. 153 | /// 154 | /// - parameter source: Observed object. 155 | /// - parameter keyPath1: KeyPath for source that confirms Wrappable. 156 | /// - parameter queue: Binding execution qeueue. 157 | /// - parameter target: Binding target. 158 | /// - parameter keyPath2: KeyPath for target that is Optional. 159 | /// - returns: Observer that observes a object. 160 | public func observe(_ source: S, 161 | _ sourceKeyPath: KeyPath, 162 | on queue: OperationQueue? = nil, 163 | bindTo target: T, 164 | _ targetKeyPath: ReferenceWritableKeyPath>) -> Observer { 165 | let handler: () -> () = { [weak source, weak target] in 166 | guard let source = source, let target = target else { return } 167 | target[keyPath: targetKeyPath] = source[keyPath: sourceKeyPath] as? V2 168 | } 169 | 170 | OperationQueue.addOrExecuteOperation(handler, in: queue) 171 | let observer = center.addObserver(forName: sourceKeyPath.notificationName, object: nil, queue: queue) { _ in handler() } 172 | return Observer(rawObserver: observer, center: center) 173 | } 174 | 175 | /// Binds source.value to property of target object. 176 | /// 177 | /// - parameter source: Observed object that value confirms Wrappable. 178 | /// - parameter queue: Binding execution qeueue. 179 | /// - parameter target: Binding target. 180 | /// - parameter keyPath: KeyPath for target that is ImplicitlyUnwrappedOptional. 181 | /// - returns: Observer that observes a ValueRepresentable. 182 | public func observe(_ source: S, 183 | _ sourceKeyPath: KeyPath, 184 | on queue: OperationQueue? = nil, 185 | bindTo target: T, 186 | _ targetKeyPath: ReferenceWritableKeyPath>) -> Observer { 187 | let handler: () -> () = { [weak source, weak target] in 188 | guard let source = source, let target = target else { return } 189 | target[keyPath: targetKeyPath] = source[keyPath: sourceKeyPath] as? V2 190 | } 191 | 192 | OperationQueue.addOrExecuteOperation(handler, in: queue) 193 | let observer = center.addObserver(forName: sourceKeyPath.notificationName, object: nil, queue: queue) { _ in handler() } 194 | return Observer(rawObserver: observer, center: center) 195 | } 196 | 197 | private func _observe(_ source: S, 198 | _ sourceKeyPath: KeyPath, 199 | on queue: OperationQueue? = nil, 200 | bindTo target: T, 201 | _ targetKeyPath: ReferenceWritableKeyPath) -> Observer { 202 | let handler: () -> () = { [weak source, weak target] in 203 | guard 204 | let source = source, 205 | let target = target, 206 | let value = source[keyPath: sourceKeyPath] as? V2 207 | else { return } 208 | target[keyPath: targetKeyPath] = value 209 | } 210 | 211 | OperationQueue.addOrExecuteOperation(handler, in: queue) 212 | let observer = center.addObserver(forName: sourceKeyPath.notificationName, object: nil, queue: queue) { _ in handler() } 213 | return Observer(rawObserver: observer, center: center) 214 | } 215 | } 216 | 217 | extension NotificationCenterContinuum { 218 | /// Binds source.value to property of target object. 219 | /// 220 | /// - parameter source: Observed object. 221 | /// - parameter queue: Binding execution qeueue. 222 | /// - parameter target: Binding target. 223 | /// - parameter keyPath: KeyPath for target. 224 | /// - returns: Observer that observes a object that confirms ValueRepresentable. 225 | public func observe(_ source: S, 226 | on queue: OperationQueue? = nil, 227 | bindTo target: T, 228 | _ keyPath: ReferenceWritableKeyPath) -> Observer where S.E == V { 229 | return _observe(source, on: queue, bindTo: target, keyPath) 230 | } 231 | 232 | /// Binds source.value to property of target object. 233 | /// 234 | /// - parameter source: Observed object. 235 | /// - parameter queue: Binding execution qeueue. 236 | /// - parameter target: Binding target. 237 | /// - parameter keyPath: KeyPath for target that confirms Wrappable. 238 | /// - returns: Observer that observes a ValueRepresentable. 239 | public func observe(_ source: S, 240 | on queue: OperationQueue? = nil, 241 | bindTo target: T, 242 | _ keyPath: ReferenceWritableKeyPath) -> Observer where S.E == V.Wrapped { 243 | return _observe(source, on: queue, bindTo: target, keyPath) 244 | } 245 | 246 | /// Binds source.value to property of target object. 247 | /// 248 | /// - parameter source: Observed object that value confirms Wrappable. 249 | /// - parameter queue: Binding execution qeueue. 250 | /// - parameter target: Binding target. 251 | /// - parameter keyPath: KeyPath for target that confirms Wrappable. 252 | /// - returns: Observer that observes a ValueRepresentable. 253 | public func observe(_ source: S, 254 | on queue: OperationQueue? = nil, 255 | bindTo target: T, 256 | _ keyPath: ReferenceWritableKeyPath) -> Observer where S.E: Wrappable, S.E.Wrapped == V { 257 | return _observe(source, on: queue, bindTo: target, keyPath) 258 | } 259 | 260 | /// Binds source.value to property of target object. 261 | /// 262 | /// - parameter source: Observed object that value confirms Wrappable. 263 | /// - parameter queue: Binding execution qeueue. 264 | /// - parameter target: Binding target. 265 | /// - parameter keyPath: KeyPath for target that is Optional. 266 | /// - returns: Observer that observes a ValueRepresentable. 267 | public func observe(_ source: S, 268 | on queue: OperationQueue? = nil, 269 | bindTo target: T, 270 | _ keyPath: ReferenceWritableKeyPath>) -> Observer where S.E: Wrappable, S.E.Wrapped == V { 271 | let handler: () -> () = { [weak source, weak target] in 272 | guard let target = target, let source = source else { return } 273 | target[keyPath: keyPath] = source.value as? V 274 | } 275 | 276 | OperationQueue.addOrExecuteOperation(handler, in: queue) 277 | (source as? NotificationCenterSettable)?.setCenter(center) 278 | let observer = center.addObserver(forName: source.uniqueName, object: nil, queue: queue) { _ in handler() } 279 | return Observer(rawObserver: observer, center: center) 280 | } 281 | 282 | /// Binds source.value to property of target object. 283 | /// 284 | /// - parameter source: Observed object that value confirms Wrappable. 285 | /// - parameter queue: Binding execution qeueue. 286 | /// - parameter target: Binding target. 287 | /// - parameter keyPath: KeyPath for target that confirms Wrappable. 288 | /// - returns: Observer that observes a ValueRepresentable. 289 | public func observe(_ source: S, 290 | on queue: OperationQueue? = nil, 291 | bindTo target: T, 292 | _ keyPath: ReferenceWritableKeyPath>) -> Observer where S.E: Wrappable, S.E.Wrapped == V { 293 | let handler: () -> () = { [weak source, weak target] in 294 | guard let target = target, let source = source else { return } 295 | target[keyPath: keyPath] = source.value as? V 296 | } 297 | 298 | OperationQueue.addOrExecuteOperation(handler, in: queue) 299 | (source as? NotificationCenterSettable)?.setCenter(center) 300 | let observer = center.addObserver(forName: source.uniqueName, object: nil, queue: queue) { _ in handler() } 301 | return Observer(rawObserver: observer, center: center) 302 | } 303 | 304 | private func _observe(_ source: S, 305 | on queue: OperationQueue? = nil, 306 | bindTo target: T, 307 | _ keyPath: ReferenceWritableKeyPath) -> Observer { 308 | let handler: () -> () = { [weak source, weak target] in 309 | guard 310 | let target = target, 311 | let value = source?.value as? V 312 | else { return } 313 | target[keyPath: keyPath] = value 314 | } 315 | 316 | OperationQueue.addOrExecuteOperation(handler, in: queue) 317 | (source as? NotificationCenterSettable)?.setCenter(center) 318 | let observer = center.addObserver(forName: source.uniqueName, object: nil, queue: queue) { _ in handler() } 319 | return Observer(rawObserver: observer, center: center) 320 | } 321 | } 322 | 323 | extension NotificationCenterContinuum { 324 | /// Binds source.value to property of target object. 325 | /// 326 | /// - parameter source: Observed object. 327 | /// - parameter queue: Binding execution qeueue. 328 | /// - parameter onValueChange: Value handler. 329 | /// - returns: Observer that observes a object that confirms ValueRepresentable. 330 | public func observe(_ source: S, 331 | on queue: OperationQueue? = nil, 332 | onValueChange: @escaping (V) -> ()) -> Observer where S.E == V { 333 | return _observe(source, on: queue, onValueChange: onValueChange) 334 | } 335 | 336 | private func _observe(_ source: S, 337 | on queue: OperationQueue? = nil, 338 | onValueChange: @escaping (V) -> ()) -> Observer where S.E == V { 339 | let handler: () -> () = { [weak source] in 340 | guard let source = source else { return } 341 | onValueChange(source.value) 342 | } 343 | 344 | OperationQueue.addOrExecuteOperation(handler, in: queue) 345 | (source as? NotificationCenterSettable)?.setCenter(center) 346 | let observer = center.addObserver(forName: source.uniqueName, object: nil, queue: queue) { _ in handler() } 347 | return Observer(rawObserver: observer, center: center) 348 | } 349 | } 350 | 351 | extension OperationQueue { 352 | fileprivate static func addOrExecuteOperation(_ operation: @escaping () -> Void, in queue: OperationQueue?) { 353 | if let _queue = queue, current != _queue { 354 | // only dispatch async if given queue is different from current 355 | _queue.addOperation(operation) 356 | } else { 357 | operation() 358 | } 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /Continuum/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Continuum/Internal/AnyKeyPath.extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyKeyPath.extension.swift 3 | // Continuum 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension AnyKeyPath { 12 | var notificationName: Notification.Name { 13 | let string = "\(type(of: self).rootType)-\(type(of: self).valueType)-\(hashValue)" 14 | return Notification.Name(string) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Continuum/Internal/PThreadMutex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PThreadMutex.swift 3 | // Continuum 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// A pthread_mutex wrapper 12 | final class PThreadMutex { 13 | private let mutex = UnsafeMutablePointer.allocate(capacity: 1) 14 | 15 | init() { 16 | pthread_mutex_init(mutex, nil) 17 | } 18 | 19 | deinit { 20 | pthread_mutex_destroy(mutex) 21 | mutex.deinitialize() 22 | mutex.deallocate(capacity: 1) 23 | } 24 | 25 | func lock() { 26 | pthread_mutex_lock(mutex) 27 | } 28 | 29 | func unlock() { 30 | pthread_mutex_unlock(mutex) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Continuum/Variable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Variable.swift 3 | // Continuum 4 | // 5 | // Created by 鈴木大貴 on 2018/02/08. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ValueRepresentable: class { 12 | associatedtype E 13 | var value: E { get } 14 | var uniqueName: Notification.Name { get } 15 | } 16 | 17 | protocol NotificationCenterSettable: class { 18 | func setCenter(_ center: NotificationCenter) 19 | } 20 | 21 | /// Variable is wrapper for value that has getter / setter. 22 | public final class Variable: ValueRepresentable, NotificationCenterSettable { 23 | /// Gets or sets current value of variable. 24 | /// 25 | /// Whenever a new value is set, all the observers are notified of the change. 26 | public var value: Element { 27 | set { 28 | mutex.lock() 29 | _value = newValue 30 | mutex.unlock() 31 | center?.post(name: uniqueName, object: nil) 32 | } 33 | get { 34 | defer { mutex.unlock() }; mutex.lock() 35 | return _value 36 | } 37 | } 38 | 39 | /// Represents unique Notification.Name for each Variables. 40 | public let uniqueName = Notification.Name("Continuum.\(UUID().uuidString)") 41 | 42 | private var _value: Element 43 | private let mutex = PThreadMutex() 44 | private var center: NotificationCenter? 45 | 46 | /// Initializes Variable with initial value. 47 | /// 48 | /// - parameter value: Initial value. 49 | public init(value: Element) { 50 | self._value = value 51 | } 52 | 53 | func setCenter(_ center: NotificationCenter) { 54 | self.center = center 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Continuum/Wrappable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Wrappable.swift 3 | // Continuum 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Represents Optional. 12 | public protocol Wrappable { 13 | associatedtype Wrapped 14 | var value: Wrapped? { get } 15 | } 16 | 17 | extension Optional: Wrappable { 18 | public var value: Wrapped? { 19 | return self 20 | } 21 | } 22 | 23 | extension ImplicitlyUnwrappedOptional: Wrappable { 24 | public var value: Wrapped? { 25 | return self 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ContinuumTests/ConstantTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConstantTests.swift 3 | // ContinuumTests 4 | // 5 | // Created by marty-suzuki on 2018/02/08. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Continuum 11 | 12 | final class ConstantTests: XCTestCase { 13 | 14 | func testBindingWhenConstantToSameValueType() { 15 | class Cat { 16 | var sound = "Meow" 17 | } 18 | 19 | let _barkOfDog = Variable(value: "Bow wow") 20 | let barkOfDog = Constant(variable: _barkOfDog) 21 | let cat = Cat() 22 | 23 | XCTAssertEqual(cat.sound, "Meow") 24 | 25 | let center = NotificationCenter() 26 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 27 | 28 | XCTAssertEqual(cat.sound, "Bow wow") 29 | 30 | _barkOfDog.value = "Meow" 31 | 32 | XCTAssertEqual(cat.sound, "Meow") 33 | } 34 | 35 | func testBindingWhenConstantIsOptional() { 36 | class Cat { 37 | var sound = "Meow" 38 | } 39 | 40 | let _barkOfDog = Variable(value: "Bow wow") 41 | let barkOfDog = Constant(variable: _barkOfDog) 42 | let cat = Cat() 43 | 44 | XCTAssertEqual(cat.sound, "Meow") 45 | 46 | let center = NotificationCenter() 47 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 48 | 49 | XCTAssertEqual(cat.sound, "Bow wow") 50 | 51 | _barkOfDog.value = "Meow" 52 | 53 | XCTAssertEqual(cat.sound, "Meow") 54 | } 55 | 56 | func testBindingWhenConstantIsNotOPtionalAndRightValueTypeIsOptional() { 57 | class Cat { 58 | var sound: String? = "Meow" 59 | } 60 | 61 | let _barkOfDog = Variable(value: "Bow wow") 62 | let barkOfDog = Constant(variable: _barkOfDog) 63 | let cat = Cat() 64 | 65 | XCTAssertEqual(cat.sound, "Meow") 66 | 67 | let center = NotificationCenter() 68 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 69 | 70 | XCTAssertEqual(cat.sound, "Bow wow") 71 | 72 | _barkOfDog.value = "Meow" 73 | 74 | XCTAssertEqual(cat.sound, "Meow") 75 | } 76 | 77 | func testBindingWhenConstantIsOptionalRightValueTypeIsIuoFinallyNil() { 78 | class Cat { 79 | var sound: String! = "Meow" 80 | } 81 | 82 | let _barkOfDog = Variable(value: "Bow wow") 83 | let barkOfDog = Constant(variable: _barkOfDog) 84 | let cat = Cat() 85 | 86 | XCTAssertEqual(cat.sound, "Meow") 87 | 88 | let center = NotificationCenter() 89 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 90 | 91 | XCTAssertEqual(cat.sound, "Bow wow") 92 | 93 | _barkOfDog.value = nil 94 | 95 | XCTAssertNil(cat.sound) 96 | } 97 | 98 | func testBindingWhenConstantIsIuolRightValueTypeIsOptionalFinallyNil() { 99 | class Cat { 100 | var sound: String? = "Meow" 101 | } 102 | 103 | let _barkOfDog = Variable(value: "Bow wow") 104 | let barkOfDog = Constant(variable: _barkOfDog) 105 | let cat = Cat() 106 | 107 | XCTAssertEqual(cat.sound, "Meow") 108 | 109 | let center = NotificationCenter() 110 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 111 | 112 | XCTAssertEqual(cat.sound, "Bow wow") 113 | 114 | _barkOfDog.value = nil 115 | 116 | XCTAssertNil(cat.sound) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /ContinuumTests/ContinuumTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContinuumTests.swift 3 | // ContinuumTests 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Continuum 11 | 12 | final class ContinuumTests: XCTestCase { 13 | 14 | func testBindingWhenSameValueType() { 15 | class Dog { 16 | var bark = "Bow wow" 17 | } 18 | 19 | class Cat { 20 | var sound = "Meow" 21 | } 22 | 23 | let dog = Dog() 24 | let cat = Cat() 25 | 26 | XCTAssertEqual(cat.sound, "Meow") 27 | 28 | let center = NotificationCenter() 29 | _ = center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 30 | 31 | XCTAssertEqual(cat.sound, "Bow wow") 32 | 33 | dog.bark = "Meow" 34 | center.continuum.post(keyPath: \Dog.bark) 35 | 36 | XCTAssertEqual(cat.sound, "Meow") 37 | } 38 | 39 | func testBindingWhenLeftValueTypeIsOptional() { 40 | class Dog { 41 | var bark: String? = "Bow wow" 42 | } 43 | 44 | class Cat { 45 | var sound = "Meow" 46 | } 47 | 48 | let dog = Dog() 49 | let cat = Cat() 50 | 51 | XCTAssertEqual(cat.sound, "Meow") 52 | 53 | let center = NotificationCenter() 54 | _ = center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 55 | 56 | XCTAssertEqual(cat.sound, "Bow wow") 57 | 58 | dog.bark = "Meow" 59 | center.continuum.post(keyPath: \Dog.bark) 60 | 61 | XCTAssertEqual(cat.sound, "Meow") 62 | } 63 | 64 | func testBindingWhenRightValueTypeIsOptional() { 65 | class Dog { 66 | var bark = "Bow wow" 67 | } 68 | 69 | class Cat { 70 | var sound: String? = "Meow" 71 | } 72 | 73 | let dog = Dog() 74 | let cat = Cat() 75 | 76 | XCTAssertEqual(cat.sound, "Meow") 77 | 78 | let center = NotificationCenter() 79 | _ = center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 80 | 81 | XCTAssertEqual(cat.sound, "Bow wow") 82 | 83 | dog.bark = "Meow" 84 | center.continuum.post(keyPath: \Dog.bark) 85 | 86 | XCTAssertEqual(cat.sound, "Meow") 87 | } 88 | 89 | func testBindingWhenLeftValueTypeIsImplicitlyUnwrappedOptional() { 90 | class Dog { 91 | var bark: String! = "Bow wow" 92 | } 93 | 94 | class Cat { 95 | var sound = "Meow" 96 | } 97 | 98 | let dog = Dog() 99 | let cat = Cat() 100 | 101 | XCTAssertEqual(cat.sound, "Meow") 102 | 103 | let center = NotificationCenter() 104 | _ = center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 105 | 106 | XCTAssertEqual(cat.sound, "Bow wow") 107 | 108 | dog.bark = "Meow" 109 | center.continuum.post(keyPath: \Dog.bark) 110 | 111 | XCTAssertEqual(cat.sound, "Meow") 112 | } 113 | 114 | func testBindingWhenRightValueTypeIsImplicitlyUnwrappedOptional() { 115 | class Dog { 116 | var bark = "Bow wow" 117 | } 118 | 119 | class Cat { 120 | var sound: String! = "Meow" 121 | } 122 | 123 | let dog = Dog() 124 | let cat = Cat() 125 | 126 | XCTAssertEqual(cat.sound, "Meow") 127 | 128 | let center = NotificationCenter() 129 | _ = center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 130 | 131 | XCTAssertEqual(cat.sound, "Bow wow") 132 | 133 | dog.bark = "Meow" 134 | center.continuum.post(keyPath: \Dog.bark) 135 | 136 | XCTAssertEqual(cat.sound, "Meow") 137 | } 138 | 139 | func testCancelObserving() { 140 | class Dog { 141 | var bark = "Bow wow" 142 | } 143 | 144 | class Cat { 145 | var sound = "Meow" 146 | } 147 | 148 | let dog = Dog() 149 | let cat = Cat() 150 | 151 | XCTAssertEqual(cat.sound, "Meow") 152 | 153 | let center = NotificationCenter() 154 | let observer = center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 155 | 156 | XCTAssertEqual(cat.sound, "Bow wow") 157 | 158 | dog.bark = "Meow" 159 | center.continuum.post(keyPath: \Dog.bark) 160 | 161 | XCTAssertEqual(cat.sound, "Meow") 162 | 163 | observer.cancel() 164 | 165 | dog.bark = "Woof Woof" 166 | center.continuum.post(keyPath: \Dog.bark) 167 | 168 | XCTAssertEqual(cat.sound, "Meow") 169 | } 170 | 171 | func testCancelObservingByDeinit() { 172 | class Dog { 173 | var bark = "Bow wow" 174 | } 175 | 176 | class Cat { 177 | var sound = "Meow" 178 | } 179 | 180 | let dog = Dog() 181 | let cat = Cat() 182 | 183 | XCTAssertEqual(cat.sound, "Meow") 184 | 185 | let center = NotificationCenter() 186 | var bag = ContinuumBag() 187 | center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 188 | .disposed(by: bag) 189 | center.continuum.post(keyPath: \Dog.bark) 190 | 191 | XCTAssertEqual(cat.sound, "Bow wow") 192 | 193 | dog.bark = "Meow" 194 | center.continuum.post(keyPath: \Dog.bark) 195 | 196 | XCTAssertEqual(cat.sound, "Meow") 197 | 198 | bag = ContinuumBag() 199 | 200 | dog.bark = "Woof Woof" 201 | center.continuum.post(keyPath: \Dog.bark) 202 | 203 | XCTAssertEqual(cat.sound, "Meow") 204 | } 205 | 206 | func testMultipleBinding() { 207 | class Dog { 208 | var bark = "Bow wow" 209 | } 210 | 211 | class Cat { 212 | var sound = "Meow" 213 | } 214 | 215 | class Sheep { 216 | var sound = "Baa Baa" 217 | } 218 | 219 | let dog = Dog() 220 | let cat = Cat() 221 | let sheep = Sheep() 222 | 223 | XCTAssertEqual(cat.sound, "Meow") 224 | XCTAssertEqual(sheep.sound, "Baa Baa") 225 | 226 | let center = NotificationCenter() 227 | _ = center.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 228 | _ = center.continuum.observe(dog, \.bark, bindTo: sheep, \.sound) 229 | 230 | XCTAssertEqual(cat.sound, "Bow wow") 231 | XCTAssertEqual(sheep.sound, "Bow wow") 232 | 233 | dog.bark = "Meow" 234 | center.continuum.post(keyPath: \Dog.bark) 235 | 236 | XCTAssertEqual(cat.sound, "Meow") 237 | XCTAssertEqual(sheep.sound, "Meow") 238 | } 239 | 240 | func testMultipleNotificationCenter() { 241 | class Dog { 242 | var bark = "Bow wow" 243 | } 244 | 245 | class Cat { 246 | var sound = "Meow" 247 | } 248 | 249 | class Sheep { 250 | var sound = "Baa Baa" 251 | } 252 | 253 | let dog = Dog() 254 | let cat = Cat() 255 | let sheep = Sheep() 256 | 257 | XCTAssertEqual(cat.sound, "Meow") 258 | XCTAssertEqual(sheep.sound, "Baa Baa") 259 | 260 | let center1 = NotificationCenter() 261 | let center2 = NotificationCenter() 262 | _ = center1.continuum.observe(dog, \.bark, bindTo: cat, \.sound) 263 | _ = center2.continuum.observe(dog, \.bark, bindTo: sheep, \.sound) 264 | 265 | XCTAssertEqual(cat.sound, "Bow wow") 266 | XCTAssertEqual(sheep.sound, "Bow wow") 267 | 268 | dog.bark = "Woof Woof" 269 | 270 | center1.continuum.post(keyPath: \Dog.bark) 271 | 272 | XCTAssertEqual(cat.sound, "Woof Woof") 273 | XCTAssertEqual(sheep.sound, "Bow wow") 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /ContinuumTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ContinuumTests/OnValueChangeClosureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OnValueChangeClosureTests.swift 3 | // ContinuumTests 4 | // 5 | // Created by Toshihiro Suzuki on 2018/02/25. 6 | // Copyright © 2018 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Continuum 11 | 12 | final class OnValueChangeClosureTests: XCTestCase { 13 | private class Cat { 14 | var sound = "Meow" 15 | } 16 | 17 | private var _barkOfDog: Variable! 18 | private var barkOfDog: Constant! 19 | private var cat: Cat! 20 | 21 | override func setUp() { 22 | super.setUp() 23 | 24 | _barkOfDog = Variable(value: "Bow wow") 25 | barkOfDog = Constant(variable: _barkOfDog) 26 | cat = Cat() 27 | } 28 | 29 | func testBindingWithNoQueue() { 30 | 31 | XCTAssertEqual(cat.sound, "Meow") 32 | 33 | let center = NotificationCenter() 34 | _ = center.continuum.observe(barkOfDog, onValueChange: { [unowned self] barkOfDog in 35 | XCTAssertTrue(Thread.isMainThread) 36 | self.cat.sound = barkOfDog 37 | }) 38 | 39 | // NOTE: No need to setup XCTestExpectation. 40 | // Continuum is on main thread all the time in this case. 41 | 42 | XCTAssertEqual(cat.sound, "Bow wow") 43 | 44 | _barkOfDog.value = "Meow" 45 | 46 | XCTAssertEqual(cat.sound, "Meow") 47 | } 48 | 49 | func testBindingWithMainQueue() { 50 | 51 | XCTAssertEqual(cat.sound, "Meow") 52 | 53 | let center = NotificationCenter() 54 | _ = center.continuum.observe(barkOfDog, on: .main, onValueChange: { [unowned self] barkOfDog in 55 | XCTAssertTrue(Thread.isMainThread) 56 | self.cat.sound = barkOfDog 57 | }) 58 | 59 | // NOTE: No need to setup XCTestExpectation. 60 | // Continuum is on main thread all the time in this case, too. 61 | // Because given queue `.main` is same as the current queue. 62 | 63 | XCTAssertEqual(cat.sound, "Bow wow") 64 | 65 | _barkOfDog.value = "Meow" 66 | 67 | XCTAssertEqual(cat.sound, "Meow") 68 | } 69 | 70 | func testBindingWithBackgroundQueue() { 71 | 72 | XCTAssertEqual(cat.sound, "Meow") 73 | 74 | let backgroundQueue = OperationQueue() 75 | 76 | // NOTE: We need to setup XCTestExpectation. 77 | // Continuum dispatches onValueChanges handler call on given queue. 78 | let ex1 = expectation(description: "first expectation") 79 | let ex2 = expectation(description: "second expectation") 80 | var exs = [ex1, ex2] 81 | 82 | let center = NotificationCenter() 83 | _ = center.continuum.observe(barkOfDog, on: backgroundQueue, onValueChange: { [unowned self] barkOfDog in 84 | 85 | // Pretend as an expensive logic. 86 | usleep(200 * 1000) // 0.2 sec 87 | 88 | self.cat.sound = barkOfDog 89 | XCTAssertFalse(Thread.isMainThread) 90 | exs.removeFirst().fulfill() 91 | }) 92 | 93 | wait(for: [ex1], timeout: 0.3) 94 | 95 | XCTAssertEqual(cat.sound, "Bow wow") 96 | 97 | _barkOfDog.value = "Meow" 98 | 99 | wait(for: [ex2], timeout: 0.3) 100 | 101 | XCTAssertEqual(cat.sound, "Meow") 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ContinuumTests/VariableTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VariableTests.swift 3 | // ContinuumTests 4 | // 5 | // Created by marty-suzuki on 2018/02/08. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Continuum 11 | 12 | final class VariableTests: XCTestCase { 13 | 14 | func testBindingWhenVariableToSameValueType() { 15 | class Cat { 16 | var sound = "Meow" 17 | } 18 | 19 | let barkOfDog = Variable(value: "Bow wow") 20 | let cat = Cat() 21 | 22 | XCTAssertEqual(cat.sound, "Meow") 23 | 24 | let center = NotificationCenter() 25 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 26 | 27 | XCTAssertEqual(cat.sound, "Bow wow") 28 | 29 | barkOfDog.value = "Meow" 30 | 31 | XCTAssertEqual(cat.sound, "Meow") 32 | } 33 | 34 | func testBindingWhenVariableIsOptional() { 35 | class Cat { 36 | var sound = "Meow" 37 | } 38 | 39 | let barkOfDog = Variable(value: "Bow wow") 40 | let cat = Cat() 41 | 42 | XCTAssertEqual(cat.sound, "Meow") 43 | 44 | let center = NotificationCenter() 45 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 46 | 47 | XCTAssertEqual(cat.sound, "Bow wow") 48 | 49 | barkOfDog.value = "Meow" 50 | 51 | XCTAssertEqual(cat.sound, "Meow") 52 | } 53 | 54 | func testBindingWhenVariableIsNotOPtionalAndRightValueTypeIsOptional() { 55 | class Cat { 56 | var sound: String? = "Meow" 57 | } 58 | 59 | let barkOfDog = Variable(value: "Bow wow") 60 | let cat = Cat() 61 | 62 | XCTAssertEqual(cat.sound, "Meow") 63 | 64 | let center = NotificationCenter() 65 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 66 | 67 | XCTAssertEqual(cat.sound, "Bow wow") 68 | 69 | barkOfDog.value = "Meow" 70 | 71 | XCTAssertEqual(cat.sound, "Meow") 72 | } 73 | 74 | func testBindingWhenVariableIsImplicitlyUnwrappedOptional() { 75 | class Cat { 76 | var sound = "Meow" 77 | } 78 | 79 | let barkOfDog = Variable(value: "Bow wow") 80 | let cat = Cat() 81 | 82 | XCTAssertEqual(cat.sound, "Meow") 83 | 84 | let center = NotificationCenter() 85 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 86 | 87 | XCTAssertEqual(cat.sound, "Bow wow") 88 | 89 | barkOfDog.value = "Meow" 90 | 91 | XCTAssertEqual(cat.sound, "Meow") 92 | } 93 | 94 | func testBindingWhenVariableIsNotIuoRightValueTypeIsIuo() { 95 | class Cat { 96 | var sound: String! = "Meow" 97 | } 98 | 99 | let barkOfDog = Variable(value: "Bow wow") 100 | let cat = Cat() 101 | 102 | XCTAssertEqual(cat.sound, "Meow") 103 | 104 | let center = NotificationCenter() 105 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 106 | 107 | XCTAssertEqual(cat.sound, "Bow wow") 108 | 109 | barkOfDog.value = "Meow" 110 | 111 | XCTAssertEqual(cat.sound, "Meow") 112 | } 113 | 114 | func testBindingWhenVariableIsOptionalRightValueTypeIsIuo() { 115 | class Cat { 116 | var sound: String! = "Meow" 117 | } 118 | 119 | let barkOfDog = Variable(value: "Bow wow") 120 | let cat = Cat() 121 | 122 | XCTAssertEqual(cat.sound, "Meow") 123 | 124 | let center = NotificationCenter() 125 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 126 | 127 | XCTAssertEqual(cat.sound, "Bow wow") 128 | 129 | barkOfDog.value = "Meow" 130 | 131 | XCTAssertEqual(cat.sound, "Meow") 132 | } 133 | 134 | func testBindingWhenVariableIsIuolRightValueTypeIsOptional() { 135 | class Cat { 136 | var sound: String? = "Meow" 137 | } 138 | 139 | let barkOfDog = Variable(value: "Bow wow") 140 | let cat = Cat() 141 | 142 | XCTAssertEqual(cat.sound, "Meow") 143 | 144 | let center = NotificationCenter() 145 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 146 | 147 | XCTAssertEqual(cat.sound, "Bow wow") 148 | 149 | barkOfDog.value = "Meow" 150 | 151 | XCTAssertEqual(cat.sound, "Meow") 152 | } 153 | 154 | func testBindingWhenVariableIsOptionalRightValueTypeIsIuoFinallyNil() { 155 | class Cat { 156 | var sound: String! = "Meow" 157 | } 158 | 159 | let barkOfDog = Variable(value: "Bow wow") 160 | let cat = Cat() 161 | 162 | XCTAssertEqual(cat.sound, "Meow") 163 | 164 | let center = NotificationCenter() 165 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 166 | 167 | XCTAssertEqual(cat.sound, "Bow wow") 168 | 169 | barkOfDog.value = nil 170 | 171 | XCTAssertNil(cat.sound) 172 | } 173 | 174 | func testBindingWhenVariableIsIuolRightValueTypeIsOptionalFinallyNil() { 175 | class Cat { 176 | var sound: String? = "Meow" 177 | } 178 | 179 | let barkOfDog = Variable(value: "Bow wow") 180 | let cat = Cat() 181 | 182 | XCTAssertEqual(cat.sound, "Meow") 183 | 184 | let center = NotificationCenter() 185 | _ = center.continuum.observe(barkOfDog, bindTo: cat, \.sound) 186 | 187 | XCTAssertEqual(cat.sound, "Bow wow") 188 | 189 | barkOfDog.value = nil 190 | 191 | XCTAssertNil(cat.sound) 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /Example/ContinuumSample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3700DEEE202A1B690010408B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700DEED202A1B690010408B /* AppDelegate.swift */; }; 11 | 3700DEF0202A1B690010408B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3700DEEF202A1B690010408B /* ViewController.swift */; }; 12 | 3700DEF3202A1B690010408B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3700DEF1202A1B690010408B /* Main.storyboard */; }; 13 | 3700DEF5202A1B690010408B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3700DEF4202A1B690010408B /* Assets.xcassets */; }; 14 | 3700DEF8202A1B690010408B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3700DEF6202A1B690010408B /* LaunchScreen.storyboard */; }; 15 | 7A68D6858E740794887EAE76 /* Pods_ContinuumSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D790DBFAB019D834272CC9A /* Pods_ContinuumSample.framework */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 3700DEEA202A1B690010408B /* ContinuumSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ContinuumSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 3700DEED202A1B690010408B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | 3700DEEF202A1B690010408B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 22 | 3700DEF2202A1B690010408B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 23 | 3700DEF4202A1B690010408B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | 3700DEF7202A1B690010408B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 25 | 3700DEF9202A1B690010408B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | 7D790DBFAB019D834272CC9A /* Pods_ContinuumSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ContinuumSample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 89766802E0978ADFA9D1162F /* Pods-ContinuumSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContinuumSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample.debug.xcconfig"; sourceTree = ""; }; 28 | D77E8EFE48AE7DEB9223E883 /* Pods-ContinuumSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContinuumSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample.release.xcconfig"; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 3700DEE7202A1B690010408B /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | 7A68D6858E740794887EAE76 /* Pods_ContinuumSample.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 3700DEE1202A1B690010408B = { 44 | isa = PBXGroup; 45 | children = ( 46 | 3700DEEC202A1B690010408B /* ContinuumSample */, 47 | 3700DEEB202A1B690010408B /* Products */, 48 | 40775F7DFA4250250857AA6B /* Pods */, 49 | F26FD004F44C94FE58128834 /* Frameworks */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | 3700DEEB202A1B690010408B /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 3700DEEA202A1B690010408B /* ContinuumSample.app */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | 3700DEEC202A1B690010408B /* ContinuumSample */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 3700DEED202A1B690010408B /* AppDelegate.swift */, 65 | 3700DEEF202A1B690010408B /* ViewController.swift */, 66 | 3700DEF1202A1B690010408B /* Main.storyboard */, 67 | 3700DEF4202A1B690010408B /* Assets.xcassets */, 68 | 3700DEF6202A1B690010408B /* LaunchScreen.storyboard */, 69 | 3700DEF9202A1B690010408B /* Info.plist */, 70 | ); 71 | path = ContinuumSample; 72 | sourceTree = ""; 73 | }; 74 | 40775F7DFA4250250857AA6B /* Pods */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 89766802E0978ADFA9D1162F /* Pods-ContinuumSample.debug.xcconfig */, 78 | D77E8EFE48AE7DEB9223E883 /* Pods-ContinuumSample.release.xcconfig */, 79 | ); 80 | name = Pods; 81 | sourceTree = ""; 82 | }; 83 | F26FD004F44C94FE58128834 /* Frameworks */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 7D790DBFAB019D834272CC9A /* Pods_ContinuumSample.framework */, 87 | ); 88 | name = Frameworks; 89 | sourceTree = ""; 90 | }; 91 | /* End PBXGroup section */ 92 | 93 | /* Begin PBXNativeTarget section */ 94 | 3700DEE9202A1B690010408B /* ContinuumSample */ = { 95 | isa = PBXNativeTarget; 96 | buildConfigurationList = 3700DEFC202A1B690010408B /* Build configuration list for PBXNativeTarget "ContinuumSample" */; 97 | buildPhases = ( 98 | 19952AEC5DC9C125B68CB744 /* [CP] Check Pods Manifest.lock */, 99 | 3700DEE6202A1B690010408B /* Sources */, 100 | 3700DEE7202A1B690010408B /* Frameworks */, 101 | 3700DEE8202A1B690010408B /* Resources */, 102 | 5F8D13A94B7694248762A938 /* [CP] Embed Pods Frameworks */, 103 | 0E6764616709DAC64369286E /* [CP] Copy Pods Resources */, 104 | ); 105 | buildRules = ( 106 | ); 107 | dependencies = ( 108 | ); 109 | name = ContinuumSample; 110 | productName = ContinuumSample; 111 | productReference = 3700DEEA202A1B690010408B /* ContinuumSample.app */; 112 | productType = "com.apple.product-type.application"; 113 | }; 114 | /* End PBXNativeTarget section */ 115 | 116 | /* Begin PBXProject section */ 117 | 3700DEE2202A1B690010408B /* Project object */ = { 118 | isa = PBXProject; 119 | attributes = { 120 | LastSwiftUpdateCheck = 0920; 121 | LastUpgradeCheck = 0920; 122 | ORGANIZATIONNAME = "marty-suzuki"; 123 | TargetAttributes = { 124 | 3700DEE9202A1B690010408B = { 125 | CreatedOnToolsVersion = 9.2; 126 | ProvisioningStyle = Automatic; 127 | }; 128 | }; 129 | }; 130 | buildConfigurationList = 3700DEE5202A1B690010408B /* Build configuration list for PBXProject "ContinuumSample" */; 131 | compatibilityVersion = "Xcode 8.0"; 132 | developmentRegion = en; 133 | hasScannedForEncodings = 0; 134 | knownRegions = ( 135 | en, 136 | Base, 137 | ); 138 | mainGroup = 3700DEE1202A1B690010408B; 139 | productRefGroup = 3700DEEB202A1B690010408B /* Products */; 140 | projectDirPath = ""; 141 | projectRoot = ""; 142 | targets = ( 143 | 3700DEE9202A1B690010408B /* ContinuumSample */, 144 | ); 145 | }; 146 | /* End PBXProject section */ 147 | 148 | /* Begin PBXResourcesBuildPhase section */ 149 | 3700DEE8202A1B690010408B /* Resources */ = { 150 | isa = PBXResourcesBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | 3700DEF8202A1B690010408B /* LaunchScreen.storyboard in Resources */, 154 | 3700DEF5202A1B690010408B /* Assets.xcassets in Resources */, 155 | 3700DEF3202A1B690010408B /* Main.storyboard in Resources */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXResourcesBuildPhase section */ 160 | 161 | /* Begin PBXShellScriptBuildPhase section */ 162 | 0E6764616709DAC64369286E /* [CP] Copy Pods Resources */ = { 163 | isa = PBXShellScriptBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | ); 167 | inputPaths = ( 168 | ); 169 | name = "[CP] Copy Pods Resources"; 170 | outputPaths = ( 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | shellPath = /bin/sh; 174 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-resources.sh\"\n"; 175 | showEnvVarsInLog = 0; 176 | }; 177 | 19952AEC5DC9C125B68CB744 /* [CP] Check Pods Manifest.lock */ = { 178 | isa = PBXShellScriptBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | ); 182 | inputPaths = ( 183 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 184 | "${PODS_ROOT}/Manifest.lock", 185 | ); 186 | name = "[CP] Check Pods Manifest.lock"; 187 | outputPaths = ( 188 | "$(DERIVED_FILE_DIR)/Pods-ContinuumSample-checkManifestLockResult.txt", 189 | ); 190 | runOnlyForDeploymentPostprocessing = 0; 191 | shellPath = /bin/sh; 192 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/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# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 193 | showEnvVarsInLog = 0; 194 | }; 195 | 5F8D13A94B7694248762A938 /* [CP] Embed Pods Frameworks */ = { 196 | isa = PBXShellScriptBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | ); 200 | inputPaths = ( 201 | "${SRCROOT}/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-frameworks.sh", 202 | "${BUILT_PRODUCTS_DIR}/Continuum/Continuum.framework", 203 | ); 204 | name = "[CP] Embed Pods Frameworks"; 205 | outputPaths = ( 206 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Continuum.framework", 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | shellPath = /bin/sh; 210 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-frameworks.sh\"\n"; 211 | showEnvVarsInLog = 0; 212 | }; 213 | /* End PBXShellScriptBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | 3700DEE6202A1B690010408B /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 3700DEF0202A1B690010408B /* ViewController.swift in Sources */, 221 | 3700DEEE202A1B690010408B /* AppDelegate.swift in Sources */, 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | }; 225 | /* End PBXSourcesBuildPhase section */ 226 | 227 | /* Begin PBXVariantGroup section */ 228 | 3700DEF1202A1B690010408B /* Main.storyboard */ = { 229 | isa = PBXVariantGroup; 230 | children = ( 231 | 3700DEF2202A1B690010408B /* Base */, 232 | ); 233 | name = Main.storyboard; 234 | sourceTree = ""; 235 | }; 236 | 3700DEF6202A1B690010408B /* LaunchScreen.storyboard */ = { 237 | isa = PBXVariantGroup; 238 | children = ( 239 | 3700DEF7202A1B690010408B /* Base */, 240 | ); 241 | name = LaunchScreen.storyboard; 242 | sourceTree = ""; 243 | }; 244 | /* End PBXVariantGroup section */ 245 | 246 | /* Begin XCBuildConfiguration section */ 247 | 3700DEFA202A1B690010408B /* Debug */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | ALWAYS_SEARCH_USER_PATHS = NO; 251 | CLANG_ANALYZER_NONNULL = YES; 252 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 253 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 254 | CLANG_CXX_LIBRARY = "libc++"; 255 | CLANG_ENABLE_MODULES = YES; 256 | CLANG_ENABLE_OBJC_ARC = YES; 257 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 258 | CLANG_WARN_BOOL_CONVERSION = YES; 259 | CLANG_WARN_COMMA = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 263 | CLANG_WARN_EMPTY_BODY = YES; 264 | CLANG_WARN_ENUM_CONVERSION = YES; 265 | CLANG_WARN_INFINITE_RECURSION = YES; 266 | CLANG_WARN_INT_CONVERSION = YES; 267 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 268 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 270 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 271 | CLANG_WARN_STRICT_PROTOTYPES = YES; 272 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 273 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 274 | CLANG_WARN_UNREACHABLE_CODE = YES; 275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 276 | CODE_SIGN_IDENTITY = "iPhone Developer"; 277 | COPY_PHASE_STRIP = NO; 278 | DEBUG_INFORMATION_FORMAT = dwarf; 279 | ENABLE_STRICT_OBJC_MSGSEND = YES; 280 | ENABLE_TESTABILITY = YES; 281 | GCC_C_LANGUAGE_STANDARD = gnu11; 282 | GCC_DYNAMIC_NO_PIC = NO; 283 | GCC_NO_COMMON_BLOCKS = YES; 284 | GCC_OPTIMIZATION_LEVEL = 0; 285 | GCC_PREPROCESSOR_DEFINITIONS = ( 286 | "DEBUG=1", 287 | "$(inherited)", 288 | ); 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 296 | MTL_ENABLE_DEBUG_INFO = YES; 297 | ONLY_ACTIVE_ARCH = YES; 298 | SDKROOT = iphoneos; 299 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 300 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 301 | }; 302 | name = Debug; 303 | }; 304 | 3700DEFB202A1B690010408B /* Release */ = { 305 | isa = XCBuildConfiguration; 306 | buildSettings = { 307 | ALWAYS_SEARCH_USER_PATHS = NO; 308 | CLANG_ANALYZER_NONNULL = YES; 309 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 310 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 311 | CLANG_CXX_LIBRARY = "libc++"; 312 | CLANG_ENABLE_MODULES = YES; 313 | CLANG_ENABLE_OBJC_ARC = YES; 314 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 315 | CLANG_WARN_BOOL_CONVERSION = YES; 316 | CLANG_WARN_COMMA = YES; 317 | CLANG_WARN_CONSTANT_CONVERSION = YES; 318 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 319 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 320 | CLANG_WARN_EMPTY_BODY = YES; 321 | CLANG_WARN_ENUM_CONVERSION = YES; 322 | CLANG_WARN_INFINITE_RECURSION = YES; 323 | CLANG_WARN_INT_CONVERSION = YES; 324 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 325 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 326 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 327 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 328 | CLANG_WARN_STRICT_PROTOTYPES = YES; 329 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 330 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 331 | CLANG_WARN_UNREACHABLE_CODE = YES; 332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 333 | CODE_SIGN_IDENTITY = "iPhone Developer"; 334 | COPY_PHASE_STRIP = NO; 335 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 336 | ENABLE_NS_ASSERTIONS = NO; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu11; 339 | GCC_NO_COMMON_BLOCKS = YES; 340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 342 | GCC_WARN_UNDECLARED_SELECTOR = YES; 343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 344 | GCC_WARN_UNUSED_FUNCTION = YES; 345 | GCC_WARN_UNUSED_VARIABLE = YES; 346 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 347 | MTL_ENABLE_DEBUG_INFO = NO; 348 | SDKROOT = iphoneos; 349 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 350 | VALIDATE_PRODUCT = YES; 351 | }; 352 | name = Release; 353 | }; 354 | 3700DEFD202A1B690010408B /* Debug */ = { 355 | isa = XCBuildConfiguration; 356 | baseConfigurationReference = 89766802E0978ADFA9D1162F /* Pods-ContinuumSample.debug.xcconfig */; 357 | buildSettings = { 358 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 359 | CODE_SIGN_STYLE = Automatic; 360 | INFOPLIST_FILE = ContinuumSample/Info.plist; 361 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 362 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 363 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.ContinuumSample"; 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | SWIFT_VERSION = 4.0; 366 | TARGETED_DEVICE_FAMILY = "1,2"; 367 | }; 368 | name = Debug; 369 | }; 370 | 3700DEFE202A1B690010408B /* Release */ = { 371 | isa = XCBuildConfiguration; 372 | baseConfigurationReference = D77E8EFE48AE7DEB9223E883 /* Pods-ContinuumSample.release.xcconfig */; 373 | buildSettings = { 374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 375 | CODE_SIGN_STYLE = Automatic; 376 | INFOPLIST_FILE = ContinuumSample/Info.plist; 377 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 378 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 379 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.ContinuumSample"; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | SWIFT_VERSION = 4.0; 382 | TARGETED_DEVICE_FAMILY = "1,2"; 383 | }; 384 | name = Release; 385 | }; 386 | /* End XCBuildConfiguration section */ 387 | 388 | /* Begin XCConfigurationList section */ 389 | 3700DEE5202A1B690010408B /* Build configuration list for PBXProject "ContinuumSample" */ = { 390 | isa = XCConfigurationList; 391 | buildConfigurations = ( 392 | 3700DEFA202A1B690010408B /* Debug */, 393 | 3700DEFB202A1B690010408B /* Release */, 394 | ); 395 | defaultConfigurationIsVisible = 0; 396 | defaultConfigurationName = Release; 397 | }; 398 | 3700DEFC202A1B690010408B /* Build configuration list for PBXNativeTarget "ContinuumSample" */ = { 399 | isa = XCConfigurationList; 400 | buildConfigurations = ( 401 | 3700DEFD202A1B690010408B /* Debug */, 402 | 3700DEFE202A1B690010408B /* Release */, 403 | ); 404 | defaultConfigurationIsVisible = 0; 405 | defaultConfigurationName = Release; 406 | }; 407 | /* End XCConfigurationList section */ 408 | }; 409 | rootObject = 3700DEE2202A1B690010408B /* Project object */; 410 | } 411 | -------------------------------------------------------------------------------- /Example/ContinuumSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/ContinuumSample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/ContinuumSample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ContinuumSample 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/ContinuumSample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Example/ContinuumSample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/ContinuumSample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Example/ContinuumSample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/ContinuumSample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ContinuumSample 4 | // 5 | // Created by marty-suzuki on 2018/02/07. 6 | // Copyright © 2018年 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Continuum 11 | 12 | final class ViewController: UIViewController { 13 | 14 | @IBOutlet private weak var countLabel: UILabel! 15 | @IBOutlet private weak var incrementButton: UIButton! 16 | @IBOutlet private weak var decrementButton: UIButton! 17 | 18 | private let viewModel = ViewModel() 19 | private let center = NotificationCenter() 20 | private let bag = ContinuumBag() 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | incrementButton.addTarget(viewModel, action: #selector(ViewModel.increment), for: .touchUpInside) 26 | decrementButton.addTarget(viewModel, action: #selector(ViewModel.decrement), for: .touchUpInside) 27 | 28 | center.continuum 29 | .observe(viewModel.count, bindTo: countLabel, \.text) 30 | .disposed(by: bag) 31 | 32 | center.continuum 33 | .observe(viewModel.decrementAlpha, bindTo: decrementButton, \.alpha) 34 | .disposed(by: bag) 35 | 36 | center.continuum 37 | .observe(viewModel.isDecrementEnabled, bindTo: decrementButton, \.isEnabled) 38 | .disposed(by: bag) 39 | } 40 | } 41 | 42 | final class ViewModel { 43 | let isDecrementEnabled: Constant 44 | private let _isDecrementEnabled = Variable(value: false) 45 | 46 | let decrementAlpha: Constant 47 | private let _decrementAlpha = Variable(value: 0.5) 48 | 49 | let count: Constant 50 | private let _count = Variable(value: "") 51 | 52 | private var rawCount: Int = 0 { 53 | didSet { 54 | _count.value = String(describing: rawCount) 55 | _isDecrementEnabled.value = rawCount > 0 56 | _decrementAlpha.value = _isDecrementEnabled.value ? 1 : 0.5 57 | } 58 | } 59 | 60 | init() { 61 | self.isDecrementEnabled = Constant(variable: _isDecrementEnabled) 62 | self.decrementAlpha = Constant(variable: _decrementAlpha) 63 | self.count = Constant(variable: _count) 64 | setInitialValue() 65 | } 66 | 67 | private func setInitialValue() { 68 | rawCount = 0 69 | } 70 | 71 | @objc func increment() { 72 | rawCount += 1 73 | } 74 | 75 | @objc func decrement() { 76 | rawCount -= 1 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '10.0' 3 | 4 | target 'ContinuumSample' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for ContinuumSample 9 | pod 'Continuum', :path => '../' 10 | end 11 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Continuum (0.2.0) 3 | 4 | DEPENDENCIES: 5 | - Continuum (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | Continuum: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | Continuum: 5b8ffad60099ff51417c53a21d8cb0e5ebff7789 13 | 14 | PODFILE CHECKSUM: deaf72ef75c6b582e95628803ecc2aadef262590 15 | 16 | COCOAPODS: 1.3.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/Continuum.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Continuum", 3 | "version": "0.2.0", 4 | "summary": "NotificationCenter based Lightweight UI / AnyObject binder.", 5 | "homepage": "https://github.com/marty-suzuki/Continuum", 6 | "license": { 7 | "type": "MIT", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "marty-suzuki": "s1180183@gmail.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/marty-suzuki/Continuum.git", 15 | "tag": "0.2.0" 16 | }, 17 | "social_media_url": "https://twitter.com/marty_suzuki", 18 | "platforms": { 19 | "ios": "10.0" 20 | }, 21 | "source_files": "Continuum/**/*.{swift}" 22 | } 23 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Continuum (0.2.0) 3 | 4 | DEPENDENCIES: 5 | - Continuum (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | Continuum: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | Continuum: 5b8ffad60099ff51417c53a21d8cb0e5ebff7789 13 | 14 | PODFILE CHECKSUM: deaf72ef75c6b582e95628803ecc2aadef262590 15 | 16 | COCOAPODS: 1.3.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 03F1F7DAB7CFFC0E24792E493602A161 /* Continuum-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E3674EBEF5D46CE8BECD35468E2931 /* Continuum-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 1998DF8598710E88E46E19D649ECEF7C /* Wrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8AF842944EDD43FCFA81C31DE1A0371 /* Wrappable.swift */; }; 12 | 1AB480729050FCC1AEDB779E1750F8E3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */; }; 13 | 66BF7D3C4EEE20497693209D87B5E385 /* Variable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB4E48303809AC3B7630333949891369 /* Variable.swift */; }; 14 | 7235F933E51ED2058D2076AFCDE2D20F /* Pods-ContinuumSample-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF908B4E1AAFB3C6C9B6329290D09E /* Pods-ContinuumSample-dummy.m */; }; 15 | 91C1F09007BAC9B411E4829BFC8595A3 /* Constant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B097997B73FB994CBBF728B6138636A /* Constant.swift */; }; 16 | A5DC4B427C09F9964900F1234E5CDE57 /* Continuum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E400428E4117A832E065CD451402D /* Continuum.swift */; }; 17 | BC2D51F30A3A6CA65D56EE0E6A970390 /* PThreadMutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 254BE333E3AC45AFD7546F400F924141 /* PThreadMutex.swift */; }; 18 | D47DC44A1D8AFB3F33C738C46B91F911 /* AnyKeyPath.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20C6DC74D23E349BF2F25302AFE17481 /* AnyKeyPath.extension.swift */; }; 19 | EB71AA5DE2A5A5CFD5527CD917404A10 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */; }; 20 | FA46FDA855243A07B38EAE054F98D65C /* Pods-ContinuumSample-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A50721901352C5903E6D52F37E31C249 /* Pods-ContinuumSample-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 21 | FFBBE30F29442ED5116A2C92BC0E6465 /* Continuum-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5027C66518C9F8A3353E2186AA0CB347 /* Continuum-dummy.m */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | FC6EF868F6AB56609C6E700FC32DF8A9 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = 3AB1DE9AE07F3F82E624B79E4B56C420; 30 | remoteInfo = Continuum; 31 | }; 32 | /* End PBXContainerItemProxy section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 172E400428E4117A832E065CD451402D /* Continuum.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Continuum.swift; path = Continuum/Continuum.swift; sourceTree = ""; }; 36 | 20C6DC74D23E349BF2F25302AFE17481 /* AnyKeyPath.extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnyKeyPath.extension.swift; sourceTree = ""; }; 37 | 254BE333E3AC45AFD7546F400F924141 /* PThreadMutex.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PThreadMutex.swift; sourceTree = ""; }; 38 | 2B097997B73FB994CBBF728B6138636A /* Constant.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Constant.swift; path = Continuum/Constant.swift; sourceTree = ""; }; 39 | 2FAB1941A561C07D0E703C37132B7E66 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 347D2184E29E6F1C9F1D781E94D570D5 /* Pods-ContinuumSample.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-ContinuumSample.modulemap"; sourceTree = ""; }; 41 | 3AE73E77B7FC25EFF633C2B776356C6C /* Continuum-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Continuum-prefix.pch"; sourceTree = ""; }; 42 | 451ADF51A04F60EE52436BE8E6E1B161 /* Pods-ContinuumSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ContinuumSample.debug.xcconfig"; sourceTree = ""; }; 43 | 4706065CC93C7BEC41E8A3B2B75C8567 /* Continuum.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Continuum.xcconfig; sourceTree = ""; }; 44 | 5027C66518C9F8A3353E2186AA0CB347 /* Continuum-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Continuum-dummy.m"; sourceTree = ""; }; 45 | 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 46 | 6737FCC4A5034EDD7A5682AB5FD3B693 /* Continuum.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Continuum.framework; path = Continuum.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 7D8F21ACE5B1ABBD1FEB2A5F598BE82F /* Pods-ContinuumSample-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ContinuumSample-resources.sh"; sourceTree = ""; }; 48 | 83C84D7CDB1D41A1603E1FDD350F6A65 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 50 | 954CD81546F562DD4A4988FC6505388D /* Pods-ContinuumSample-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-ContinuumSample-acknowledgements.plist"; sourceTree = ""; }; 51 | 9BDF908B4E1AAFB3C6C9B6329290D09E /* Pods-ContinuumSample-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-ContinuumSample-dummy.m"; sourceTree = ""; }; 52 | 9C15908990F3C299B6647E6976B97D89 /* Pods-ContinuumSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ContinuumSample.release.xcconfig"; sourceTree = ""; }; 53 | A50721901352C5903E6D52F37E31C249 /* Pods-ContinuumSample-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-ContinuumSample-umbrella.h"; sourceTree = ""; }; 54 | AB4E48303809AC3B7630333949891369 /* Variable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Variable.swift; path = Continuum/Variable.swift; sourceTree = ""; }; 55 | B2E3674EBEF5D46CE8BECD35468E2931 /* Continuum-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Continuum-umbrella.h"; sourceTree = ""; }; 56 | C8AF842944EDD43FCFA81C31DE1A0371 /* Wrappable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Wrappable.swift; path = Continuum/Wrappable.swift; sourceTree = ""; }; 57 | CAE479E8B4FBB0F43520A1B413FFE06B /* Pods_ContinuumSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_ContinuumSample.framework; path = "Pods-ContinuumSample.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | CBF717F20998B6C0CE451509B6B47E8A /* Pods-ContinuumSample-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-ContinuumSample-acknowledgements.markdown"; sourceTree = ""; }; 59 | E51E05203F4FA3A7F8FE167F3EBC09C3 /* Continuum.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = Continuum.modulemap; sourceTree = ""; }; 60 | F795D588535533FAA3710FE85D11448B /* Pods-ContinuumSample-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ContinuumSample-frameworks.sh"; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 0F1A09F2FE40E3AAC0D42D7F6AC6C2ED /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | EB71AA5DE2A5A5CFD5527CD917404A10 /* Foundation.framework in Frameworks */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | D660DB74C1A1810084F5F550C2D2A0D6 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | 1AB480729050FCC1AEDB779E1750F8E3 /* Foundation.framework in Frameworks */, 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | /* End PBXFrameworksBuildPhase section */ 81 | 82 | /* Begin PBXGroup section */ 83 | 2C967CA9D6593ABD98B5B4243438DB03 /* Development Pods */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | C01749711FAC246F79C71E41753DEB7E /* Continuum */, 87 | ); 88 | name = "Development Pods"; 89 | sourceTree = ""; 90 | }; 91 | 44B6ABECE92D65033087497A5866F991 /* Targets Support Files */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 8BA788036989F35BA172F4FD1749DC08 /* Pods-ContinuumSample */, 95 | ); 96 | name = "Targets Support Files"; 97 | sourceTree = ""; 98 | }; 99 | 7DB346D0F39D3F0E887471402A8071AB = { 100 | isa = PBXGroup; 101 | children = ( 102 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, 103 | 2C967CA9D6593ABD98B5B4243438DB03 /* Development Pods */, 104 | BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */, 105 | D2AA6F859278D50E333AA81A74C17857 /* Products */, 106 | 44B6ABECE92D65033087497A5866F991 /* Targets Support Files */, 107 | ); 108 | sourceTree = ""; 109 | }; 110 | 8BA788036989F35BA172F4FD1749DC08 /* Pods-ContinuumSample */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 2FAB1941A561C07D0E703C37132B7E66 /* Info.plist */, 114 | 347D2184E29E6F1C9F1D781E94D570D5 /* Pods-ContinuumSample.modulemap */, 115 | CBF717F20998B6C0CE451509B6B47E8A /* Pods-ContinuumSample-acknowledgements.markdown */, 116 | 954CD81546F562DD4A4988FC6505388D /* Pods-ContinuumSample-acknowledgements.plist */, 117 | 9BDF908B4E1AAFB3C6C9B6329290D09E /* Pods-ContinuumSample-dummy.m */, 118 | F795D588535533FAA3710FE85D11448B /* Pods-ContinuumSample-frameworks.sh */, 119 | 7D8F21ACE5B1ABBD1FEB2A5F598BE82F /* Pods-ContinuumSample-resources.sh */, 120 | A50721901352C5903E6D52F37E31C249 /* Pods-ContinuumSample-umbrella.h */, 121 | 451ADF51A04F60EE52436BE8E6E1B161 /* Pods-ContinuumSample.debug.xcconfig */, 122 | 9C15908990F3C299B6647E6976B97D89 /* Pods-ContinuumSample.release.xcconfig */, 123 | ); 124 | name = "Pods-ContinuumSample"; 125 | path = "Target Support Files/Pods-ContinuumSample"; 126 | sourceTree = ""; 127 | }; 128 | BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | D35AF013A5F0BAD4F32504907A52519E /* iOS */, 132 | ); 133 | name = Frameworks; 134 | sourceTree = ""; 135 | }; 136 | C01749711FAC246F79C71E41753DEB7E /* Continuum */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 2B097997B73FB994CBBF728B6138636A /* Constant.swift */, 140 | 172E400428E4117A832E065CD451402D /* Continuum.swift */, 141 | AB4E48303809AC3B7630333949891369 /* Variable.swift */, 142 | C8AF842944EDD43FCFA81C31DE1A0371 /* Wrappable.swift */, 143 | D77DC144CFFBD50B0A09350A709E68BD /* Internal */, 144 | E81640C9FCBE0BF65AE33B862C81E35B /* Support Files */, 145 | ); 146 | name = Continuum; 147 | path = ../..; 148 | sourceTree = ""; 149 | }; 150 | D2AA6F859278D50E333AA81A74C17857 /* Products */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 6737FCC4A5034EDD7A5682AB5FD3B693 /* Continuum.framework */, 154 | CAE479E8B4FBB0F43520A1B413FFE06B /* Pods_ContinuumSample.framework */, 155 | ); 156 | name = Products; 157 | sourceTree = ""; 158 | }; 159 | D35AF013A5F0BAD4F32504907A52519E /* iOS */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */, 163 | ); 164 | name = iOS; 165 | sourceTree = ""; 166 | }; 167 | D77DC144CFFBD50B0A09350A709E68BD /* Internal */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 20C6DC74D23E349BF2F25302AFE17481 /* AnyKeyPath.extension.swift */, 171 | 254BE333E3AC45AFD7546F400F924141 /* PThreadMutex.swift */, 172 | ); 173 | name = Internal; 174 | path = Continuum/Internal; 175 | sourceTree = ""; 176 | }; 177 | E81640C9FCBE0BF65AE33B862C81E35B /* Support Files */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | E51E05203F4FA3A7F8FE167F3EBC09C3 /* Continuum.modulemap */, 181 | 4706065CC93C7BEC41E8A3B2B75C8567 /* Continuum.xcconfig */, 182 | 5027C66518C9F8A3353E2186AA0CB347 /* Continuum-dummy.m */, 183 | 3AE73E77B7FC25EFF633C2B776356C6C /* Continuum-prefix.pch */, 184 | B2E3674EBEF5D46CE8BECD35468E2931 /* Continuum-umbrella.h */, 185 | 83C84D7CDB1D41A1603E1FDD350F6A65 /* Info.plist */, 186 | ); 187 | name = "Support Files"; 188 | path = "Example/Pods/Target Support Files/Continuum"; 189 | sourceTree = ""; 190 | }; 191 | /* End PBXGroup section */ 192 | 193 | /* Begin PBXHeadersBuildPhase section */ 194 | 54033D5F381CD0CCBD2AD690D5A0FFA0 /* Headers */ = { 195 | isa = PBXHeadersBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | FA46FDA855243A07B38EAE054F98D65C /* Pods-ContinuumSample-umbrella.h in Headers */, 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | D071E47B4DF75FB29B320A5763EED3A4 /* Headers */ = { 203 | isa = PBXHeadersBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | 03F1F7DAB7CFFC0E24792E493602A161 /* Continuum-umbrella.h in Headers */, 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | }; 210 | /* End PBXHeadersBuildPhase section */ 211 | 212 | /* Begin PBXNativeTarget section */ 213 | 04649C7DCEF2DB89D90DBB9DE53E6E15 /* Pods-ContinuumSample */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = 9B6A4F0F4E7A6ED808A3C6E46A5C0820 /* Build configuration list for PBXNativeTarget "Pods-ContinuumSample" */; 216 | buildPhases = ( 217 | 72800F6BA1CE2F89075F4BE55333BD46 /* Sources */, 218 | 0F1A09F2FE40E3AAC0D42D7F6AC6C2ED /* Frameworks */, 219 | 54033D5F381CD0CCBD2AD690D5A0FFA0 /* Headers */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | 0CCFCCE7DE26D2ABEC8D559B871A2183 /* PBXTargetDependency */, 225 | ); 226 | name = "Pods-ContinuumSample"; 227 | productName = "Pods-ContinuumSample"; 228 | productReference = CAE479E8B4FBB0F43520A1B413FFE06B /* Pods_ContinuumSample.framework */; 229 | productType = "com.apple.product-type.framework"; 230 | }; 231 | 3AB1DE9AE07F3F82E624B79E4B56C420 /* Continuum */ = { 232 | isa = PBXNativeTarget; 233 | buildConfigurationList = 19E328D3715047F705DDBDC6B1D458F3 /* Build configuration list for PBXNativeTarget "Continuum" */; 234 | buildPhases = ( 235 | 48E0E6EEC2389CF34B127C367E0D7C50 /* Sources */, 236 | D660DB74C1A1810084F5F550C2D2A0D6 /* Frameworks */, 237 | D071E47B4DF75FB29B320A5763EED3A4 /* Headers */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | ); 243 | name = Continuum; 244 | productName = Continuum; 245 | productReference = 6737FCC4A5034EDD7A5682AB5FD3B693 /* Continuum.framework */; 246 | productType = "com.apple.product-type.framework"; 247 | }; 248 | /* End PBXNativeTarget section */ 249 | 250 | /* Begin PBXProject section */ 251 | D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { 252 | isa = PBXProject; 253 | attributes = { 254 | LastSwiftUpdateCheck = 0830; 255 | LastUpgradeCheck = 0700; 256 | }; 257 | buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; 258 | compatibilityVersion = "Xcode 3.2"; 259 | developmentRegion = English; 260 | hasScannedForEncodings = 0; 261 | knownRegions = ( 262 | en, 263 | ); 264 | mainGroup = 7DB346D0F39D3F0E887471402A8071AB; 265 | productRefGroup = D2AA6F859278D50E333AA81A74C17857 /* Products */; 266 | projectDirPath = ""; 267 | projectRoot = ""; 268 | targets = ( 269 | 3AB1DE9AE07F3F82E624B79E4B56C420 /* Continuum */, 270 | 04649C7DCEF2DB89D90DBB9DE53E6E15 /* Pods-ContinuumSample */, 271 | ); 272 | }; 273 | /* End PBXProject section */ 274 | 275 | /* Begin PBXSourcesBuildPhase section */ 276 | 48E0E6EEC2389CF34B127C367E0D7C50 /* Sources */ = { 277 | isa = PBXSourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | D47DC44A1D8AFB3F33C738C46B91F911 /* AnyKeyPath.extension.swift in Sources */, 281 | 91C1F09007BAC9B411E4829BFC8595A3 /* Constant.swift in Sources */, 282 | FFBBE30F29442ED5116A2C92BC0E6465 /* Continuum-dummy.m in Sources */, 283 | A5DC4B427C09F9964900F1234E5CDE57 /* Continuum.swift in Sources */, 284 | BC2D51F30A3A6CA65D56EE0E6A970390 /* PThreadMutex.swift in Sources */, 285 | 66BF7D3C4EEE20497693209D87B5E385 /* Variable.swift in Sources */, 286 | 1998DF8598710E88E46E19D649ECEF7C /* Wrappable.swift in Sources */, 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | 72800F6BA1CE2F89075F4BE55333BD46 /* Sources */ = { 291 | isa = PBXSourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | 7235F933E51ED2058D2076AFCDE2D20F /* Pods-ContinuumSample-dummy.m in Sources */, 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | /* End PBXSourcesBuildPhase section */ 299 | 300 | /* Begin PBXTargetDependency section */ 301 | 0CCFCCE7DE26D2ABEC8D559B871A2183 /* PBXTargetDependency */ = { 302 | isa = PBXTargetDependency; 303 | name = Continuum; 304 | target = 3AB1DE9AE07F3F82E624B79E4B56C420 /* Continuum */; 305 | targetProxy = FC6EF868F6AB56609C6E700FC32DF8A9 /* PBXContainerItemProxy */; 306 | }; 307 | /* End PBXTargetDependency section */ 308 | 309 | /* Begin XCBuildConfiguration section */ 310 | 3BC1AA6DB7394C020E67657E717AB4AE /* Release */ = { 311 | isa = XCBuildConfiguration; 312 | baseConfigurationReference = 4706065CC93C7BEC41E8A3B2B75C8567 /* Continuum.xcconfig */; 313 | buildSettings = { 314 | CODE_SIGN_IDENTITY = ""; 315 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 316 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 317 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 318 | CURRENT_PROJECT_VERSION = 1; 319 | DEFINES_MODULE = YES; 320 | DYLIB_COMPATIBILITY_VERSION = 1; 321 | DYLIB_CURRENT_VERSION = 1; 322 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 323 | GCC_PREFIX_HEADER = "Target Support Files/Continuum/Continuum-prefix.pch"; 324 | INFOPLIST_FILE = "Target Support Files/Continuum/Info.plist"; 325 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 326 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 327 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 328 | MODULEMAP_FILE = "Target Support Files/Continuum/Continuum.modulemap"; 329 | PRODUCT_NAME = Continuum; 330 | SDKROOT = iphoneos; 331 | SKIP_INSTALL = YES; 332 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 333 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 334 | SWIFT_VERSION = 4.0; 335 | TARGETED_DEVICE_FAMILY = "1,2"; 336 | VALIDATE_PRODUCT = YES; 337 | VERSIONING_SYSTEM = "apple-generic"; 338 | VERSION_INFO_PREFIX = ""; 339 | }; 340 | name = Release; 341 | }; 342 | 52994B40DF69F1C8BB9F5E732CC2E47F /* Debug */ = { 343 | isa = XCBuildConfiguration; 344 | baseConfigurationReference = 451ADF51A04F60EE52436BE8E6E1B161 /* Pods-ContinuumSample.debug.xcconfig */; 345 | buildSettings = { 346 | CODE_SIGN_IDENTITY = ""; 347 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 348 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 349 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 350 | CURRENT_PROJECT_VERSION = 1; 351 | DEFINES_MODULE = YES; 352 | DYLIB_COMPATIBILITY_VERSION = 1; 353 | DYLIB_CURRENT_VERSION = 1; 354 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 355 | INFOPLIST_FILE = "Target Support Files/Pods-ContinuumSample/Info.plist"; 356 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 357 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 358 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 359 | MACH_O_TYPE = staticlib; 360 | MODULEMAP_FILE = "Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample.modulemap"; 361 | OTHER_LDFLAGS = ""; 362 | OTHER_LIBTOOLFLAGS = ""; 363 | PODS_ROOT = "$(SRCROOT)"; 364 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 365 | PRODUCT_NAME = Pods_ContinuumSample; 366 | SDKROOT = iphoneos; 367 | SKIP_INSTALL = YES; 368 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 369 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 370 | TARGETED_DEVICE_FAMILY = "1,2"; 371 | VERSIONING_SYSTEM = "apple-generic"; 372 | VERSION_INFO_PREFIX = ""; 373 | }; 374 | name = Debug; 375 | }; 376 | 714729AF77640D20B2327DA9EE4B0829 /* Release */ = { 377 | isa = XCBuildConfiguration; 378 | baseConfigurationReference = 9C15908990F3C299B6647E6976B97D89 /* Pods-ContinuumSample.release.xcconfig */; 379 | buildSettings = { 380 | CODE_SIGN_IDENTITY = ""; 381 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 382 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 383 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 384 | CURRENT_PROJECT_VERSION = 1; 385 | DEFINES_MODULE = YES; 386 | DYLIB_COMPATIBILITY_VERSION = 1; 387 | DYLIB_CURRENT_VERSION = 1; 388 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 389 | INFOPLIST_FILE = "Target Support Files/Pods-ContinuumSample/Info.plist"; 390 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 391 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 393 | MACH_O_TYPE = staticlib; 394 | MODULEMAP_FILE = "Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample.modulemap"; 395 | OTHER_LDFLAGS = ""; 396 | OTHER_LIBTOOLFLAGS = ""; 397 | PODS_ROOT = "$(SRCROOT)"; 398 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 399 | PRODUCT_NAME = Pods_ContinuumSample; 400 | SDKROOT = iphoneos; 401 | SKIP_INSTALL = YES; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | VERSIONING_SYSTEM = "apple-generic"; 406 | VERSION_INFO_PREFIX = ""; 407 | }; 408 | name = Release; 409 | }; 410 | 7C07ED8089F70A31B83996A8910D7F18 /* Debug */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | CLANG_ANALYZER_NONNULL = YES; 415 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 416 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 417 | CLANG_CXX_LIBRARY = "libc++"; 418 | CLANG_ENABLE_MODULES = YES; 419 | CLANG_ENABLE_OBJC_ARC = YES; 420 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 421 | CLANG_WARN_BOOL_CONVERSION = YES; 422 | CLANG_WARN_COMMA = YES; 423 | CLANG_WARN_CONSTANT_CONVERSION = YES; 424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 425 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 426 | CLANG_WARN_EMPTY_BODY = YES; 427 | CLANG_WARN_ENUM_CONVERSION = YES; 428 | CLANG_WARN_INFINITE_RECURSION = YES; 429 | CLANG_WARN_INT_CONVERSION = YES; 430 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 431 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 434 | CLANG_WARN_STRICT_PROTOTYPES = YES; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 437 | CLANG_WARN_UNREACHABLE_CODE = YES; 438 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 439 | CODE_SIGNING_REQUIRED = NO; 440 | COPY_PHASE_STRIP = NO; 441 | DEBUG_INFORMATION_FORMAT = dwarf; 442 | ENABLE_STRICT_OBJC_MSGSEND = YES; 443 | ENABLE_TESTABILITY = YES; 444 | GCC_C_LANGUAGE_STANDARD = gnu11; 445 | GCC_DYNAMIC_NO_PIC = NO; 446 | GCC_NO_COMMON_BLOCKS = YES; 447 | GCC_OPTIMIZATION_LEVEL = 0; 448 | GCC_PREPROCESSOR_DEFINITIONS = ( 449 | "POD_CONFIGURATION_DEBUG=1", 450 | "DEBUG=1", 451 | "$(inherited)", 452 | ); 453 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 454 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 455 | GCC_WARN_UNDECLARED_SELECTOR = YES; 456 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 457 | GCC_WARN_UNUSED_FUNCTION = YES; 458 | GCC_WARN_UNUSED_VARIABLE = YES; 459 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 460 | MTL_ENABLE_DEBUG_INFO = YES; 461 | ONLY_ACTIVE_ARCH = YES; 462 | PRODUCT_NAME = "$(TARGET_NAME)"; 463 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; 464 | STRIP_INSTALLED_PRODUCT = NO; 465 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 466 | SYMROOT = "${SRCROOT}/../build"; 467 | }; 468 | name = Debug; 469 | }; 470 | 95D08C2CF13689CEB3553C2F75F2DEDF /* Debug */ = { 471 | isa = XCBuildConfiguration; 472 | baseConfigurationReference = 4706065CC93C7BEC41E8A3B2B75C8567 /* Continuum.xcconfig */; 473 | buildSettings = { 474 | CODE_SIGN_IDENTITY = ""; 475 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 476 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 477 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 478 | CURRENT_PROJECT_VERSION = 1; 479 | DEFINES_MODULE = YES; 480 | DYLIB_COMPATIBILITY_VERSION = 1; 481 | DYLIB_CURRENT_VERSION = 1; 482 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 483 | GCC_PREFIX_HEADER = "Target Support Files/Continuum/Continuum-prefix.pch"; 484 | INFOPLIST_FILE = "Target Support Files/Continuum/Info.plist"; 485 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 486 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 487 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 488 | MODULEMAP_FILE = "Target Support Files/Continuum/Continuum.modulemap"; 489 | PRODUCT_NAME = Continuum; 490 | SDKROOT = iphoneos; 491 | SKIP_INSTALL = YES; 492 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 493 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 494 | SWIFT_VERSION = 4.0; 495 | TARGETED_DEVICE_FAMILY = "1,2"; 496 | VERSIONING_SYSTEM = "apple-generic"; 497 | VERSION_INFO_PREFIX = ""; 498 | }; 499 | name = Debug; 500 | }; 501 | 98F29E7567052F62660DDD7069ADF73C /* Release */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | ALWAYS_SEARCH_USER_PATHS = NO; 505 | CLANG_ANALYZER_NONNULL = YES; 506 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 507 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 508 | CLANG_CXX_LIBRARY = "libc++"; 509 | CLANG_ENABLE_MODULES = YES; 510 | CLANG_ENABLE_OBJC_ARC = YES; 511 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 512 | CLANG_WARN_BOOL_CONVERSION = YES; 513 | CLANG_WARN_COMMA = YES; 514 | CLANG_WARN_CONSTANT_CONVERSION = YES; 515 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 516 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 517 | CLANG_WARN_EMPTY_BODY = YES; 518 | CLANG_WARN_ENUM_CONVERSION = YES; 519 | CLANG_WARN_INFINITE_RECURSION = YES; 520 | CLANG_WARN_INT_CONVERSION = YES; 521 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 522 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 523 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 524 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 525 | CLANG_WARN_STRICT_PROTOTYPES = YES; 526 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 527 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 528 | CLANG_WARN_UNREACHABLE_CODE = YES; 529 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 530 | CODE_SIGNING_REQUIRED = NO; 531 | COPY_PHASE_STRIP = NO; 532 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 533 | ENABLE_NS_ASSERTIONS = NO; 534 | ENABLE_STRICT_OBJC_MSGSEND = YES; 535 | GCC_C_LANGUAGE_STANDARD = gnu11; 536 | GCC_NO_COMMON_BLOCKS = YES; 537 | GCC_PREPROCESSOR_DEFINITIONS = ( 538 | "POD_CONFIGURATION_RELEASE=1", 539 | "$(inherited)", 540 | ); 541 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 542 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 543 | GCC_WARN_UNDECLARED_SELECTOR = YES; 544 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 545 | GCC_WARN_UNUSED_FUNCTION = YES; 546 | GCC_WARN_UNUSED_VARIABLE = YES; 547 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 548 | MTL_ENABLE_DEBUG_INFO = NO; 549 | PRODUCT_NAME = "$(TARGET_NAME)"; 550 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; 551 | STRIP_INSTALLED_PRODUCT = NO; 552 | SYMROOT = "${SRCROOT}/../build"; 553 | }; 554 | name = Release; 555 | }; 556 | /* End XCBuildConfiguration section */ 557 | 558 | /* Begin XCConfigurationList section */ 559 | 19E328D3715047F705DDBDC6B1D458F3 /* Build configuration list for PBXNativeTarget "Continuum" */ = { 560 | isa = XCConfigurationList; 561 | buildConfigurations = ( 562 | 95D08C2CF13689CEB3553C2F75F2DEDF /* Debug */, 563 | 3BC1AA6DB7394C020E67657E717AB4AE /* Release */, 564 | ); 565 | defaultConfigurationIsVisible = 0; 566 | defaultConfigurationName = Release; 567 | }; 568 | 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { 569 | isa = XCConfigurationList; 570 | buildConfigurations = ( 571 | 7C07ED8089F70A31B83996A8910D7F18 /* Debug */, 572 | 98F29E7567052F62660DDD7069ADF73C /* Release */, 573 | ); 574 | defaultConfigurationIsVisible = 0; 575 | defaultConfigurationName = Release; 576 | }; 577 | 9B6A4F0F4E7A6ED808A3C6E46A5C0820 /* Build configuration list for PBXNativeTarget "Pods-ContinuumSample" */ = { 578 | isa = XCConfigurationList; 579 | buildConfigurations = ( 580 | 52994B40DF69F1C8BB9F5E732CC2E47F /* Debug */, 581 | 714729AF77640D20B2327DA9EE4B0829 /* Release */, 582 | ); 583 | defaultConfigurationIsVisible = 0; 584 | defaultConfigurationName = Release; 585 | }; 586 | /* End XCConfigurationList section */ 587 | }; 588 | rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 589 | } 590 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Continuum/Continuum-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Continuum : NSObject 3 | @end 4 | @implementation PodsDummy_Continuum 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Continuum/Continuum-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Continuum/Continuum-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double ContinuumVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ContinuumVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Continuum/Continuum.modulemap: -------------------------------------------------------------------------------- 1 | framework module Continuum { 2 | umbrella header "Continuum-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Continuum/Continuum.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Continuum 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Continuum/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 | 0.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Continuum 5 | 6 | Copyright (c) 2018 marty-suzuki 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2018 marty-suzuki <s1180183@gmail.com> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | Continuum 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ContinuumSample : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ContinuumSample 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | 104 | if [[ "$CONFIGURATION" == "Debug" ]]; then 105 | install_framework "${BUILT_PRODUCTS_DIR}/Continuum/Continuum.framework" 106 | fi 107 | if [[ "$CONFIGURATION" == "Release" ]]; then 108 | install_framework "${BUILT_PRODUCTS_DIR}/Continuum/Continuum.framework" 109 | fi 110 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 111 | wait 112 | fi 113 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ContinuumSampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ContinuumSampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Continuum" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Continuum/Continuum.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "Continuum" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ContinuumSample { 2 | umbrella header "Pods-ContinuumSample-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ContinuumSample/Pods-ContinuumSample.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Continuum" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Continuum/Continuum.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "Continuum" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marty-suzuki/Continuum/440f44a7f8fb5550da6da01da77ddd1dd8ccb268/Images/example.png -------------------------------------------------------------------------------- /Images/playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marty-suzuki/Continuum/440f44a7f8fb5550da6da01da77ddd1dd8ccb268/Images/playground.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 marty-suzuki 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 11 | all 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 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Continuum 2 | 3 | [![CI Status](http://img.shields.io/travis/marty-suzuki/Continuum.svg?style=flat)](https://travis-ci.org/marty-suzuki/Continuum) 4 | [![Version](https://img.shields.io/cocoapods/v/Continuum.svg?style=flat)](http://cocoapods.org/pods/Continuum) 5 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 6 | [![License](https://img.shields.io/cocoapods/l/Continuum.svg?style=flat)](http://cocoapods.org/pods/Continuum) 7 | [![Platform](https://img.shields.io/cocoapods/p/Continuum.svg?style=flat)](http://cocoapods.org/pods/Continuum) 8 | 9 | NotificationCenter based Lightweight UI / AnyObject binder. 10 | 11 | ```swift 12 | final class ViewController: UIViewController { 13 | 14 | @IBOutlet weak var label: UILabel! 15 | 16 | private let viewModel: ViewModel = ViewModel() 17 | private let center = NotificationCenter() 18 | private let bag = ContinuumBag() 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | 23 | center.continuum 24 | .observe(viewModel.text, on: .main, bindTo: label, \.text) 25 | .disposed(by: bag) 26 | 27 | viewModel.text.value = "Binding this text to label.text!" 28 | } 29 | } 30 | 31 | final class ViewModel { 32 | let text: Variable 33 | 34 | init() { 35 | self.text = Variable(value: "") 36 | } 37 | } 38 | ``` 39 | 40 | ## Usage 41 | 42 | ### 1. Observe object KeyPath and bind it to target KeyPath 43 | 44 | NotificationCenter's instance has `continuum` property. You can access Continuum functions from it. 45 | 46 | ```swift 47 | let center = NotificationCenter() 48 | let observer = center.continuum.observe(viewModel, \.text, on: .main, bindTo: label, \.text) 49 | ``` 50 | 51 | Above source code means `observe viewModel's text propety and bind that value to label's text property on main thread`. 52 | If property is observed, current value comes immediately. 53 | 54 | #### Notify changes with `func post(keyPath:)` 55 | 56 | If value changed, notify changes like this. 57 | 58 | ```swift 59 | viewModel.text = "Changed" 60 | center.continuum.post(keyPath: \ViewModel.text) 61 | print(label.text) // Changed 62 | ``` 63 | 64 | ### 2. Observe Constant / Variable and bind it to target KeyPath 65 | 66 | Constant / Variable are value wrapper. Variable has getter / setter. Constant has only getter. 67 | 68 | ```swift 69 | let center = NotificationCenter() 70 | let text = Variable(value: "") 71 | let observer = center.continuum.observe(text, on: .main, bindTo: label, \.text) 72 | ``` 73 | 74 | If property is observed, current value comes immediately. 75 | 76 | ### 3. Observe Constant / Variable and bind it to closure 77 | 78 | Constant / Variable are value wrapper. Variable has getter / setter. Constant has only getter. 79 | 80 | ```swift 81 | let center = NotificationCenter() 82 | let text = Variable(value: "") 83 | let observer = center.continuum.observe(text, on: .main, onValueChange: { value in 84 | // something to do 85 | }) 86 | ``` 87 | 88 | If property is observed, current value comes immediately. 89 | 90 | #### Notify changes with setter of value at Variable 91 | 92 | If Variable's value is changed, `func post(name:object:)` is automatically executed. 93 | 94 | ```swift 95 | text.value = "Changed" 96 | print(label.text) // Changed 97 | ``` 98 | 99 | In addition, if Variable's value is changed, related Constant value is automatically changed. 100 | 101 | ```swift 102 | let center = NotificationCenter() 103 | let variable = Variable(value: "") 104 | let constant = Constant(variable: variable) 105 | let observer = center.continuum.observe(constant, on: .main, bindTo: label, \.text) 106 | variable.value = "Changed" 107 | print(label.text) // Changed 108 | ``` 109 | 110 | ### Lifecycle of ContinuumObserver 111 | 112 | `func observe(_:,_:,on:,bindTo:,_:)` returns `ContinuumObserver`. 113 | If `func cancel()` of `ContinuumObserver` called, observation is cancelled. 114 | 115 | ```swift 116 | let observer = center.continuum.observe(viewModel, \.text, on: .main, bindTo: label, \.text) 117 | observer.cancel() 118 | ``` 119 | 120 | If adding observer to `ContinumeBag`, observation is cancelled by lifecycle of `ContinumeBag`. 121 | 122 | ```swift 123 | var bag = ContinumeBag() 124 | center.continuum 125 | .observe(viewModel, \.text, on: .main, bindTo: label, \.text) 126 | .disposed(by: bag) 127 | 128 | bag = ContinumeBag() // previous instance of ContinumeBag is released and observation is cancelled. 129 | ``` 130 | 131 | ## Example 132 | 133 | ### Playground 134 | 135 | You can try **Continuum** with Playground. 136 | Open Continuum.xcworkspace and run build. 137 | You can try like this. 138 | 139 | ![](./Images/playground.png) 140 | 141 | ### Example Project 142 | 143 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 144 | Open ContinuumSample.xcworkspace and run build. 145 | You can try a simple counter app like this. 146 | 147 | ![](./Images/example.png) 148 | 149 | ## Requirements 150 | 151 | - Xcode 9.2 or later 152 | - Swift 4.0.3 or later 153 | - iOS 10.0 or later 154 | 155 | ## Installation 156 | 157 | ### CocoaPods 158 | 159 | Continuum is available through [CocoaPods](http://cocoapods.org). To install 160 | it, simply add the following line to your Podfile: 161 | 162 | ```ruby 163 | pod 'Continuum' 164 | ``` 165 | 166 | ### Carthage 167 | 168 | If you’re using [Carthage](https://github.com/Carthage/Carthage), simply add Continuum to your `Cartfile`: 169 | 170 | ```ruby 171 | github "marty-suzuki/Continuum" 172 | ``` 173 | 174 | ## Author 175 | 176 | marty-suzuki, s1180183@gmail.com 177 | 178 | ## License 179 | 180 | Continuum is available under the MIT license. See the LICENSE file for more info. 181 | --------------------------------------------------------------------------------