├── .DS_Store ├── .gitignore ├── LICENSE ├── Observing ├── .DS_Store ├── Observing.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Observing │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── KVCViewController.h │ ├── KVCViewController.m │ ├── KVOViewController.h │ ├── KVOViewController.m │ ├── LaughingSir.h │ ├── LaughingSir.m │ ├── ViewController.h │ ├── ViewController.m │ ├── YiTian.h │ ├── YiTian.m │ └── main.m ├── ObservingTests │ ├── Info.plist │ └── ObservingTests.m └── ObservingUITests │ ├── Info.plist │ └── ObservingUITests.m ├── README.md └── picture ├── observing.gif └── observing1.png /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minggo620/iOSObserving/184b30ed4501601a9dcd4b5c1a9682d8df0475f0/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 minggo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Observing/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minggo620/iOSObserving/184b30ed4501601a9dcd4b5c1a9682d8df0475f0/Observing/.DS_Store -------------------------------------------------------------------------------- /Observing/Observing.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4648DB281CAD1EFE00D8DCD5 /* YiTian.m in Sources */ = {isa = PBXBuildFile; fileRef = 4648DB271CAD1EFE00D8DCD5 /* YiTian.m */; }; 11 | 46F3D36F1C7AFB82007C612F /* LaughingSir.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F3D36E1C7AFB82007C612F /* LaughingSir.m */; }; 12 | 46F6AE521C5F557A0074ECE7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F6AE511C5F557A0074ECE7 /* main.m */; }; 13 | 46F6AE551C5F557A0074ECE7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F6AE541C5F557A0074ECE7 /* AppDelegate.m */; }; 14 | 46F6AE581C5F557A0074ECE7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F6AE571C5F557A0074ECE7 /* ViewController.m */; }; 15 | 46F6AE5B1C5F557A0074ECE7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46F6AE591C5F557A0074ECE7 /* Main.storyboard */; }; 16 | 46F6AE5D1C5F557B0074ECE7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 46F6AE5C1C5F557B0074ECE7 /* Assets.xcassets */; }; 17 | 46F6AE601C5F557B0074ECE7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46F6AE5E1C5F557B0074ECE7 /* LaunchScreen.storyboard */; }; 18 | 46F6AE6B1C5F557B0074ECE7 /* ObservingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F6AE6A1C5F557B0074ECE7 /* ObservingTests.m */; }; 19 | 46F6AE761C5F557B0074ECE7 /* ObservingUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F6AE751C5F557B0074ECE7 /* ObservingUITests.m */; }; 20 | 46F6AE851C5F5E880074ECE7 /* KVCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F6AE841C5F5E880074ECE7 /* KVCViewController.m */; }; 21 | 46F6AE881C5F5E960074ECE7 /* KVOViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F6AE871C5F5E960074ECE7 /* KVOViewController.m */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | 46F6AE671C5F557B0074ECE7 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = 46F6AE451C5F557A0074ECE7 /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = 46F6AE4C1C5F557A0074ECE7; 30 | remoteInfo = Observing; 31 | }; 32 | 46F6AE721C5F557B0074ECE7 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 46F6AE451C5F557A0074ECE7 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 46F6AE4C1C5F557A0074ECE7; 37 | remoteInfo = Observing; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 4648DB261CAD1EFE00D8DCD5 /* YiTian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YiTian.h; sourceTree = ""; }; 43 | 4648DB271CAD1EFE00D8DCD5 /* YiTian.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YiTian.m; sourceTree = ""; }; 44 | 46F3D36D1C7AFB82007C612F /* LaughingSir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaughingSir.h; sourceTree = ""; }; 45 | 46F3D36E1C7AFB82007C612F /* LaughingSir.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LaughingSir.m; sourceTree = ""; }; 46 | 46F6AE4D1C5F557A0074ECE7 /* Observing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Observing.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 46F6AE511C5F557A0074ECE7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 48 | 46F6AE531C5F557A0074ECE7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 49 | 46F6AE541C5F557A0074ECE7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 50 | 46F6AE561C5F557A0074ECE7 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 51 | 46F6AE571C5F557A0074ECE7 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 52 | 46F6AE5A1C5F557A0074ECE7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 46F6AE5C1C5F557B0074ECE7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 46F6AE5F1C5F557B0074ECE7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 46F6AE611C5F557B0074ECE7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 46F6AE661C5F557B0074ECE7 /* ObservingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ObservingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 46F6AE6A1C5F557B0074ECE7 /* ObservingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ObservingTests.m; sourceTree = ""; }; 58 | 46F6AE6C1C5F557B0074ECE7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 46F6AE711C5F557B0074ECE7 /* ObservingUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ObservingUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 46F6AE751C5F557B0074ECE7 /* ObservingUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ObservingUITests.m; sourceTree = ""; }; 61 | 46F6AE771C5F557B0074ECE7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 46F6AE831C5F5E880074ECE7 /* KVCViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KVCViewController.h; sourceTree = ""; }; 63 | 46F6AE841C5F5E880074ECE7 /* KVCViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KVCViewController.m; sourceTree = ""; }; 64 | 46F6AE861C5F5E960074ECE7 /* KVOViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KVOViewController.h; sourceTree = ""; }; 65 | 46F6AE871C5F5E960074ECE7 /* KVOViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KVOViewController.m; sourceTree = ""; }; 66 | /* End PBXFileReference section */ 67 | 68 | /* Begin PBXFrameworksBuildPhase section */ 69 | 46F6AE4A1C5F557A0074ECE7 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | 46F6AE631C5F557B0074ECE7 /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | 46F6AE6E1C5F557B0074ECE7 /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | /* End PBXFrameworksBuildPhase section */ 91 | 92 | /* Begin PBXGroup section */ 93 | 46F6AE441C5F557A0074ECE7 = { 94 | isa = PBXGroup; 95 | children = ( 96 | 46F6AE4F1C5F557A0074ECE7 /* Observing */, 97 | 46F6AE691C5F557B0074ECE7 /* ObservingTests */, 98 | 46F6AE741C5F557B0074ECE7 /* ObservingUITests */, 99 | 46F6AE4E1C5F557A0074ECE7 /* Products */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | 46F6AE4E1C5F557A0074ECE7 /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 46F6AE4D1C5F557A0074ECE7 /* Observing.app */, 107 | 46F6AE661C5F557B0074ECE7 /* ObservingTests.xctest */, 108 | 46F6AE711C5F557B0074ECE7 /* ObservingUITests.xctest */, 109 | ); 110 | name = Products; 111 | sourceTree = ""; 112 | }; 113 | 46F6AE4F1C5F557A0074ECE7 /* Observing */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 46F6AE531C5F557A0074ECE7 /* AppDelegate.h */, 117 | 46F6AE541C5F557A0074ECE7 /* AppDelegate.m */, 118 | 46F6AE561C5F557A0074ECE7 /* ViewController.h */, 119 | 46F6AE571C5F557A0074ECE7 /* ViewController.m */, 120 | 46F6AE591C5F557A0074ECE7 /* Main.storyboard */, 121 | 46F6AE5C1C5F557B0074ECE7 /* Assets.xcassets */, 122 | 46F6AE5E1C5F557B0074ECE7 /* LaunchScreen.storyboard */, 123 | 46F6AE611C5F557B0074ECE7 /* Info.plist */, 124 | 46F6AE501C5F557A0074ECE7 /* Supporting Files */, 125 | 46F6AE831C5F5E880074ECE7 /* KVCViewController.h */, 126 | 46F6AE841C5F5E880074ECE7 /* KVCViewController.m */, 127 | 46F6AE861C5F5E960074ECE7 /* KVOViewController.h */, 128 | 46F6AE871C5F5E960074ECE7 /* KVOViewController.m */, 129 | 46F3D36D1C7AFB82007C612F /* LaughingSir.h */, 130 | 46F3D36E1C7AFB82007C612F /* LaughingSir.m */, 131 | 4648DB261CAD1EFE00D8DCD5 /* YiTian.h */, 132 | 4648DB271CAD1EFE00D8DCD5 /* YiTian.m */, 133 | ); 134 | path = Observing; 135 | sourceTree = ""; 136 | }; 137 | 46F6AE501C5F557A0074ECE7 /* Supporting Files */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 46F6AE511C5F557A0074ECE7 /* main.m */, 141 | ); 142 | name = "Supporting Files"; 143 | sourceTree = ""; 144 | }; 145 | 46F6AE691C5F557B0074ECE7 /* ObservingTests */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 46F6AE6A1C5F557B0074ECE7 /* ObservingTests.m */, 149 | 46F6AE6C1C5F557B0074ECE7 /* Info.plist */, 150 | ); 151 | path = ObservingTests; 152 | sourceTree = ""; 153 | }; 154 | 46F6AE741C5F557B0074ECE7 /* ObservingUITests */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 46F6AE751C5F557B0074ECE7 /* ObservingUITests.m */, 158 | 46F6AE771C5F557B0074ECE7 /* Info.plist */, 159 | ); 160 | path = ObservingUITests; 161 | sourceTree = ""; 162 | }; 163 | /* End PBXGroup section */ 164 | 165 | /* Begin PBXNativeTarget section */ 166 | 46F6AE4C1C5F557A0074ECE7 /* Observing */ = { 167 | isa = PBXNativeTarget; 168 | buildConfigurationList = 46F6AE7A1C5F557B0074ECE7 /* Build configuration list for PBXNativeTarget "Observing" */; 169 | buildPhases = ( 170 | 46F6AE491C5F557A0074ECE7 /* Sources */, 171 | 46F6AE4A1C5F557A0074ECE7 /* Frameworks */, 172 | 46F6AE4B1C5F557A0074ECE7 /* Resources */, 173 | ); 174 | buildRules = ( 175 | ); 176 | dependencies = ( 177 | ); 178 | name = Observing; 179 | productName = Observing; 180 | productReference = 46F6AE4D1C5F557A0074ECE7 /* Observing.app */; 181 | productType = "com.apple.product-type.application"; 182 | }; 183 | 46F6AE651C5F557B0074ECE7 /* ObservingTests */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 46F6AE7D1C5F557B0074ECE7 /* Build configuration list for PBXNativeTarget "ObservingTests" */; 186 | buildPhases = ( 187 | 46F6AE621C5F557B0074ECE7 /* Sources */, 188 | 46F6AE631C5F557B0074ECE7 /* Frameworks */, 189 | 46F6AE641C5F557B0074ECE7 /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | 46F6AE681C5F557B0074ECE7 /* PBXTargetDependency */, 195 | ); 196 | name = ObservingTests; 197 | productName = ObservingTests; 198 | productReference = 46F6AE661C5F557B0074ECE7 /* ObservingTests.xctest */; 199 | productType = "com.apple.product-type.bundle.unit-test"; 200 | }; 201 | 46F6AE701C5F557B0074ECE7 /* ObservingUITests */ = { 202 | isa = PBXNativeTarget; 203 | buildConfigurationList = 46F6AE801C5F557B0074ECE7 /* Build configuration list for PBXNativeTarget "ObservingUITests" */; 204 | buildPhases = ( 205 | 46F6AE6D1C5F557B0074ECE7 /* Sources */, 206 | 46F6AE6E1C5F557B0074ECE7 /* Frameworks */, 207 | 46F6AE6F1C5F557B0074ECE7 /* Resources */, 208 | ); 209 | buildRules = ( 210 | ); 211 | dependencies = ( 212 | 46F6AE731C5F557B0074ECE7 /* PBXTargetDependency */, 213 | ); 214 | name = ObservingUITests; 215 | productName = ObservingUITests; 216 | productReference = 46F6AE711C5F557B0074ECE7 /* ObservingUITests.xctest */; 217 | productType = "com.apple.product-type.bundle.ui-testing"; 218 | }; 219 | /* End PBXNativeTarget section */ 220 | 221 | /* Begin PBXProject section */ 222 | 46F6AE451C5F557A0074ECE7 /* Project object */ = { 223 | isa = PBXProject; 224 | attributes = { 225 | LastUpgradeCheck = 0720; 226 | ORGANIZATIONNAME = minggo; 227 | TargetAttributes = { 228 | 46F6AE4C1C5F557A0074ECE7 = { 229 | CreatedOnToolsVersion = 7.2; 230 | }; 231 | 46F6AE651C5F557B0074ECE7 = { 232 | CreatedOnToolsVersion = 7.2; 233 | TestTargetID = 46F6AE4C1C5F557A0074ECE7; 234 | }; 235 | 46F6AE701C5F557B0074ECE7 = { 236 | CreatedOnToolsVersion = 7.2; 237 | TestTargetID = 46F6AE4C1C5F557A0074ECE7; 238 | }; 239 | }; 240 | }; 241 | buildConfigurationList = 46F6AE481C5F557A0074ECE7 /* Build configuration list for PBXProject "Observing" */; 242 | compatibilityVersion = "Xcode 3.2"; 243 | developmentRegion = English; 244 | hasScannedForEncodings = 0; 245 | knownRegions = ( 246 | en, 247 | Base, 248 | ); 249 | mainGroup = 46F6AE441C5F557A0074ECE7; 250 | productRefGroup = 46F6AE4E1C5F557A0074ECE7 /* Products */; 251 | projectDirPath = ""; 252 | projectRoot = ""; 253 | targets = ( 254 | 46F6AE4C1C5F557A0074ECE7 /* Observing */, 255 | 46F6AE651C5F557B0074ECE7 /* ObservingTests */, 256 | 46F6AE701C5F557B0074ECE7 /* ObservingUITests */, 257 | ); 258 | }; 259 | /* End PBXProject section */ 260 | 261 | /* Begin PBXResourcesBuildPhase section */ 262 | 46F6AE4B1C5F557A0074ECE7 /* Resources */ = { 263 | isa = PBXResourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | 46F6AE601C5F557B0074ECE7 /* LaunchScreen.storyboard in Resources */, 267 | 46F6AE5D1C5F557B0074ECE7 /* Assets.xcassets in Resources */, 268 | 46F6AE5B1C5F557A0074ECE7 /* Main.storyboard in Resources */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | 46F6AE641C5F557B0074ECE7 /* Resources */ = { 273 | isa = PBXResourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | ); 277 | runOnlyForDeploymentPostprocessing = 0; 278 | }; 279 | 46F6AE6F1C5F557B0074ECE7 /* Resources */ = { 280 | isa = PBXResourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | ); 284 | runOnlyForDeploymentPostprocessing = 0; 285 | }; 286 | /* End PBXResourcesBuildPhase section */ 287 | 288 | /* Begin PBXSourcesBuildPhase section */ 289 | 46F6AE491C5F557A0074ECE7 /* Sources */ = { 290 | isa = PBXSourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | 46F6AE851C5F5E880074ECE7 /* KVCViewController.m in Sources */, 294 | 46F6AE581C5F557A0074ECE7 /* ViewController.m in Sources */, 295 | 46F6AE551C5F557A0074ECE7 /* AppDelegate.m in Sources */, 296 | 46F6AE521C5F557A0074ECE7 /* main.m in Sources */, 297 | 46F6AE881C5F5E960074ECE7 /* KVOViewController.m in Sources */, 298 | 46F3D36F1C7AFB82007C612F /* LaughingSir.m in Sources */, 299 | 4648DB281CAD1EFE00D8DCD5 /* YiTian.m in Sources */, 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | 46F6AE621C5F557B0074ECE7 /* Sources */ = { 304 | isa = PBXSourcesBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | 46F6AE6B1C5F557B0074ECE7 /* ObservingTests.m in Sources */, 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | 46F6AE6D1C5F557B0074ECE7 /* Sources */ = { 312 | isa = PBXSourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | 46F6AE761C5F557B0074ECE7 /* ObservingUITests.m in Sources */, 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | /* End PBXSourcesBuildPhase section */ 320 | 321 | /* Begin PBXTargetDependency section */ 322 | 46F6AE681C5F557B0074ECE7 /* PBXTargetDependency */ = { 323 | isa = PBXTargetDependency; 324 | target = 46F6AE4C1C5F557A0074ECE7 /* Observing */; 325 | targetProxy = 46F6AE671C5F557B0074ECE7 /* PBXContainerItemProxy */; 326 | }; 327 | 46F6AE731C5F557B0074ECE7 /* PBXTargetDependency */ = { 328 | isa = PBXTargetDependency; 329 | target = 46F6AE4C1C5F557A0074ECE7 /* Observing */; 330 | targetProxy = 46F6AE721C5F557B0074ECE7 /* PBXContainerItemProxy */; 331 | }; 332 | /* End PBXTargetDependency section */ 333 | 334 | /* Begin PBXVariantGroup section */ 335 | 46F6AE591C5F557A0074ECE7 /* Main.storyboard */ = { 336 | isa = PBXVariantGroup; 337 | children = ( 338 | 46F6AE5A1C5F557A0074ECE7 /* Base */, 339 | ); 340 | name = Main.storyboard; 341 | sourceTree = ""; 342 | }; 343 | 46F6AE5E1C5F557B0074ECE7 /* LaunchScreen.storyboard */ = { 344 | isa = PBXVariantGroup; 345 | children = ( 346 | 46F6AE5F1C5F557B0074ECE7 /* Base */, 347 | ); 348 | name = LaunchScreen.storyboard; 349 | sourceTree = ""; 350 | }; 351 | /* End PBXVariantGroup section */ 352 | 353 | /* Begin XCBuildConfiguration section */ 354 | 46F6AE781C5F557B0074ECE7 /* Debug */ = { 355 | isa = XCBuildConfiguration; 356 | buildSettings = { 357 | ALWAYS_SEARCH_USER_PATHS = NO; 358 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 359 | CLANG_CXX_LIBRARY = "libc++"; 360 | CLANG_ENABLE_MODULES = YES; 361 | CLANG_ENABLE_OBJC_ARC = YES; 362 | CLANG_WARN_BOOL_CONVERSION = YES; 363 | CLANG_WARN_CONSTANT_CONVERSION = YES; 364 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 365 | CLANG_WARN_EMPTY_BODY = YES; 366 | CLANG_WARN_ENUM_CONVERSION = YES; 367 | CLANG_WARN_INT_CONVERSION = YES; 368 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 369 | CLANG_WARN_UNREACHABLE_CODE = YES; 370 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 371 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 372 | COPY_PHASE_STRIP = NO; 373 | DEBUG_INFORMATION_FORMAT = dwarf; 374 | ENABLE_STRICT_OBJC_MSGSEND = YES; 375 | ENABLE_TESTABILITY = YES; 376 | GCC_C_LANGUAGE_STANDARD = gnu99; 377 | GCC_DYNAMIC_NO_PIC = NO; 378 | GCC_NO_COMMON_BLOCKS = YES; 379 | GCC_OPTIMIZATION_LEVEL = 0; 380 | GCC_PREPROCESSOR_DEFINITIONS = ( 381 | "DEBUG=1", 382 | "$(inherited)", 383 | ); 384 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 385 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 386 | GCC_WARN_UNDECLARED_SELECTOR = YES; 387 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 388 | GCC_WARN_UNUSED_FUNCTION = YES; 389 | GCC_WARN_UNUSED_VARIABLE = YES; 390 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 391 | MTL_ENABLE_DEBUG_INFO = YES; 392 | ONLY_ACTIVE_ARCH = YES; 393 | SDKROOT = iphoneos; 394 | TARGETED_DEVICE_FAMILY = "1,2"; 395 | }; 396 | name = Debug; 397 | }; 398 | 46F6AE791C5F557B0074ECE7 /* Release */ = { 399 | isa = XCBuildConfiguration; 400 | buildSettings = { 401 | ALWAYS_SEARCH_USER_PATHS = NO; 402 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 403 | CLANG_CXX_LIBRARY = "libc++"; 404 | CLANG_ENABLE_MODULES = YES; 405 | CLANG_ENABLE_OBJC_ARC = YES; 406 | CLANG_WARN_BOOL_CONVERSION = YES; 407 | CLANG_WARN_CONSTANT_CONVERSION = YES; 408 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 409 | CLANG_WARN_EMPTY_BODY = YES; 410 | CLANG_WARN_ENUM_CONVERSION = YES; 411 | CLANG_WARN_INT_CONVERSION = YES; 412 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 413 | CLANG_WARN_UNREACHABLE_CODE = YES; 414 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 415 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 416 | COPY_PHASE_STRIP = NO; 417 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 418 | ENABLE_NS_ASSERTIONS = NO; 419 | ENABLE_STRICT_OBJC_MSGSEND = YES; 420 | GCC_C_LANGUAGE_STANDARD = gnu99; 421 | GCC_NO_COMMON_BLOCKS = YES; 422 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 423 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 424 | GCC_WARN_UNDECLARED_SELECTOR = YES; 425 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 426 | GCC_WARN_UNUSED_FUNCTION = YES; 427 | GCC_WARN_UNUSED_VARIABLE = YES; 428 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 429 | MTL_ENABLE_DEBUG_INFO = NO; 430 | SDKROOT = iphoneos; 431 | TARGETED_DEVICE_FAMILY = "1,2"; 432 | VALIDATE_PRODUCT = YES; 433 | }; 434 | name = Release; 435 | }; 436 | 46F6AE7B1C5F557B0074ECE7 /* Debug */ = { 437 | isa = XCBuildConfiguration; 438 | buildSettings = { 439 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 440 | INFOPLIST_FILE = Observing/Info.plist; 441 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 442 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 443 | PRODUCT_BUNDLE_IDENTIFIER = com.minggo.observing.Observing; 444 | PRODUCT_NAME = "$(TARGET_NAME)"; 445 | }; 446 | name = Debug; 447 | }; 448 | 46F6AE7C1C5F557B0074ECE7 /* Release */ = { 449 | isa = XCBuildConfiguration; 450 | buildSettings = { 451 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 452 | INFOPLIST_FILE = Observing/Info.plist; 453 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 454 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 455 | PRODUCT_BUNDLE_IDENTIFIER = com.minggo.observing.Observing; 456 | PRODUCT_NAME = "$(TARGET_NAME)"; 457 | }; 458 | name = Release; 459 | }; 460 | 46F6AE7E1C5F557B0074ECE7 /* Debug */ = { 461 | isa = XCBuildConfiguration; 462 | buildSettings = { 463 | BUNDLE_LOADER = "$(TEST_HOST)"; 464 | INFOPLIST_FILE = ObservingTests/Info.plist; 465 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 466 | PRODUCT_BUNDLE_IDENTIFIER = com.minggo.observing.ObservingTests; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Observing.app/Observing"; 469 | }; 470 | name = Debug; 471 | }; 472 | 46F6AE7F1C5F557B0074ECE7 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | buildSettings = { 475 | BUNDLE_LOADER = "$(TEST_HOST)"; 476 | INFOPLIST_FILE = ObservingTests/Info.plist; 477 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 478 | PRODUCT_BUNDLE_IDENTIFIER = com.minggo.observing.ObservingTests; 479 | PRODUCT_NAME = "$(TARGET_NAME)"; 480 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Observing.app/Observing"; 481 | }; 482 | name = Release; 483 | }; 484 | 46F6AE811C5F557B0074ECE7 /* Debug */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | INFOPLIST_FILE = ObservingUITests/Info.plist; 488 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 489 | PRODUCT_BUNDLE_IDENTIFIER = com.minggo.observing.ObservingUITests; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | TEST_TARGET_NAME = Observing; 492 | USES_XCTRUNNER = YES; 493 | }; 494 | name = Debug; 495 | }; 496 | 46F6AE821C5F557B0074ECE7 /* Release */ = { 497 | isa = XCBuildConfiguration; 498 | buildSettings = { 499 | INFOPLIST_FILE = ObservingUITests/Info.plist; 500 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 501 | PRODUCT_BUNDLE_IDENTIFIER = com.minggo.observing.ObservingUITests; 502 | PRODUCT_NAME = "$(TARGET_NAME)"; 503 | TEST_TARGET_NAME = Observing; 504 | USES_XCTRUNNER = YES; 505 | }; 506 | name = Release; 507 | }; 508 | /* End XCBuildConfiguration section */ 509 | 510 | /* Begin XCConfigurationList section */ 511 | 46F6AE481C5F557A0074ECE7 /* Build configuration list for PBXProject "Observing" */ = { 512 | isa = XCConfigurationList; 513 | buildConfigurations = ( 514 | 46F6AE781C5F557B0074ECE7 /* Debug */, 515 | 46F6AE791C5F557B0074ECE7 /* Release */, 516 | ); 517 | defaultConfigurationIsVisible = 0; 518 | defaultConfigurationName = Release; 519 | }; 520 | 46F6AE7A1C5F557B0074ECE7 /* Build configuration list for PBXNativeTarget "Observing" */ = { 521 | isa = XCConfigurationList; 522 | buildConfigurations = ( 523 | 46F6AE7B1C5F557B0074ECE7 /* Debug */, 524 | 46F6AE7C1C5F557B0074ECE7 /* Release */, 525 | ); 526 | defaultConfigurationIsVisible = 0; 527 | defaultConfigurationName = Release; 528 | }; 529 | 46F6AE7D1C5F557B0074ECE7 /* Build configuration list for PBXNativeTarget "ObservingTests" */ = { 530 | isa = XCConfigurationList; 531 | buildConfigurations = ( 532 | 46F6AE7E1C5F557B0074ECE7 /* Debug */, 533 | 46F6AE7F1C5F557B0074ECE7 /* Release */, 534 | ); 535 | defaultConfigurationIsVisible = 0; 536 | defaultConfigurationName = Release; 537 | }; 538 | 46F6AE801C5F557B0074ECE7 /* Build configuration list for PBXNativeTarget "ObservingUITests" */ = { 539 | isa = XCConfigurationList; 540 | buildConfigurations = ( 541 | 46F6AE811C5F557B0074ECE7 /* Debug */, 542 | 46F6AE821C5F557B0074ECE7 /* Release */, 543 | ); 544 | defaultConfigurationIsVisible = 0; 545 | defaultConfigurationName = Release; 546 | }; 547 | /* End XCConfigurationList section */ 548 | }; 549 | rootObject = 46F6AE451C5F557A0074ECE7 /* Project object */; 550 | } 551 | -------------------------------------------------------------------------------- /Observing/Observing.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Observing/Observing/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Observing/Observing/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Observing/Observing/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /Observing/Observing/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 30 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Observing/Observing/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 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 65 | 75 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 226 | 235 | 244 | 253 | 262 | 273 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | -------------------------------------------------------------------------------- /Observing/Observing/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Observing/Observing/KVCViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // KVVViewController.h 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KVCViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Observing/Observing/KVCViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // KVVViewController.m 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import "KVCViewController.h" 10 | #import "LaughingSir.h" 11 | 12 | @interface KVCViewController () 13 | @property (weak, nonatomic) IBOutlet UITextField *answerTf; 14 | 15 | - (IBAction)answer:(id)sender; 16 | 17 | @end 18 | 19 | @implementation KVCViewController{ 20 | LaughingSir *laughingSir; 21 | } 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | laughingSir = [LaughingSir new]; 26 | laughingSir.name = @"梁笑棠"; 27 | laughingSir.famous = @"一日警察,一世警察"; 28 | } 29 | 30 | NSString* exchangeName(LaughingSir *laughingSir){ 31 | 32 | NSString *preName = [laughingSir valueForKey:@"name"]; 33 | NSLog(@"laughing的旧名字:%@",preName); 34 | 35 | [laughingSir setValue:@"laughing 哥" forKey:@"name"]; 36 | 37 | NSString *newName = [laughingSir valueForKey:@"name"]; 38 | NSLog(@"laughing的新名字:%@",newName); 39 | 40 | return newName; 41 | } 42 | 43 | 44 | 45 | 46 | - (void)didReceiveMemoryWarning { 47 | [super didReceiveMemoryWarning]; 48 | 49 | } 50 | 51 | 52 | - (IBAction)answer:(id)sender { 53 | 54 | NSString *newName = exchangeName(laughingSir); 55 | NSString *famous = [laughingSir valueForKey:@"famous"]; 56 | self.answerTf.text = [NSString stringWithFormat:@"%@,%@",newName,famous]; 57 | 58 | } 59 | @end 60 | -------------------------------------------------------------------------------- /Observing/Observing/KVOViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // KVOViewController.h 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KVOViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Observing/Observing/KVOViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // KVOViewController.m 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import "KVOViewController.h" 10 | #import "LaughingSir.h" 11 | #import "YiTian.h" 12 | 13 | @interface KVOViewController () 14 | - (IBAction)watchOver:(id)sender; 15 | @property (weak, nonatomic) IBOutlet UITextField *narcoticsTf; 16 | 17 | @end 18 | 19 | @implementation KVOViewController{ 20 | YiTian *yiTian; 21 | LaughingSir *laughingSir; 22 | 23 | } 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | yiTian = [YiTian new]; 28 | } 29 | 30 | - (void)didReceiveMemoryWarning { 31 | [super didReceiveMemoryWarning]; 32 | 33 | } 34 | - (IBAction)watchOver:(id)sender { 35 | if (laughingSir==nil) { 36 | laughingSir = [[LaughingSir alloc] initWithYiTian:yiTian]; 37 | laughingSir.delegate = self; 38 | 39 | } 40 | //[laughingSir watchOverYiTian:yiTian]; 41 | 42 | } 43 | 44 | #pragma mark - LaughingReportDelegate 45 | -(void)reportYitian:(NSUInteger)narcotics{ 46 | self.narcoticsTf.text = [NSString stringWithFormat:@"%iKg",narcotics]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Observing/Observing/LaughingSir.h: -------------------------------------------------------------------------------- 1 | // 2 | // LaughingSir.h 3 | // Observing 4 | // 梁笑棠 5 | // Created by minggo on 16/2/22. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | @class YiTian; 11 | 12 | @protocol LaughingReportDelegate 13 | 14 | -(void)reportYitian:(NSUInteger)narcotics; 15 | 16 | @end 17 | 18 | @interface LaughingSir : NSObject 19 | 20 | @property(nonatomic,copy) NSString *name; 21 | @property(nonatomic,copy) NSString *famous; 22 | @property(nonatomic,retain) YiTian *yiTian; 23 | @property(nonatomic,retain) id delegate; 24 | 25 | //-(void)watchOverYiTian:(YiTian *)yiTian; 26 | 27 | -(instancetype)initWithYiTian:(YiTian *)yiTian; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Observing/Observing/LaughingSir.m: -------------------------------------------------------------------------------- 1 | // 2 | // LaughingSir.m 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/22. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import "LaughingSir.h" 10 | #import "YiTian.h" 11 | 12 | @implementation LaughingSir 13 | 14 | 15 | -(instancetype)initWithYiTian:(YiTian *)yiTian{ 16 | self = [super init]; 17 | 18 | self.yiTian = yiTian; 19 | [self.yiTian addObserver:self forKeyPath:@"narcotics" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil]; 20 | 21 | return self; 22 | } 23 | 24 | //-(void)watchOverYiTian:(YiTian *)yiTian { 25 | // self.yiTian = yiTian; 26 | // [self.yiTian addObserver:self forKeyPath:@"narcotics" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil]; 27 | //} 28 | 29 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ 30 | 31 | if([keyPath isEqualToString:@"narcotics"]){ 32 | 33 | NSNumber *narcoticsN = [change objectForKey:@"new"];//修改之后的最新值 34 | NSInteger narcotics = [narcoticsN integerValue]; 35 | if (narcotics>0) { 36 | if (self.delegate!=nil&&[self.delegate respondsToSelector:@selector(reportYitian:)]) { 37 | [self.delegate reportYitian:narcotics]; 38 | } 39 | } 40 | } 41 | } 42 | 43 | - (void)dealloc{ 44 | //移除观察者 45 | [self.yiTian removeObserver:self forKeyPath:@"narcotics"]; 46 | } 47 | 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Observing/Observing/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Observing/Observing/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view, typically from a nib. 20 | } 21 | 22 | - (void)didReceiveMemoryWarning { 23 | [super didReceiveMemoryWarning]; 24 | // Dispose of any resources that can be recreated. 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Observing/Observing/YiTian.h: -------------------------------------------------------------------------------- 1 | // 2 | // YiTian.h 3 | // Observing 4 | // 5 | // Created by minggo on 16/3/31. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YiTian : NSObject 12 | @property(nonatomic,assign) NSInteger narcotics;//毒品 13 | -(void)makeNarcotics; 14 | @end 15 | -------------------------------------------------------------------------------- /Observing/Observing/YiTian.m: -------------------------------------------------------------------------------- 1 | // 2 | // YiTian.m 3 | // Observing 4 | // 亦天 5 | // Created by minggo on 16/3/31. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import "YiTian.h" 10 | 11 | @implementation YiTian{ 12 | NSTimer *timer; 13 | } 14 | 15 | 16 | -(instancetype)init{ 17 | self = [super init]; 18 | timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(makeNarcotics) userInfo:nil repeats:YES]; 19 | 20 | return self; 21 | } 22 | 23 | -(void)makeNarcotics { 24 | 25 | int narcotics = self.narcotics; 26 | if (narcotics==20) { 27 | [timer invalidate]; 28 | } 29 | [self setNarcotics:++narcotics]; 30 | NSLog(@"亦天制毒了%iKg",self.narcotics); 31 | } 32 | @end 33 | -------------------------------------------------------------------------------- /Observing/Observing/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Observing 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Observing/ObservingTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Observing/ObservingTests/ObservingTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObservingTests.m 3 | // ObservingTests 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ObservingTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ObservingTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Observing/ObservingUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Observing/ObservingUITests/ObservingUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObservingUITests.m 3 | // ObservingUITests 4 | // 5 | // Created by minggo on 16/2/1. 6 | // Copyright © 2016年 minggo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ObservingUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ObservingUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##微信公众号: 2 | 3 | ![学习流程图](https://github.com/minggo620/iOSRuntimeLearn/blob/master/picture/gongzhonghao.jpg?raw=true) 4 | #谈KVC、KVO(重点观察者模式)机制编程 5 | [![Support](https://img.shields.io/badge/support-iOS%207%2B%20-blue.svg?style=flat)](https://www.apple.com/nl/ios/)  6 | [![Travis](https://img.shields.io/travis/rust-lang/rust.svg)]() 7 | [![GitHub release](https://img.shields.io/github/release/qubyte/rubidium.svg)]() 8 | [![Github All Releases](https://img.shields.io/badge/download-6M Total-green.svg)](https://github.com/minggo620/iOSObserving.git) 9 | 一不小心,小明在《跟着贝尔去冒险》这个真人秀节目中看到了“一日警察,一世警察”的Laughing哥,整个节目除了贝尔吃牛睾丸都不用刀叉的不雅餐饮文化外,还是镜头少普通话跟小明一样烂的Laughing Sir那种冷静和沉着稳定留下了深刻印象,不由想起电视剧《学警狙击》中为了不暴露钟立文的身份,要求向自己补一枪的警匪卧底巅峰推动者--Laughing 哥。 10 | 那么,卧底这样的工作,在我们程序里有没有呢?答案是肯定的,观察者模式。 11 | 12 | 13 | ![文章内容思维导图](http://upload-images.jianshu.io/upload_images/1252638-2d492cca12bcbd50.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 14 | 15 | ###一.基本概念 16 | #####1)KVC概念 17 | >1. KVC全称Key-value coding. 18 | 2. 一个非正式的Protocol,提供一种机制来间接访问对象的属性. 19 | **官方文档提供对KVC很准确的描述** 20 | >Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties, rather than through invocation of an accessor method or accessing them directly through instance variables. In essence, key-value coding defines the patterns and method signatures that your application’s accessor methods implement. 21 | 22 | #####2)KVO概念 23 | >1. KVO全称Key-Value Observing。 24 | 2. 典型的观察者模式承载者。 25 | 3. 基于监控键值发生变化,通知观察者。 26 | 4. KVO 就是基于 KVC 实现的关键技术之一。 27 | **官方文档提供对KVO很准确的描述** 28 | >Key-value observing provides a mechanism that allows objects to be notified of changes to specific properties of other objects. It is particularly useful for communication between model and controller layers in an application. 29 | 30 | ###二.KVC和KVO的作用 31 | >Laughing哥上场了,先看看怎么做卧底,首先,Laughing哥先得符合古惑仔行为准则混入黑帮;接着,除了放高利贷和Disco业务外最重的是挤兑从台湾出狱的世孝,选择站在亦天内心的一边得到足够多的信任;最后,凭借“一日警察,一世警察”赤诚初心,秉公执法端掉亦天和制毒窝点。 32 | 33 | 那么,你觉度Laughing Sir的作用是什么? 34 | 35 | **1. 接近需要得到信息隐秘或不隐秘的使用场所。** 36 | **2. 直接监视信息的变化。** 37 | **3. 当产生了有用的信息后,那马上通知汇报。** 38 | 39 | 如果亦天制作的毒品比作信息,普通警察只能通过get方式属性,更重要是不知道他什么时候发生了变化。卧底Laughing Sir完美扮演的就是KVC和KVO机制,为什么说完美?KVC是可以直接通过路径获取对应的键的值,KVO的观察通知部分就对应Laughing Sir的监视和汇报,如果Laughing Sir变节了或者没有意志做下去了,那就只能是KVC能获取到信息,但不能通知上级信息的变化,就没有了一个经典的卧底角色Laughing了。 40 | ###三.JAVA中的观察着模式 41 | Sun公司早早就把观察者模式视为重要的模式,并在Java中提供方便的接口Observer和类Observable。这个地方注意一下,Observer是一个接口,Observable是一个类。因为很容易先入为主,XXXable第一反应是接口。如果看过《设计模式之禅》这本书的人,自然想起书中举的例子是李斯监视同窗韩非子的一举一动汇报给秦始皇。并且书中的Observer和Observable自定义定义刚好相反,注意下即可。为什么提Java,继续看吧。 42 | 43 | ###四.代码实现 44 | ####1. KVC属性读取和修改 45 | #####1)Sense: 46 | 警官:梁笑棠,从今天开始 ,你的生命属于社会的,清楚吗? 47 | Laughing Sir:清楚。 48 | 警官:出了这个学堂,你要叫Laughing 哥,记好了吗? 49 | Laughing Sir:Yes sir。 50 | 警官:你妹,大声点。 51 | Laughing Sir:_____ 52 | 53 | 程序中,Laughing Sir被派于卧底工作前,需要把`Laughing Sir`的名字属性值更换成`Laughing哥`.我们就从这个地方开始练练手预热做卧底的体验吧。 54 | #####2)Step: 55 | ①通过路径方式获取属性值 56 | 57 | NSString *preName = [laughingSir valueForKey:@"name"]; 58 | 59 | ②修改属性值 60 | 61 | [laughingSir setValue:@"laughing 哥" forKey:@"name"]; 62 | 63 | #####3)Show Code: 64 | 65 | NSString* exchangeName(LaughingSir *laughingSir){ 66 | 67 | NSString *preName = [laughingSir valueForKey:@"name"]; 68 | NSLog(@"laughing的旧名字:%@",preName); 69 | 70 | [laughingSir setValue:@"laughing 哥" forKey:@"name"]; 71 | 72 | NSString *newName = [laughingSir valueForKey:@"name"]; 73 | NSLog(@"laughing的新名字:%@",newName); 74 | 75 | return newName; 76 | } 77 | 78 | 79 | ####2.KVO观察者模式演绎 80 | #####1)Sense: 81 | 亦天可能进行制毒。。。 82 | Laughing Sir开始监控亦天 83 | 报告上级亦天制毒数:___ 84 | 程序中,Laughing Sir开始观察YiTian这个实体类中的narcotics属性,一旦亦天制作出毒品,就马上observeValueForKeyPath通知上级,看看如下的具体实现。 85 | #####2)Step: 86 | ①对被观察者添加观察 87 | 88 | [self.yiTian addObserver:self forKeyPath:@"narcotics" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil]; 89 | 90 | ②实现观察结果处理方法 91 | 92 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ 93 | //汇报上级 94 | } 95 | 96 | #####3)Show Code: 97 | 98 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ 99 | if([keyPath isEqualToString:@"narcotics"]){ 100 | 101 | NSNumber *narcoticsN = [change objectForKey:@"new"];//修改之后的最新值 102 | NSInteger narcotics = [narcoticsN integerValue]; 103 | if (narcotics>0) { 104 | if (self.delegate!=nil&&[self.delegate respondsToSelector:@selector(reportYitian:)]) { 105 | [self.delegate reportYitian:narcotics]; 106 | } 107 | } 108 | } 109 | } 110 | 注意:留意下[change objectForKey:@"new"]其中这个new是指新赋予narcotics这个属性的值,当然也有一个old而不是[change objectForKey:@"narcotics"];narcotics是毒品意思。 111 | 112 | ####3.Java实现观察者模式 113 | 这里我就直接显示关键代码了,不做过多说明,对比了解和学习。 114 | 115 | /** 116 | * 亦天实体类 117 | * @author minggo 118 | * @time 2016年4月1日 上午10:24:15 119 | */ 120 | public class YITian extends Observable { 121 | 122 | private Observer observer; 123 | private int narcotics; 124 | 125 | @Override 126 | public synchronized void addObserver(Observer o) { 127 | super.addObserver(o); 128 | this.observer = o; 129 | } 130 | 131 | public void MakeNarcotics(){ 132 | for (int i = 0; i <3; i++) { 133 | narcotics++; 134 | if (observer!=null) { 135 | observer.update(this, narcotics); 136 | } 137 | } 138 | } 139 | 140 | } 141 | 留意Laughing Sir实体类的@override方法 142 | 143 | /** 144 | * Laughing Sir实体类 145 | * @author minggo 146 | * @time 2016年4月1日 上午9:58:36 147 | */ 148 | public class LaughingSir implements Observer{ 149 | @Override 150 | public void update(Observable o, Object arg) { 151 | if (o instanceof YITian) { 152 | System.out.println("监视到亦天制毒"+arg+"kg"); 153 | } 154 | } 155 | public void watchOverYiTian(YITian yiTian){ 156 | yiTian.addObserver(this); 157 | } 158 | } 159 | 160 | 最后是测试main方法 161 | 162 | /** 163 | * 观察者模式 164 | * @author minggo 165 | * @time 2016年4月1日 上午10:36:37 166 | */ 167 | public class TestOberving { 168 | 169 | public static void main(String[] args) { 170 | 171 | YITian yiTian = new YITian(); 172 | LaughingSir laughingSir = new LaughingSir(); 173 | 174 | //Laughing Sir卧底开始监视亦天的一举一动 175 | laughingSir.watchOverYiTian(yiTian); 176 | System.out.println("Laughing Sir卧底开始监视亦天的一举一动"); 177 | 178 | System.out.println("-----------亦天开始制作毒品--------"); 179 | //亦天开始制毒 180 | yiTian.MakeNarcotics(); 181 | System.out.println("-----------亦天结束制作毒品--------"); 182 | } 183 | } 184 | 185 | ###五.现状下观察者模式的重要性 186 | 就犹如Laughing哥这样的角色,观察者模式在实际应用中起到重要的作用。无论你之前发现了,还是现在察觉到它的不可忽视。移动开发的MVVM开发架构思想中的重要解耦页面部分,就是观察者模式实现数据绑定,即时刷新数据。这个在iOS中KVO和Android使用Java的Observer接口都异曲同工之意,RxJava的响应是编程的基本思想也是观察者模式之艺术。 187 | 188 | 现状下的热门的移动开发的关键字,透漏出观察者模式显得越来越重要。其中就包括面试门槛,曾经面试过Android开发者还是iOS开发者,问到观察者这个模式可有了解?有回答iOS观察就是KVO,Java的就是在被观察对象添加回调接口,也有说过《设计模式之禅》中的韩非子被李斯监视的例子。 189 | 190 | 今天,有多了一个,Laughing哥卧底神话,个人感情建议使用这个例子,呵呵~。 191 | 192 | ###六.效果图更直观 193 | ![效果图](http://upload-images.jianshu.io/upload_images/1252638-596cd6fc268d7d51.gif?imageMogr2/auto-orient/strip) 194 | ###七.源码下载地址更详细 195 | #####*[https://github.com/minggo620/iOSObserving.git](https://github.com/minggo620/iOSObserving.git)* 196 | 197 | ####Laughing哥如果见到我,估计会说:“小明,其实我真实的名字叫~谢天华!” 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /picture/observing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minggo620/iOSObserving/184b30ed4501601a9dcd4b5c1a9682d8df0475f0/picture/observing.gif -------------------------------------------------------------------------------- /picture/observing1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minggo620/iOSObserving/184b30ed4501601a9dcd4b5c1a9682d8df0475f0/picture/observing1.png --------------------------------------------------------------------------------