From d644a1df82695fbb6a343a446fb4ec5f7b44503f Mon Sep 17 00:00:00 2001 From: pro648 <AugSpan@gmail.com> Date: Mon, 25 Jan 2021 20:11:45 +0800 Subject: [PATCH] =?UTF-8?q?KVC=E3=80=81KVO=E7=9A=84=E6=9C=AC=E8=B4=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project.pbxproj" | 387 ++++++++++++++++++ .../contents.xcworkspacedata" | 7 + .../AppDelegate.h" | 14 + .../AppDelegate.m" | 40 ++ .../AccentColor.colorset/Contents.json" | 11 + .../AppIcon.appiconset/Contents.json" | 98 +++++ .../Assets.xcassets/Contents.json" | 6 + .../Base.lproj/LaunchScreen.storyboard" | 25 ++ .../Base.lproj/Main.storyboard" | 24 ++ .../Info.plist" | 66 +++ .../KVC/Observer.h" | 16 + .../KVC/Observer.m" | 16 + .../KVC/Person.h" | 31 ++ .../KVC/Person.m" | 51 +++ .../KVO/Child.h" | 18 + .../KVO/Child.m" | 33 ++ .../KVO/NSKVONotifying_Child.h" | 16 + .../KVO/NSKVONotifying_Child.m" | 40 ++ .../SceneDelegate.h" | 15 + .../SceneDelegate.m" | 57 +++ .../ViewController.h" | 14 + .../ViewController.m" | 148 +++++++ .../main.m" | 18 + .../README.md" | 18 + README.md | 1 + 25 files changed, 1170 insertions(+) create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.pbxproj" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.xcworkspace/contents.xcworkspacedata" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.h" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AccentColor.colorset/Contents.json" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AppIcon.appiconset/Contents.json" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/Contents.json" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/LaunchScreen.storyboard" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/Main.storyboard" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Info.plist" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.h" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.h" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.h" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.h" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.h" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.h" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/main.m" create mode 100644 "KVC&KVO\347\232\204\346\234\254\350\264\250/README.md" diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.pbxproj" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.pbxproj" new file mode 100644 index 0000000..7c973b4 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.pbxproj" @@ -0,0 +1,387 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 0D5B188825B9273500F1D301 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D5B188725B9273500F1D301 /* AppDelegate.m */; }; + 0D5B188B25B9273500F1D301 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D5B188A25B9273500F1D301 /* SceneDelegate.m */; }; + 0D5B188E25B9273500F1D301 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D5B188D25B9273500F1D301 /* ViewController.m */; }; + 0D5B189125B9273500F1D301 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D5B188F25B9273500F1D301 /* Main.storyboard */; }; + 0D5B189325B9273600F1D301 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0D5B189225B9273600F1D301 /* Assets.xcassets */; }; + 0D5B189625B9273600F1D301 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D5B189425B9273600F1D301 /* LaunchScreen.storyboard */; }; + 0D5B189925B9273600F1D301 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D5B189825B9273600F1D301 /* main.m */; }; + 0D5B18A225B9275000F1D301 /* Child.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D5B18A125B9275000F1D301 /* Child.m */; }; + 0DB67EF025BE7670007C5DCF /* Person.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB67EEF25BE7670007C5DCF /* Person.m */; }; + 0DB67EF525BE7679007C5DCF /* Observer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB67EF425BE7679007C5DCF /* Observer.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0D5B188325B9273500F1D301 /* KVC&KVO的本质.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "KVC&KVO的本质.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 0D5B188625B9273500F1D301 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; + 0D5B188725B9273500F1D301 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; + 0D5B188925B9273500F1D301 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = "<group>"; }; + 0D5B188A25B9273500F1D301 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = "<group>"; }; + 0D5B188C25B9273500F1D301 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; + 0D5B188D25B9273500F1D301 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; + 0D5B189025B9273500F1D301 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + 0D5B189225B9273600F1D301 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + 0D5B189525B9273600F1D301 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; + 0D5B189725B9273600F1D301 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 0D5B189825B9273600F1D301 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + 0D5B18A025B9275000F1D301 /* Child.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Child.h; sourceTree = "<group>"; }; + 0D5B18A125B9275000F1D301 /* Child.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Child.m; sourceTree = "<group>"; }; + 0D9A098825B9805500AE5BE3 /* NSKVONotifying_Child.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSKVONotifying_Child.h; sourceTree = "<group>"; }; + 0D9A098925B9805500AE5BE3 /* NSKVONotifying_Child.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSKVONotifying_Child.m; sourceTree = "<group>"; }; + 0DB67EEE25BE7670007C5DCF /* Person.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Person.h; sourceTree = "<group>"; }; + 0DB67EEF25BE7670007C5DCF /* Person.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Person.m; sourceTree = "<group>"; }; + 0DB67EF325BE7679007C5DCF /* Observer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Observer.h; sourceTree = "<group>"; }; + 0DB67EF425BE7679007C5DCF /* Observer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Observer.m; sourceTree = "<group>"; }; + 0DB67EF825BEE9D3007C5DCF /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0D5B188025B9273500F1D301 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0D5B187A25B9273500F1D301 = { + isa = PBXGroup; + children = ( + 0DB67EF825BEE9D3007C5DCF /* README.md */, + 0D5B188525B9273500F1D301 /* KVC&KVO的本质 */, + 0D5B188425B9273500F1D301 /* Products */, + ); + sourceTree = "<group>"; + }; + 0D5B188425B9273500F1D301 /* Products */ = { + isa = PBXGroup; + children = ( + 0D5B188325B9273500F1D301 /* KVC&KVO的本质.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + 0D5B188525B9273500F1D301 /* KVC&KVO的本质 */ = { + isa = PBXGroup; + children = ( + 0D5B188625B9273500F1D301 /* AppDelegate.h */, + 0D5B188725B9273500F1D301 /* AppDelegate.m */, + 0D5B188925B9273500F1D301 /* SceneDelegate.h */, + 0D5B188A25B9273500F1D301 /* SceneDelegate.m */, + 0D5B188C25B9273500F1D301 /* ViewController.h */, + 0D5B188D25B9273500F1D301 /* ViewController.m */, + 0DB67EED25BE7625007C5DCF /* KVC */, + 0DB67EEC25BE7619007C5DCF /* KVO */, + 0D5B188F25B9273500F1D301 /* Main.storyboard */, + 0D5B189225B9273600F1D301 /* Assets.xcassets */, + 0D5B189425B9273600F1D301 /* LaunchScreen.storyboard */, + 0D5B189725B9273600F1D301 /* Info.plist */, + 0D5B189825B9273600F1D301 /* main.m */, + ); + path = "KVC&KVO的本质"; + sourceTree = "<group>"; + }; + 0DB67EEC25BE7619007C5DCF /* KVO */ = { + isa = PBXGroup; + children = ( + 0D5B18A025B9275000F1D301 /* Child.h */, + 0D5B18A125B9275000F1D301 /* Child.m */, + 0D9A098825B9805500AE5BE3 /* NSKVONotifying_Child.h */, + 0D9A098925B9805500AE5BE3 /* NSKVONotifying_Child.m */, + ); + path = KVO; + sourceTree = "<group>"; + }; + 0DB67EED25BE7625007C5DCF /* KVC */ = { + isa = PBXGroup; + children = ( + 0DB67EEE25BE7670007C5DCF /* Person.h */, + 0DB67EEF25BE7670007C5DCF /* Person.m */, + 0DB67EF325BE7679007C5DCF /* Observer.h */, + 0DB67EF425BE7679007C5DCF /* Observer.m */, + ); + path = KVC; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0D5B188225B9273500F1D301 /* KVC&KVO的本质 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0D5B189C25B9273600F1D301 /* Build configuration list for PBXNativeTarget "KVC&KVO的本质" */; + buildPhases = ( + 0D5B187F25B9273500F1D301 /* Sources */, + 0D5B188025B9273500F1D301 /* Frameworks */, + 0D5B188125B9273500F1D301 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "KVC&KVO的本质"; + productName = "KVC&KVO的本质"; + productReference = 0D5B188325B9273500F1D301 /* KVC&KVO的本质.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0D5B187B25B9273500F1D301 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1230; + TargetAttributes = { + 0D5B188225B9273500F1D301 = { + CreatedOnToolsVersion = 12.3; + }; + }; + }; + buildConfigurationList = 0D5B187E25B9273500F1D301 /* Build configuration list for PBXProject "KVC&KVO的本质" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0D5B187A25B9273500F1D301; + productRefGroup = 0D5B188425B9273500F1D301 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0D5B188225B9273500F1D301 /* KVC&KVO的本质 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0D5B188125B9273500F1D301 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0D5B189625B9273600F1D301 /* LaunchScreen.storyboard in Resources */, + 0D5B189325B9273600F1D301 /* Assets.xcassets in Resources */, + 0D5B189125B9273500F1D301 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0D5B187F25B9273500F1D301 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0DB67EF025BE7670007C5DCF /* Person.m in Sources */, + 0D5B188E25B9273500F1D301 /* ViewController.m in Sources */, + 0D5B188825B9273500F1D301 /* AppDelegate.m in Sources */, + 0DB67EF525BE7679007C5DCF /* Observer.m in Sources */, + 0D5B189925B9273600F1D301 /* main.m in Sources */, + 0D5B188B25B9273500F1D301 /* SceneDelegate.m in Sources */, + 0D5B18A225B9275000F1D301 /* Child.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 0D5B188F25B9273500F1D301 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0D5B189025B9273500F1D301 /* Base */, + ); + name = Main.storyboard; + sourceTree = "<group>"; + }; + 0D5B189425B9273600F1D301 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0D5B189525B9273600F1D301 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 0D5B189A25B9273600F1D301 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 0D5B189B25B9273600F1D301 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0D5B189D25B9273600F1D301 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "KVC&KVO的本质/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "pro648.KVC-KVO---"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0D5B189E25B9273600F1D301 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "KVC&KVO的本质/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "pro648.KVC-KVO---"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0D5B187E25B9273500F1D301 /* Build configuration list for PBXProject "KVC&KVO的本质" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0D5B189A25B9273600F1D301 /* Debug */, + 0D5B189B25B9273600F1D301 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0D5B189C25B9273600F1D301 /* Build configuration list for PBXNativeTarget "KVC&KVO的本质" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0D5B189D25B9273600F1D301 /* Debug */, + 0D5B189E25B9273600F1D301 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0D5B187B25B9273500F1D301 /* Project object */; +} diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.xcworkspace/contents.xcworkspacedata" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.xcworkspace/contents.xcworkspacedata" new file mode 100644 index 0000000..919434a --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250.xcodeproj/project.xcworkspace/contents.xcworkspacedata" @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:"> + </FileRef> +</Workspace> diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.h" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.h" new file mode 100644 index 0000000..8c19187 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.h" @@ -0,0 +1,14 @@ +// +// AppDelegate.h +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import <UIKit/UIKit.h> + +@interface AppDelegate : UIResponder <UIApplicationDelegate> + + +@end + diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.m" new file mode 100644 index 0000000..652dbfe --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/AppDelegate.m" @@ -0,0 +1,40 @@ +// +// AppDelegate.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + + +#pragma mark - UISceneSession lifecycle + + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; +} + + +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. +} + + +@end diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AccentColor.colorset/Contents.json" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AccentColor.colorset/Contents.json" new file mode 100644 index 0000000..eb87897 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AccentColor.colorset/Contents.json" @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AppIcon.appiconset/Contents.json" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AppIcon.appiconset/Contents.json" new file mode 100644 index 0000000..9221b9b --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/AppIcon.appiconset/Contents.json" @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/Contents.json" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/Contents.json" new file mode 100644 index 0000000..73c0059 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Assets.xcassets/Contents.json" @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/LaunchScreen.storyboard" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/LaunchScreen.storyboard" new file mode 100644 index 0000000..865e932 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/LaunchScreen.storyboard" @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="EHf-IW-A2E"> + <objects> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="53" y="375"/> + </scene> + </scenes> +</document> diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/Main.storyboard" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/Main.storyboard" new file mode 100644 index 0000000..808a21c --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Base.lproj/Main.storyboard" @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="tne-QT-ifu"> + <objects> + <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> + </objects> + </scene> + </scenes> +</document> diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Info.plist" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Info.plist" new file mode 100644 index 0000000..72bf2c4 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/Info.plist" @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>UIApplicationSceneManifest</key> + <dict> + <key>UIApplicationSupportsMultipleScenes</key> + <false/> + <key>UISceneConfigurations</key> + <dict> + <key>UIWindowSceneSessionRoleApplication</key> + <array> + <dict> + <key>UISceneConfigurationName</key> + <string>Default Configuration</string> + <key>UISceneDelegateClassName</key> + <string>SceneDelegate</string> + <key>UISceneStoryboardFile</key> + <string>Main</string> + </dict> + </array> + </dict> + </dict> + <key>UIApplicationSupportsIndirectInputEvents</key> + <true/> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIMainStoryboardFile</key> + <string>Main</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> +</dict> +</plist> diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.h" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.h" new file mode 100644 index 0000000..bdd60a6 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.h" @@ -0,0 +1,16 @@ +// +// Observer.h +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import <Foundation/Foundation.h> + +NS_ASSUME_NONNULL_BEGIN + +@interface Observer : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.m" new file mode 100644 index 0000000..4f985b2 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Observer.m" @@ -0,0 +1,16 @@ +// +// Observer.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import "Observer.h" + +@implementation Observer + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + NSLog(@"%s - %@", __PRETTY_FUNCTION__, change); +} + +@end diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.h" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.h" new file mode 100644 index 0000000..90a5a80 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.h" @@ -0,0 +1,31 @@ +// +// Person.h +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import <Foundation/Foundation.h> + +NS_ASSUME_NONNULL_BEGIN + +@interface Person : NSObject +{ + @public + // 如果没有set方法,按照下面顺序查找。 +// int _age; + int _isAge; + int age; + int isAge; +} + +// 如果没有setAge方法,但有上述成员变量,就会触发KVO。KVO内部实现了willChangeValueForKey didChangeValueForKey。 + +//@property (nonatomic, assign) int age; + +// 如果是只读的,则会查看accessInstanceMethodDirectly返回值,进而决定是否查看成员变量。 +//@property (nonatomic, assign, readonly) int age; + +@end + +NS_ASSUME_NONNULL_END diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.m" new file mode 100644 index 0000000..1a2e7b6 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC/Person.m" @@ -0,0 +1,51 @@ +// +// Person.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import "Person.h" + +@implementation Person + +// MARK: - setValue:forKey: + +//- (void)setAge:(int)age { +// _age = age; +// NSLog(@"%s %d", __PRETTY_FUNCTION__, age); +//} +// +//- (void)_setAge:(int)age { +// _age = age; +// NSLog(@"%s %d", __PRETTY_FUNCTION__, age); +//} + +// MARK: - valueForKey: + +- (int)getAge { + return 22; +} + +// 没有访问器方法,是否运行直接访问变量。默认YES。 ++ (BOOL)accessInstanceVariablesDirectly { + return YES; +// return NO; +} + +// 可以验证内部实现了willChangeValueForKey: didChangeValueForKey: +- (void)willChangeValueForKey:(NSString *)key { + [super willChangeValueForKey:key]; + + NSLog(@"%s %@", __PRETTY_FUNCTION__, key); +} + +- (void)didChangeValueForKey:(NSString *)key { + NSLog(@"%s - begin - %@", __PRETTY_FUNCTION__, key); + + [super didChangeValueForKey:key]; + + NSLog(@"%s - end - %@", __PRETTY_FUNCTION__, key); +} + +@end diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.h" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.h" new file mode 100644 index 0000000..a903aec --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.h" @@ -0,0 +1,18 @@ +// +// Child.h +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/21. +// + +#import <Foundation/Foundation.h> + +NS_ASSUME_NONNULL_BEGIN + +@interface Child : NSObject + +@property (nonatomic, assign) int age; + +@end + +NS_ASSUME_NONNULL_END diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.m" new file mode 100644 index 0000000..e031f54 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/Child.m" @@ -0,0 +1,33 @@ +// +// Child.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/21. +// + +#import "Child.h" + +@implementation Child + +- (void)setAge:(int)age { + NSLog(@"begin - setAge:%d", age); + _age = age; + NSLog(@"end - setAge:%d", age); + +// NSLog(@"KVO是否通过重写setAge:方法实现?age:%d", age); +} + +- (void)willChangeValueForKey:(NSString *)key { + NSLog(@"willChangeValueForKey: - begin"); + [super willChangeValueForKey:key]; + NSLog(@"willChangeValueForKey: - end"); +} + +// 验证didChangeValueForKey:调用了KVO +- (void)didChangeValueForKey:(NSString *)key { + NSLog(@"didChangeValueForKey: - begin"); + [super didChangeValueForKey:key]; + NSLog(@"didChangeValueForKey: - end"); +} + +@end diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.h" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.h" new file mode 100644 index 0000000..b6cf9f4 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.h" @@ -0,0 +1,16 @@ +// +// NSKVONotifying_Child.h +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/21. +// + +#import "Child.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface NSKVONotifying_Child : Child + +@end + +NS_ASSUME_NONNULL_END diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.m" new file mode 100644 index 0000000..06d899c --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/KVO/NSKVONotifying_Child.m" @@ -0,0 +1,40 @@ +// +// NSKVONotifying_Child.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/21. +// + +#import "NSKVONotifying_Child.h" +#import <objc/runtime.h> + +@implementation NSKVONotifying_Child + +//- (void)setAge:(int)age { +// _NSSetIntValueAndNotify(); +//} +// +//void _NSSetIntValueAndNotify() { +// [self willChangeValueForKey:@"age"]; +// [super setAge:age]; +// [self didChangeValueForKey:@"age"]; +//} +// +//- (void)didChangeValueForKey:(NSString *)key { +// // 通知监听器,key属性发生了改变。 +// [observer observeValueForKeyPath:key ofObject:self change:nil context:nil]; +//} + +- (Class)class { + return class_getSuperclass(object_getClass(self)); +} + +- (void)dealloc { + // 执行清理工作 +} + +- (BOOL)isKVOA { + return YES; +} + +@end diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.h" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.h" new file mode 100644 index 0000000..5e6c9e8 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.h" @@ -0,0 +1,15 @@ +// +// SceneDelegate.h +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import <UIKit/UIKit.h> + +@interface SceneDelegate : UIResponder <UIWindowSceneDelegate> + +@property (strong, nonatomic) UIWindow * window; + +@end + diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.m" new file mode 100644 index 0000000..7903564 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/SceneDelegate.m" @@ -0,0 +1,57 @@ +// +// SceneDelegate.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import "SceneDelegate.h" + +@interface SceneDelegate () + +@end + +@implementation SceneDelegate + + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). +} + + +- (void)sceneDidDisconnect:(UIScene *)scene { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). +} + + +- (void)sceneDidBecomeActive:(UIScene *)scene { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. +} + + +- (void)sceneWillResignActive:(UIScene *)scene { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). +} + + +- (void)sceneWillEnterForeground:(UIScene *)scene { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. +} + + +- (void)sceneDidEnterBackground:(UIScene *)scene { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. +} + + +@end diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.h" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.h" new file mode 100644 index 0000000..c4e3ef9 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.h" @@ -0,0 +1,14 @@ +// +// ViewController.h +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import <UIKit/UIKit.h> + +@interface ViewController : UIViewController + + +@end + diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.m" new file mode 100644 index 0000000..18df472 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/ViewController.m" @@ -0,0 +1,148 @@ +// +// ViewController.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// +// 详细介绍:https://github.com/pro648/tips/blob/master/sources/KVC%E3%80%81KVO%E7%9A%84%E6%9C%AC%E8%B4%A8.md + +#import "ViewController.h" +#import "Child.h" +#import <objc/runtime.h> +#import "Person.h" +#import "Observer.h" + +@interface ViewController () + +@property (nonatomic, strong) Child *child1; +@property (nonatomic, strong) Child *child2; +@property (nonatomic, strong) Observer *observer; +@property (nonatomic, strong) Person *person; + +@end + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self testKVO]; + [self testKVC]; +} + +// MARK: - KVO + +- (void)testKVO { + self.child1 = [[Child alloc] init]; + self.child1.age = 1; + + self.child2 = [[Child alloc] init]; + self.child2.age = 2; + + // 打印添加观察者前实例对象的isa +// NSLog(@"添加Observer前 child1: %@ - child2: %@", object_getClass(self.child1), object_getClass(self.child2)); + + // 打印添加观察者前,打印setAge:具体实现。 +// NSLog(@"添加Observer前 child1: %p - child2: %p", [self.child1 methodForSelector:@selector(setAge:)], [self.child2 methodForSelector:@selector(setAge:)]); + + // 添加观察者 + [self.child1 addObserver:self + forKeyPath:@"age" + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:@"123context"]; + + // 打印添加观察者后实例对象的isa +// NSLog(@"添加Observer后 child1: %@ - child2: %@", object_getClass(self.child1), object_getClass(self.child2)); + + // 打印添加观察者后,打印setAge:具体实现。 +// NSLog(@"添加Observer后 child1: %p - child2: %p", [self.child1 methodForSelector:@selector(setAge:)], [self.child2 methodForSelector:@selector(setAge:)]); + + // 打印添加观察者后,child1、child2类对象中所有方法 +// [self printMethodList:object_getClass(self.child1)]; +// [self printMethodList:object_getClass(self.child2)]; +} + +// 观察到键值发生改变 +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + NSLog(@"监听到 %@ 的 %@ 属性值发生改变 - %@ - %@", object, keyPath, change, context); +} + +- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { + [self.child1 setAge:11]; + + [self.child2 setAge:22]; +} + +- (void)printMethodList:(Class)cls { + unsigned int methodCount; + // 获取方法数组 + Method *methodList = class_copyMethodList(cls, &methodCount); + + NSMutableString *name = [NSMutableString string]; + for (int i=0; i<methodCount; ++i) { + // 获得方法 + Method method = methodList[i]; + // 获得方法名 + NSString *methodName = NSStringFromSelector(method_getName(method)); + + [name appendString:methodName]; + [name appendString:@", "]; + } + + // C语言中使用copy、create创建的对象需释放。 + free(methodList); + NSLog(@"%@ %@", cls, name); +} + +- (void)printIvarList:(Class)cls { + unsigned int ivarCount; + // 获取ivar数组 + Ivar *ivarList = class_copyIvarList(cls, &ivarCount); + // 存储ivar名 + NSMutableString *ivarNames = [NSMutableString string]; + + // 遍历所有的ivar + for (int i=0; i<ivarCount; ++i) { + // 获得ivar + Ivar ivar = ivarList[i]; + // 获得ivar名 + NSString *methodName = [NSString stringWithUTF8String:ivar_getName(ivar)]; + // 拼接ivar名 + [ivarNames appendString:methodName]; + [ivarNames appendString:@", "]; + } + + // C语言中使用create、copy创建的对象,需释放。 + free(ivarList); + NSLog(@"%@ %@", cls, ivarNames); +} + +// MARK: - KVC + +- (void)testKVC { + self.observer = [[Observer alloc] init]; + self.person = [[Person alloc] init]; + + [self.person addObserver:self.observer + forKeyPath:@"age" + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:NULL]; + +// [self printIvarList:[Person class]]; + [self.person setValue:@10 forKey:@"age"]; + + NSLog(@"age: %@", [self.person valueForKey:@"age"]); + + NSLog(@""); + +} + +- (void)dealloc { + // 移除观察者 + [self.child1 removeObserver:self + forKeyPath:@"age"]; + [self.person removeObserver:self.observer + forKeyPath:@"age"]; +} + +@end diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/main.m" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/main.m" new file mode 100644 index 0000000..f8945fe --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/KVC&KVO\347\232\204\346\234\254\350\264\250/main.m" @@ -0,0 +1,18 @@ +// +// main.m +// KVC&KVO的本质 +// +// Created by pro648 on 2021/1/24. +// + +#import <UIKit/UIKit.h> +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + NSString * appDelegateClassName; + @autoreleasepool { + // Setup code that might create autoreleased objects goes here. + appDelegateClassName = NSStringFromClass([AppDelegate class]); + } + return UIApplicationMain(argc, argv, nil, appDelegateClassName); +} diff --git "a/KVC&KVO\347\232\204\346\234\254\350\264\250/README.md" "b/KVC&KVO\347\232\204\346\234\254\350\264\250/README.md" new file mode 100644 index 0000000..f80f803 --- /dev/null +++ "b/KVC&KVO\347\232\204\346\234\254\350\264\250/README.md" @@ -0,0 +1,18 @@ +### KVC、KVO的本质 + +添加观察者后,KVO利用runtime生成一个`NSKVONOtifying_`子类,并重写set方法。修改属性值时触发KVO。 + +![NSKVONotifying](https://raw.githubusercontent.com/pro648/tips/master/sources/images/21/KVO%26KVCNSKVONotifying_XXX.png) + +使用KVC设值时,`setValue:forKey:`原理如下: + +- 先查找`setKey:`、`_setKey:`方法,如果找到了,直接传递参数,调用方法;如果找不到,进入下一步。 +- 查看`accessInstanceVariableDirectly`方法返回值,如果返回`NO`,即不允许访问成员变量,则调用`setValue:forUndefinedKey:`方法,并抛出`NSUnknownKeyException`异常;如果返回`YES`,进入下一步。 +- 按照`_key`、`_isKey`、`key`、`isKey`顺序查找成员变量,如果找到了成员变量,直接赋值。如果找不到,则调用`setValue:forUndefinedKey:`方法,并抛出`NSUnknownKeyException`异常。 + +![setValueForKey](https://raw.githubusercontent.com/pro648/tips/master/sources/images/21/KVO%26KVCsetValue.png) + +详细介绍查看下面文章: + +<https://github.com/pro648/tips/blob/master/sources/KVC、KVO的本质.md> + diff --git a/README.md b/README.md index 8a45c3f..c3a2e9a 100755 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ iOS学习进程中的demo汇总 | GestureRecognizer | [手势控制:点击、滑动、平移、捏合、旋转、长按、轻扫](https://github.com/pro648/tips/wiki/%E6%89%8B%E5%8A%BF%E6%8E%A7%E5%88%B6%EF%BC%9A%E7%82%B9%E5%87%BB%E3%80%81%E6%BB%91%E5%8A%A8%E3%80%81%E5%B9%B3%E7%A7%BB%E3%80%81%E6%8D%8F%E5%90%88%E3%80%81%E6%97%8B%E8%BD%AC%E3%80%81%E9%95%BF%E6%8C%89%E3%80%81%E8%BD%BB%E6%89%AB) | | IteratorPattern | [迭代器模式 Iterator Pattern](https://github.com/pro648/tips/wiki/%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F-Iterator-Pattern) | | KVC&KVODemo | [KVC和KVO学习笔记](https://github.com/pro648/tips/wiki/KVC%E5%92%8CKVO%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0) | +| KVC&KVO原理 | [KVC、KVO的本质](https://github.com/pro648/tips/blob/master/sources/KVC、KVO的本质.md) | | KeyedArchiver | [数据存储之归档解档 NSKeyedArchiver NSKeyedUnarchiver](https://github.com/pro648/tips/wiki/%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E4%B9%8B%E5%BD%92%E6%A1%A3%E8%A7%A3%E6%A1%A3-NSKeyedArchiver-NSKeyedUnarchiver) | | LinkedList | [链表 LinkedList](https://github.com/pro648/tips/blob/master/sources/%E9%93%BE%E8%A1%A8%20LinkedList.md) | | MementoPattern | [备忘录模式 Memento Pattern](https://github.com/pro648/tips/wiki/%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F-Memento-Pattern)|