From a6f87800aff7e7e8511a0322b2a17c336b7783f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E4=B8=96=E8=B6=85?= Date: Wed, 4 Sep 2019 12:41:05 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E5=A2=9E=E5=8A=A0=E4=B8=8D=E5=90=8C=20Cra?= =?UTF-8?q?sh=20=E9=98=B2=E6=8A=A4=E6=B5=8B=E8=AF=95=E9=A1=B5=E9=9D=A2=202?= =?UTF-8?q?.=20=E5=A2=9E=E5=8A=A0=20KVC=20Crash=20=E9=98=B2=E6=8A=A4?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../YSC-Avoid-Crash.xcodeproj/project.pbxproj | 216 +++++++++++++++--- .../Base.lproj/LaunchScreen.storyboard | 16 +- .../Base.lproj/Main.storyboard | 15 +- .../Examples/Base/BaseDefine.h | 15 ++ .../Examples/Base/BaseViewController.h | 20 ++ .../Examples/Base/BaseViewController.m | 92 ++++++++ .../Examples/Containers/TestContainersVC.h | 15 ++ .../Examples/Containers/TestContainersVC.m | 32 +++ .../Examples/KVC/KVCCrashObject.h | 21 ++ .../Examples/KVC/KVCCrashObject.m | 13 ++ .../Examples/KVC/TestKVCCrashVC.h | 15 ++ .../Examples/KVC/TestKVCCrashVC.m | 126 ++++++++++ .../KVO/KVOCrashObject.h} | 6 +- .../Examples/KVO/KVOCrashObject.m | 13 ++ .../Examples/KVO/TestKVOCrashVC.h | 15 ++ .../Examples/KVO/TestKVOCrashVC.m | 176 ++++++++++++++ .../Examples/NSNull/TestNullVC.h | 15 ++ .../Examples/NSNull/TestNullVC.m | 32 +++ .../Notification/NotificationReceiver.h} | 10 +- .../Notification/NotificationReceiver.m | 29 +++ .../Notification/TestNotificationCrashVC.h | 14 ++ .../Notification/TestNotificationCrashVC.m | 22 ++ .../Examples/Timer/TestTimerCrashVC.h | 15 ++ .../Examples/Timer/TestTimerCrashVC.m | 32 +++ .../Unrecognized Selector/SelectorObject.h | 18 ++ .../Unrecognized Selector/SelectorObject.m | 13 ++ .../TestUnrecognizedSelVC.h | 15 ++ .../TestUnrecognizedSelVC.m | 94 ++++++++ .../YSC-Avoid-Crash/KVOCrashObjc.m | 13 -- .../YSC-Avoid-Crash/ViewController.m | 141 +++++++----- .../YSCDefender/NSObject+KVCDefender.h | 17 ++ .../YSCDefender/NSObject+KVCDefender.m | 54 +++++ .../{ => YSCDefender}/NSObject+KVODefender.h | 2 + .../{ => YSCDefender}/NSObject+KVODefender.m | 26 +-- .../NSObject+MethodSwizzling.h | 16 ++ .../NSObject+MethodSwizzling.m | 1 + .../NSObject+SelectorDefender.h | 0 .../NSObject+SelectorDefender.m | 7 +- YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.m | 13 -- 39 files changed, 1235 insertions(+), 170 deletions(-) create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseDefine.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.m rename YSC-Avoid-Crash/YSC-Avoid-Crash/{KVOCrashObjc.h => Examples/KVO/KVOCrashObject.h} (68%) create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/KVOCrashObject.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.m rename YSC-Avoid-Crash/YSC-Avoid-Crash/{YSCObject.h => Examples/Notification/NotificationReceiver.h} (58%) create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/NotificationReceiver.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.m delete mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/KVOCrashObjc.m create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.h create mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.m rename YSC-Avoid-Crash/YSC-Avoid-Crash/{ => YSCDefender}/NSObject+KVODefender.h (99%) rename YSC-Avoid-Crash/YSC-Avoid-Crash/{ => YSCDefender}/NSObject+KVODefender.m (93%) rename YSC-Avoid-Crash/YSC-Avoid-Crash/{ => YSCDefender}/NSObject+MethodSwizzling.h (63%) rename YSC-Avoid-Crash/YSC-Avoid-Crash/{ => YSCDefender}/NSObject+MethodSwizzling.m (99%) rename YSC-Avoid-Crash/YSC-Avoid-Crash/{ => YSCDefender}/NSObject+SelectorDefender.h (100%) rename YSC-Avoid-Crash/YSC-Avoid-Crash/{ => YSCDefender}/NSObject+SelectorDefender.m (95%) delete mode 100644 YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.m diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash.xcodeproj/project.pbxproj b/YSC-Avoid-Crash/YSC-Avoid-Crash.xcodeproj/project.pbxproj index 10dba11..bc20b8f 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash.xcodeproj/project.pbxproj +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash.xcodeproj/project.pbxproj @@ -7,23 +7,64 @@ objects = { /* Begin PBXBuildFile section */ - 950630B0230AAA18001E5349 /* KVOCrashObjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 950630AF230AAA18001E5349 /* KVOCrashObjc.m */; }; + 9534591A230FBF6C00767E14 /* KVOCrashObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345919230FBF6C00767E14 /* KVOCrashObject.m */; }; + 9534592D231677CB00767E14 /* KVCCrashObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 9534592C231677CB00767E14 /* KVCCrashObject.m */; }; + 953459392316AEBD00767E14 /* NSObject+SelectorDefender.m in Sources */ = {isa = PBXBuildFile; fileRef = 953459322316AEBC00767E14 /* NSObject+SelectorDefender.m */; }; + 9534593A2316AEBD00767E14 /* NSObject+MethodSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 953459362316AEBC00767E14 /* NSObject+MethodSwizzling.m */; }; + 9534593B2316AEBD00767E14 /* NSObject+KVODefender.m in Sources */ = {isa = PBXBuildFile; fileRef = 953459372316AEBD00767E14 /* NSObject+KVODefender.m */; }; + 9534593C2316AEBD00767E14 /* NSObject+KVCDefender.m in Sources */ = {isa = PBXBuildFile; fileRef = 953459382316AEBD00767E14 /* NSObject+KVCDefender.m */; }; + 9534594D231DF76900767E14 /* NotificationReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = 9534594C231DF76900767E14 /* NotificationReceiver.m */; }; + 95345964231F52B700767E14 /* TestUnrecognizedSelVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345963231F52B700767E14 /* TestUnrecognizedSelVC.m */; }; + 95345967231F52D000767E14 /* TestKVOCrashVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345966231F52D000767E14 /* TestKVOCrashVC.m */; }; + 9534596A231F52E900767E14 /* TestKVCCrashVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345969231F52E900767E14 /* TestKVCCrashVC.m */; }; + 9534596D231F530100767E14 /* TestNotificationCrashVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 9534596C231F530100767E14 /* TestNotificationCrashVC.m */; }; + 95345970231F531E00767E14 /* TestTimerCrashVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 9534596F231F531E00767E14 /* TestTimerCrashVC.m */; }; + 95345973231F533200767E14 /* TestContainersVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345972231F533200767E14 /* TestContainersVC.m */; }; + 95345976231F534400767E14 /* TestNullVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345975231F534400767E14 /* TestNullVC.m */; }; + 95345979231F57EE00767E14 /* BaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345978231F57EE00767E14 /* BaseViewController.m */; }; + 95345984231F619A00767E14 /* SelectorObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 95345983231F619A00767E14 /* SelectorObject.m */; }; 953F56E223055D1A00710599 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 953F56E123055D1A00710599 /* AppDelegate.m */; }; 953F56E523055D1A00710599 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 953F56E423055D1A00710599 /* ViewController.m */; }; 953F56E823055D1A00710599 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 953F56E623055D1A00710599 /* Main.storyboard */; }; 953F56EA23055D1B00710599 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 953F56E923055D1B00710599 /* Assets.xcassets */; }; 953F56ED23055D1B00710599 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 953F56EB23055D1B00710599 /* LaunchScreen.storyboard */; }; 953F56F023055D1B00710599 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 953F56EF23055D1B00710599 /* main.m */; }; - 953F56FB2306500200710599 /* YSCObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 953F56FA2306500200710599 /* YSCObject.m */; }; - 953F5707230A7A7100710599 /* NSObject+MethodSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 953F5706230A7A7100710599 /* NSObject+MethodSwizzling.m */; }; - 953F570A230A7BC300710599 /* NSObject+SelectorDefender.m in Sources */ = {isa = PBXBuildFile; fileRef = 953F5709230A7BC300710599 /* NSObject+SelectorDefender.m */; }; - 95B929E6230D269D0078E7B6 /* NSObject+KVODefender.m in Sources */ = {isa = PBXBuildFile; fileRef = 95B929E4230D269D0078E7B6 /* NSObject+KVODefender.m */; }; - 95B929F1230E46730078E7B6 /* NSObject+KVODefenderEasy.m in Sources */ = {isa = PBXBuildFile; fileRef = 95B929EF230E46730078E7B6 /* NSObject+KVODefenderEasy.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 950630AE230AAA18001E5349 /* KVOCrashObjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KVOCrashObjc.h; sourceTree = ""; }; - 950630AF230AAA18001E5349 /* KVOCrashObjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KVOCrashObjc.m; sourceTree = ""; }; + 95345918230FBF6C00767E14 /* KVOCrashObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KVOCrashObject.h; sourceTree = ""; }; + 95345919230FBF6C00767E14 /* KVOCrashObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KVOCrashObject.m; sourceTree = ""; }; + 9534592B231677CB00767E14 /* KVCCrashObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KVCCrashObject.h; sourceTree = ""; }; + 9534592C231677CB00767E14 /* KVCCrashObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KVCCrashObject.m; sourceTree = ""; }; + 953459312316AEBC00767E14 /* NSObject+MethodSwizzling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MethodSwizzling.h"; sourceTree = ""; }; + 953459322316AEBC00767E14 /* NSObject+SelectorDefender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SelectorDefender.m"; sourceTree = ""; }; + 953459332316AEBC00767E14 /* NSObject+SelectorDefender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SelectorDefender.h"; sourceTree = ""; }; + 953459342316AEBC00767E14 /* NSObject+KVODefender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+KVODefender.h"; sourceTree = ""; }; + 953459352316AEBC00767E14 /* NSObject+KVCDefender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+KVCDefender.h"; sourceTree = ""; }; + 953459362316AEBC00767E14 /* NSObject+MethodSwizzling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MethodSwizzling.m"; sourceTree = ""; }; + 953459372316AEBD00767E14 /* NSObject+KVODefender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+KVODefender.m"; sourceTree = ""; }; + 953459382316AEBD00767E14 /* NSObject+KVCDefender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+KVCDefender.m"; sourceTree = ""; }; + 9534594B231DF76900767E14 /* NotificationReceiver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationReceiver.h; sourceTree = ""; }; + 9534594C231DF76900767E14 /* NotificationReceiver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationReceiver.m; sourceTree = ""; }; + 95345962231F52B700767E14 /* TestUnrecognizedSelVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestUnrecognizedSelVC.h; sourceTree = ""; }; + 95345963231F52B700767E14 /* TestUnrecognizedSelVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestUnrecognizedSelVC.m; sourceTree = ""; }; + 95345965231F52D000767E14 /* TestKVOCrashVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestKVOCrashVC.h; sourceTree = ""; }; + 95345966231F52D000767E14 /* TestKVOCrashVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestKVOCrashVC.m; sourceTree = ""; }; + 95345968231F52E900767E14 /* TestKVCCrashVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestKVCCrashVC.h; sourceTree = ""; }; + 95345969231F52E900767E14 /* TestKVCCrashVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestKVCCrashVC.m; sourceTree = ""; }; + 9534596B231F530100767E14 /* TestNotificationCrashVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestNotificationCrashVC.h; sourceTree = ""; }; + 9534596C231F530100767E14 /* TestNotificationCrashVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestNotificationCrashVC.m; sourceTree = ""; }; + 9534596E231F531E00767E14 /* TestTimerCrashVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestTimerCrashVC.h; sourceTree = ""; }; + 9534596F231F531E00767E14 /* TestTimerCrashVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestTimerCrashVC.m; sourceTree = ""; }; + 95345971231F533200767E14 /* TestContainersVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestContainersVC.h; sourceTree = ""; }; + 95345972231F533200767E14 /* TestContainersVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestContainersVC.m; sourceTree = ""; }; + 95345974231F534400767E14 /* TestNullVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestNullVC.h; sourceTree = ""; }; + 95345975231F534400767E14 /* TestNullVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestNullVC.m; sourceTree = ""; }; + 95345977231F57EE00767E14 /* BaseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseViewController.h; sourceTree = ""; }; + 95345978231F57EE00767E14 /* BaseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BaseViewController.m; sourceTree = ""; }; + 9534597E231F5C2700767E14 /* BaseDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseDefine.h; sourceTree = ""; }; + 95345982231F619A00767E14 /* SelectorObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SelectorObject.h; sourceTree = ""; }; + 95345983231F619A00767E14 /* SelectorObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SelectorObject.m; sourceTree = ""; }; 953F56DD23055D1A00710599 /* YSC-Avoid-Crash.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "YSC-Avoid-Crash.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 953F56E023055D1A00710599 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 953F56E123055D1A00710599 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -34,16 +75,6 @@ 953F56EC23055D1B00710599 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 953F56EE23055D1B00710599 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 953F56EF23055D1B00710599 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 953F56F92306500200710599 /* YSCObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YSCObject.h; sourceTree = ""; }; - 953F56FA2306500200710599 /* YSCObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YSCObject.m; sourceTree = ""; }; - 953F5705230A7A7100710599 /* NSObject+MethodSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+MethodSwizzling.h"; sourceTree = ""; }; - 953F5706230A7A7100710599 /* NSObject+MethodSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MethodSwizzling.m"; sourceTree = ""; }; - 953F5708230A7BC300710599 /* NSObject+SelectorDefender.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+SelectorDefender.h"; sourceTree = ""; }; - 953F5709230A7BC300710599 /* NSObject+SelectorDefender.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SelectorDefender.m"; sourceTree = ""; }; - 95B929E4230D269D0078E7B6 /* NSObject+KVODefender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+KVODefender.m"; sourceTree = ""; }; - 95B929E5230D269D0078E7B6 /* NSObject+KVODefender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+KVODefender.h"; sourceTree = ""; }; - 95B929EF230E46730078E7B6 /* NSObject+KVODefenderEasy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+KVODefenderEasy.m"; sourceTree = ""; }; - 95B929F0230E46730078E7B6 /* NSObject+KVODefenderEasy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+KVODefenderEasy.h"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,6 +88,117 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 95345957231F4EC900767E14 /* YSCDefender */ = { + isa = PBXGroup; + children = ( + 953459312316AEBC00767E14 /* NSObject+MethodSwizzling.h */, + 953459362316AEBC00767E14 /* NSObject+MethodSwizzling.m */, + 953459332316AEBC00767E14 /* NSObject+SelectorDefender.h */, + 953459322316AEBC00767E14 /* NSObject+SelectorDefender.m */, + 953459342316AEBC00767E14 /* NSObject+KVODefender.h */, + 953459372316AEBD00767E14 /* NSObject+KVODefender.m */, + 953459352316AEBC00767E14 /* NSObject+KVCDefender.h */, + 953459382316AEBD00767E14 /* NSObject+KVCDefender.m */, + ); + path = YSCDefender; + sourceTree = ""; + }; + 95345958231F4EF000767E14 /* Examples */ = { + isa = PBXGroup; + children = ( + 9534595B231F51FE00767E14 /* Unrecognized Selector */, + 9534595C231F521100767E14 /* KVO */, + 9534595D231F521500767E14 /* KVC */, + 9534595E231F521F00767E14 /* Notification */, + 9534595F231F523100767E14 /* Timer */, + 95345960231F523D00767E14 /* Containers */, + 95345961231F525100767E14 /* NSNull */, + 9534597A231F57F400767E14 /* Base */, + ); + path = Examples; + sourceTree = ""; + }; + 9534595B231F51FE00767E14 /* Unrecognized Selector */ = { + isa = PBXGroup; + children = ( + 95345982231F619A00767E14 /* SelectorObject.h */, + 95345983231F619A00767E14 /* SelectorObject.m */, + 95345962231F52B700767E14 /* TestUnrecognizedSelVC.h */, + 95345963231F52B700767E14 /* TestUnrecognizedSelVC.m */, + ); + path = "Unrecognized Selector"; + sourceTree = ""; + }; + 9534595C231F521100767E14 /* KVO */ = { + isa = PBXGroup; + children = ( + 95345918230FBF6C00767E14 /* KVOCrashObject.h */, + 95345919230FBF6C00767E14 /* KVOCrashObject.m */, + 95345965231F52D000767E14 /* TestKVOCrashVC.h */, + 95345966231F52D000767E14 /* TestKVOCrashVC.m */, + ); + path = KVO; + sourceTree = ""; + }; + 9534595D231F521500767E14 /* KVC */ = { + isa = PBXGroup; + children = ( + 9534592B231677CB00767E14 /* KVCCrashObject.h */, + 9534592C231677CB00767E14 /* KVCCrashObject.m */, + 95345968231F52E900767E14 /* TestKVCCrashVC.h */, + 95345969231F52E900767E14 /* TestKVCCrashVC.m */, + ); + path = KVC; + sourceTree = ""; + }; + 9534595E231F521F00767E14 /* Notification */ = { + isa = PBXGroup; + children = ( + 9534594B231DF76900767E14 /* NotificationReceiver.h */, + 9534594C231DF76900767E14 /* NotificationReceiver.m */, + 9534596B231F530100767E14 /* TestNotificationCrashVC.h */, + 9534596C231F530100767E14 /* TestNotificationCrashVC.m */, + ); + path = Notification; + sourceTree = ""; + }; + 9534595F231F523100767E14 /* Timer */ = { + isa = PBXGroup; + children = ( + 9534596E231F531E00767E14 /* TestTimerCrashVC.h */, + 9534596F231F531E00767E14 /* TestTimerCrashVC.m */, + ); + path = Timer; + sourceTree = ""; + }; + 95345960231F523D00767E14 /* Containers */ = { + isa = PBXGroup; + children = ( + 95345971231F533200767E14 /* TestContainersVC.h */, + 95345972231F533200767E14 /* TestContainersVC.m */, + ); + path = Containers; + sourceTree = ""; + }; + 95345961231F525100767E14 /* NSNull */ = { + isa = PBXGroup; + children = ( + 95345974231F534400767E14 /* TestNullVC.h */, + 95345975231F534400767E14 /* TestNullVC.m */, + ); + path = NSNull; + sourceTree = ""; + }; + 9534597A231F57F400767E14 /* Base */ = { + isa = PBXGroup; + children = ( + 95345977231F57EE00767E14 /* BaseViewController.h */, + 95345978231F57EE00767E14 /* BaseViewController.m */, + 9534597E231F5C2700767E14 /* BaseDefine.h */, + ); + path = Base; + sourceTree = ""; + }; 953F56D423055D1A00710599 = { isa = PBXGroup; children = ( @@ -76,18 +218,8 @@ 953F56DF23055D1A00710599 /* YSC-Avoid-Crash */ = { isa = PBXGroup; children = ( - 953F56F92306500200710599 /* YSCObject.h */, - 953F56FA2306500200710599 /* YSCObject.m */, - 950630AE230AAA18001E5349 /* KVOCrashObjc.h */, - 950630AF230AAA18001E5349 /* KVOCrashObjc.m */, - 953F5705230A7A7100710599 /* NSObject+MethodSwizzling.h */, - 953F5706230A7A7100710599 /* NSObject+MethodSwizzling.m */, - 953F5708230A7BC300710599 /* NSObject+SelectorDefender.h */, - 953F5709230A7BC300710599 /* NSObject+SelectorDefender.m */, - 95B929E5230D269D0078E7B6 /* NSObject+KVODefender.h */, - 95B929E4230D269D0078E7B6 /* NSObject+KVODefender.m */, - 95B929F0230E46730078E7B6 /* NSObject+KVODefenderEasy.h */, - 95B929EF230E46730078E7B6 /* NSObject+KVODefenderEasy.m */, + 95345958231F4EF000767E14 /* Examples */, + 95345957231F4EC900767E14 /* YSCDefender */, 953F56E023055D1A00710599 /* AppDelegate.h */, 953F56E123055D1A00710599 /* AppDelegate.m */, 953F56E323055D1A00710599 /* ViewController.h */, @@ -171,15 +303,25 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 953F570A230A7BC300710599 /* NSObject+SelectorDefender.m in Sources */, - 95B929F1230E46730078E7B6 /* NSObject+KVODefenderEasy.m in Sources */, - 95B929E6230D269D0078E7B6 /* NSObject+KVODefender.m in Sources */, - 950630B0230AAA18001E5349 /* KVOCrashObjc.m in Sources */, + 95345970231F531E00767E14 /* TestTimerCrashVC.m in Sources */, + 9534591A230FBF6C00767E14 /* KVOCrashObject.m in Sources */, 953F56E523055D1A00710599 /* ViewController.m in Sources */, + 9534593A2316AEBD00767E14 /* NSObject+MethodSwizzling.m in Sources */, 953F56F023055D1B00710599 /* main.m in Sources */, - 953F56FB2306500200710599 /* YSCObject.m in Sources */, + 9534594D231DF76900767E14 /* NotificationReceiver.m in Sources */, + 95345984231F619A00767E14 /* SelectorObject.m in Sources */, 953F56E223055D1A00710599 /* AppDelegate.m in Sources */, - 953F5707230A7A7100710599 /* NSObject+MethodSwizzling.m in Sources */, + 9534592D231677CB00767E14 /* KVCCrashObject.m in Sources */, + 9534593C2316AEBD00767E14 /* NSObject+KVCDefender.m in Sources */, + 9534596D231F530100767E14 /* TestNotificationCrashVC.m in Sources */, + 95345967231F52D000767E14 /* TestKVOCrashVC.m in Sources */, + 9534596A231F52E900767E14 /* TestKVCCrashVC.m in Sources */, + 95345964231F52B700767E14 /* TestUnrecognizedSelVC.m in Sources */, + 95345973231F533200767E14 /* TestContainersVC.m in Sources */, + 953459392316AEBD00767E14 /* NSObject+SelectorDefender.m in Sources */, + 9534593B2316AEBD00767E14 /* NSObject+KVODefender.m in Sources */, + 95345976231F534400767E14 /* TestNullVC.m in Sources */, + 95345979231F57EE00767E14 /* BaseViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -324,6 +466,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "YSC-Avoid-Crash/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -341,6 +484,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "YSC-Avoid-Crash/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/LaunchScreen.storyboard b/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/LaunchScreen.storyboard index bfa3612..f4da51a 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/LaunchScreen.storyboard +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/LaunchScreen.storyboard @@ -1,8 +1,11 @@ - - + + + + + - - + + @@ -11,15 +14,14 @@ - + - - + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/Main.storyboard b/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/Main.storyboard index 942f0bc..145eef2 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/Main.storyboard +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Base.lproj/Main.storyboard @@ -1,24 +1,27 @@ - + + + + - - + + - + - + - + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseDefine.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseDefine.h new file mode 100644 index 0000000..fc27402 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseDefine.h @@ -0,0 +1,15 @@ +// +// BaseDefine.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#ifndef BaseDefine_h +#define BaseDefine_h + +#define UIScreenWidth ([[UIScreen mainScreen] bounds].size.width) +#define UIScreenHeigh ([[UIScreen mainScreen] bounds].size.height) + +#endif /* BaseDefine_h */ diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.h new file mode 100644 index 0000000..0b85fd4 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.h @@ -0,0 +1,20 @@ +// +// BaseViewController.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseDefine.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface BaseViewController : UIViewController + +- (void)redirectSTD:(int)fd; + +@end + +NS_ASSUME_NONNULL_END diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.m new file mode 100644 index 0000000..2dfa002 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Base/BaseViewController.m @@ -0,0 +1,92 @@ +// +// BaseViewController.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "BaseViewController.h" + +@interface BaseViewController () + +/* <#注释#> */ +@property (nonatomic, strong) UIButton *backButton; + +/* <#注释#> */ +@property (nonatomic, strong) UITextView *logTextView; +@end + +@implementation BaseViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor whiteColor]; + [self.view addSubview:self.backButton]; + [self.view addSubview:self.logTextView]; + + [self redirectSTD:STDOUT_FILENO]; + [self redirectSTD:STDERR_FILENO]; +} + +/** + * backButton初始化 + */ +- (UIButton *)backButton { + if (!_backButton) { + _backButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _backButton.frame = CGRectMake(15, 12, 44, 40); + _backButton.contentMode = UIViewContentModeLeft; + [_backButton setTitle:@"返回" forState:UIControlStateNormal]; + [_backButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [_backButton addTarget:self action:@selector(backButtonClick:) forControlEvents:UIControlEventTouchUpInside]; + } + return _backButton; +} + +- (void)backButtonClick:(UIButton *)button { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +/** + * logTextView初始化 + */ +- (UITextView *)logTextView { + if (!_logTextView) { + _logTextView = [[UITextView alloc] initWithFrame:CGRectMake(30, UIScreenHeigh-170, UIScreenWidth-60, 150)]; + [_logTextView setEditable:NO]; + [_logTextView setBackgroundColor:[UIColor lightGrayColor]]; + [_logTextView setTextColor:[UIColor blackColor]]; + [_logTextView setFont:[UIFont systemFontOfSize:15]]; + } + return _logTextView; +} + + +- (void)redirectNotificationHandle:(NSNotification *)nf{ // 通知方法 + NSData *data = [[nf userInfo] objectForKey:NSFileHandleNotificationDataItem]; + NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + + self.logTextView.text = [NSString stringWithFormat:@"%@\n\n%@",self.logTextView.text, str]; // logTextView 就是要将日志输出的视图(UITextView) + NSRange range; + range.location = [self.logTextView.text length] - 1; + range.length = 0; + [self.logTextView scrollRangeToVisible:range]; + [[nf object] readInBackgroundAndNotify]; +} + +- (void)redirectSTD:(int)fd { + NSPipe * pipe = [NSPipe pipe] ;// 初始化一个NSPipe 对象 + NSFileHandle *pipeReadHandle = [pipe fileHandleForReading] ; + dup2([[pipe fileHandleForWriting] fileDescriptor], fd) ; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(redirectNotificationHandle:) + name:NSFileHandleReadCompletionNotification + object:pipeReadHandle]; // 注册通知 + [pipeReadHandle readInBackgroundAndNotify]; +} + + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.h new file mode 100644 index 0000000..079ecd6 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.h @@ -0,0 +1,15 @@ +// +// TestContainersVC.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface TestContainersVC : BaseViewController + +@end + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.m new file mode 100644 index 0000000..66f10a1 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Containers/TestContainersVC.m @@ -0,0 +1,32 @@ +// +// TestContainersVC.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "TestContainersVC.h" + +@interface TestContainersVC () + +@end + +@implementation TestContainersVC + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.h new file mode 100644 index 0000000..0dfab53 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.h @@ -0,0 +1,21 @@ +// +// KVCCrashObject.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/8/28. +// Copyright © 2019 bujige. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface KVCCrashObject : NSObject + +@property (nonatomic, copy) NSString *name; + +@property (nonatomic, assign) NSInteger age; + +@end + +NS_ASSUME_NONNULL_END diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.m new file mode 100644 index 0000000..51178e7 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/KVCCrashObject.m @@ -0,0 +1,13 @@ +// +// KVCCrashObject.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/8/28. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "KVCCrashObject.h" + +@implementation KVCCrashObject + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.h new file mode 100644 index 0000000..2893c4b --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.h @@ -0,0 +1,15 @@ +// +// TestKVCCrashVC.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface TestKVCCrashVC : BaseViewController + +@end + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.m new file mode 100644 index 0000000..c77fc11 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVC/TestKVCCrashVC.m @@ -0,0 +1,126 @@ +// +// TestKVCCrashVC.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "TestKVCCrashVC.h" +#import "KVCCrashObject.h" + +@interface TestKVCCrashVC () + +@end + +@implementation TestKVCCrashVC +{ + NSArray *_titleArray; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self setupDataSource]; + + [self setupUI]; +} + +- (void)setupDataSource { + _titleArray = @[ + @"1. key 不是对象的属性", + @"2. keyPath 不正确", + @"3. key 为 nil", + @"4. value 为 nil,为非对象设值" + ]; +} + +- (void)setupUI { + CGFloat buttonWidth = (UIScreenWidth-60); + CGFloat buttonHeight = 44; + CGFloat buttonSpace = 30; + CGFloat buttonGap = 10; + for (int i = 0; i < _titleArray.count; i++) { + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.tag = 1000+i; + [button setTitle:_titleArray[i] forState:UIControlStateNormal]; + [button setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal]; + button.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + button.frame = CGRectMake(buttonSpace, 60+(buttonHeight+buttonGap)*i, buttonWidth, buttonHeight); + [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside]; + button.layer.cornerRadius = 5; + button.titleLabel.font = [UIFont systemFontOfSize:14]; + button.backgroundColor = [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1]; + [self.view addSubview:button]; + } +} + +- (void)buttonClick:(UIButton *)button { + NSInteger buttonTag = button.tag; + switch (buttonTag) { + case 1000: { + [self testKVCCrash1]; + } + break; + case 1001: { + [self testKVCCrash2]; + } + break; + case 1002: { + [self testKVCCrash3]; + } + break; + case 1003: { + [self testKVCCrash4]; + } + break; + default: + break; + } +} + +/** + 1. key 不是对象的属性,造成崩溃 + */ +- (void)testKVCCrash1 { + // 崩溃日志:[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key XXX.; + + KVCCrashObject *objc = [[KVCCrashObject alloc] init]; + [objc setValue:@"value" forKey:@"address"]; +} + +/** + 2. keyPath 不正确,造成崩溃 + */ +- (void)testKVCCrash2 { + // 崩溃日志:[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key XXX. + + KVCCrashObject *objc = [[KVCCrashObject alloc] init]; + [objc setValue:@"后厂村路" forKeyPath:@"address.street"]; +} + +/** + 3. key 为 nil,造成崩溃 + */ +- (void)testKVCCrash3 { + // 崩溃日志:'-[KVCCrashObject setValue:forKey:]: attempt to set a value for a nil key + + NSString *keyName; + // key 为 nil 会崩溃,如果传 nil 会提示警告,传空变量则不会提示警告 + + KVCCrashObject *objc = [[KVCCrashObject alloc] init]; + [objc setValue:@"value" forKey:keyName]; +} + +/** + 4. value 为 nil,造成崩溃 + */ +- (void)testKVCCrash4 { + // 崩溃日志:[ setNilValueForKey]: could not set nil as the value for the key XXX. + + // value 为 nil 会崩溃 + KVCCrashObject *objc = [[KVCCrashObject alloc] init]; + [objc setValue:nil forKey:@"age"]; +} + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/KVOCrashObjc.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/KVOCrashObject.h similarity index 68% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/KVOCrashObjc.h rename to YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/KVOCrashObject.h index 696400c..26de6ad 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/KVOCrashObjc.h +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/KVOCrashObject.h @@ -1,8 +1,8 @@ // -// KVOCrashObjc.h +// KVOCrashObject.h // YSC-Avoid-Crash // -// Created by WalkingBoy on 2019/8/19. +// Created by WalkingBoy on 2019/8/23. // Copyright © 2019 bujige. All rights reserved. // @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface KVOCrashObjc : NSObject +@interface KVOCrashObject : NSObject @property (nonatomic, copy) NSString *name; diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/KVOCrashObject.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/KVOCrashObject.m new file mode 100644 index 0000000..3a95bd6 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/KVOCrashObject.m @@ -0,0 +1,13 @@ +// +// KVOCrashObject.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/8/23. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "KVOCrashObject.h" + +@implementation KVOCrashObject + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.h new file mode 100644 index 0000000..f37c7ba --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.h @@ -0,0 +1,15 @@ +// +// TestKVOCrashVC.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface TestKVOCrashVC : BaseViewController + +@end + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.m new file mode 100644 index 0000000..fa1cef8 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/KVO/TestKVOCrashVC.m @@ -0,0 +1,176 @@ +// +// TestKVOCrashVC.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "TestKVOCrashVC.h" +#import "KVOCrashObject.h" + +@interface TestKVOCrashVC () + +@property (nonatomic, strong) KVOCrashObject *objc; + +@end + +@implementation TestKVOCrashVC +{ + NSArray *_titleArray; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + [self setupDataSource]; + + [self setupUI]; + +} + + +- (void)setupDataSource { + _titleArray = @[ + @"1.1 移除了未注册的观察者", + @"1.2 重复移除多次,移除次数多于添加次数", + @"1.3 重复添加多次,被观察多次。", + @"2. 被观察者 dealloc 时仍然注册着 KVO", + @"3. 观察者没有实现观察方法", + @"4. 添加或者移除时 keypath == nil" + ]; + + self.objc = [[KVOCrashObject alloc] init]; +} + +- (void)setupUI { + CGFloat buttonWidth = (UIScreenWidth-60); + CGFloat buttonHeight = 44; + CGFloat buttonSpace = 30; + CGFloat buttonGap = 10; + for (int i = 0; i < _titleArray.count; i++) { + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.tag = 1000+i; + [button setTitle:_titleArray[i] forState:UIControlStateNormal]; + [button setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal]; + button.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + button.frame = CGRectMake(buttonSpace, 60+(buttonHeight+buttonGap)*i, buttonWidth, buttonHeight); + [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside]; + button.layer.cornerRadius = 5; + button.titleLabel.font = [UIFont systemFontOfSize:14]; + button.backgroundColor = [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1]; + [self.view addSubview:button]; + } +} + +- (void)buttonClick:(UIButton *)button { + NSInteger buttonTag = button.tag; + switch (buttonTag) { + case 1000: { + [self testKVOCrash11]; + } + break; + case 1001: { + [self testKVOCrash12]; + } + break; + case 1002: { + [self testKVOCrash13]; + } + break; + case 1003: { + [self testKVOCrash2]; + } + break; + case 1004: { + [self testKVOCrash3]; + } + break; + case 1005: { + [self testKVOCrash4]; + } + default: + break; + } +} + + +/** + 1.1 移除了未注册的观察者,导致崩溃 + */ +- (void)testKVOCrash11 { + // 崩溃日志:Cannot remove an observer XXX for the key path "xxx" from XXX because it is not registered as an observer. + [self.objc removeObserver:self forKeyPath:@"name"]; +} + +/** + 1.2 重复移除多次,移除次数多于添加次数,导致崩溃 + */ +- (void)testKVOCrash12 { + // 崩溃日志:Cannot remove an observer XXX for the key path "xxx" from XXX because it is not registered as an observer. + [self.objc addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL]; + self.objc.name = @"0"; + [self.objc removeObserver:self forKeyPath:@"name"]; + [self.objc removeObserver:self forKeyPath:@"name"]; +} + +/** + 1.3 重复添加多次,虽然不会崩溃,但是发生改变时,也同时会被观察多次。 + */ +- (void)testKVOCrash13 { + [self.objc addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL]; + [self.objc addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL]; + self.objc.name = @"0"; +} + +/** + 2. 被观察者 dealloc 时仍然注册着 KVO,导致崩溃 + */ +- (void)testKVOCrash2 { + // 崩溃日志:An instance xxx of class xxx was deallocated while key value observers were still registered with it. + // iOS 10 及以下会导致崩溃,iOS 11 之后就不会崩溃了 + KVOCrashObject *obj = [[KVOCrashObject alloc] init]; + [obj addObserver: self + forKeyPath: @"name" + options: NSKeyValueObservingOptionNew + context: nil]; +} + +/** + 3. 观察者没有实现 -observeValueForKeyPath:ofObject:change:context:导致崩溃 + */ +- (void)testKVOCrash3 { + // 崩溃日志:An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. + KVOCrashObject *obj = [[KVOCrashObject alloc] init]; + + [self addObserver: obj + forKeyPath: @"title" + options: NSKeyValueObservingOptionNew + context: nil]; + + self.title = @"111"; +} + +/** + 4. 添加或者移除时 keypath == nil,导致崩溃。 + */ +- (void)testKVOCrash4 { + // 崩溃日志: -[__NSCFConstantString characterAtIndex:]: Range or index out of bounds + KVOCrashObject *obj = [[KVOCrashObject alloc] init]; + + [self addObserver: obj + forKeyPath: @"" + options: NSKeyValueObservingOptionNew + context: nil]; + + // [self removeObserver:obj forKeyPath:@""]; +} + + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context { + + NSLog(@"object = %@, keyPath = %@", object, keyPath); +} + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.h new file mode 100644 index 0000000..20dc367 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.h @@ -0,0 +1,15 @@ +// +// TestNullVC.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface TestNullVC : BaseViewController + +@end + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.m new file mode 100644 index 0000000..e62022d --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/NSNull/TestNullVC.m @@ -0,0 +1,32 @@ +// +// TestNullVC.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "TestNullVC.h" + +@interface TestNullVC () + +@end + +@implementation TestNullVC + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/NotificationReceiver.h similarity index 58% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.h rename to YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/NotificationReceiver.h index a2ed6cf..f250c80 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.h +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/NotificationReceiver.h @@ -1,8 +1,8 @@ // -// YSCObject.h +// NotificationReceiver.h // YSC-Avoid-Crash // -// Created by WalkingBoy on 2019/8/16. +// Created by WalkingBoy on 2019/9/3. // Copyright © 2019 bujige. All rights reserved. // @@ -10,11 +10,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface YSCObject : NSObject - -+ (id)aClassFunc; - -- (id)object; +@interface NotificationReceiver : NSObject @end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/NotificationReceiver.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/NotificationReceiver.m new file mode 100644 index 0000000..9a71950 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/NotificationReceiver.m @@ -0,0 +1,29 @@ +// +// NotificationReceiver.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/3. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "NotificationReceiver.h" + +@implementation NotificationReceiver + +- (instancetype)init { + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification:) name:@"loadingCompelete" object:nil]; + } + return self; +} + +- (void)receiveNotification:(NSNotification*)noti { + int page = [noti.userInfo[@"page"] intValue]; + NSLog(@"%d",page); +} + +- (void)dealloc { + NSLog(@"dealloc"); +} +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.h new file mode 100644 index 0000000..3081fc9 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.h @@ -0,0 +1,14 @@ +// +// TestNotificationCrashVC.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface TestNotificationCrashVC : BaseViewController + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.m new file mode 100644 index 0000000..10d87cc --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Notification/TestNotificationCrashVC.m @@ -0,0 +1,22 @@ +// +// TestNotificationCrashVC.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "TestNotificationCrashVC.h" + +@interface TestNotificationCrashVC () + +@end + +@implementation TestNotificationCrashVC + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.h new file mode 100644 index 0000000..e33dc97 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.h @@ -0,0 +1,15 @@ +// +// TestTimerCrashVC.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface TestTimerCrashVC : BaseViewController + +@end + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.m new file mode 100644 index 0000000..33d18a1 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Timer/TestTimerCrashVC.m @@ -0,0 +1,32 @@ +// +// TestTimerCrashVC.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "TestTimerCrashVC.h" + +@interface TestTimerCrashVC () + +@end + +@implementation TestTimerCrashVC + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.h new file mode 100644 index 0000000..cadf558 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.h @@ -0,0 +1,18 @@ +// +// SelectorObject.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import + +@interface SelectorObject : NSObject + ++ (id)classFunc; + +- (id)instanceFunc; + +@end + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.m new file mode 100644 index 0000000..98ea4d1 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/SelectorObject.m @@ -0,0 +1,13 @@ +// +// SelectorObject.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "SelectorObject.h" + +@implementation SelectorObject + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.h new file mode 100644 index 0000000..3e31a63 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.h @@ -0,0 +1,15 @@ +// +// TestUnrecognizedSelVC.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface TestUnrecognizedSelVC : BaseViewController + +@end + diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.m new file mode 100644 index 0000000..2dd7da1 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/Examples/Unrecognized Selector/TestUnrecognizedSelVC.m @@ -0,0 +1,94 @@ +// +// TestUnrecognizedSelVC.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/9/4. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "TestUnrecognizedSelVC.h" +#import "SelectorObject.h" + +@interface TestUnrecognizedSelVC () + +@end + +@implementation TestUnrecognizedSelVC +{ + NSArray *_titleArray; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self setupDataSource]; + + [self setupUI]; +} + +- (void)setupDataSource { + _titleArray = @[ + @"找不到 button 响应事件", + @"找不到控制器中的方法", + @"找不到对象方法", + @"找不到类方法", + @"调用 null 对象的方法", + ]; +} + +- (void)setupUI { + CGFloat buttonWidth = (UIScreenWidth-60); + CGFloat buttonHeight = 44; + CGFloat buttonSpace = 30; + CGFloat buttonGap = 10; + for (int i = 0; i < _titleArray.count; i++) { + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.tag = 1000+i; + [button setTitle:_titleArray[i] forState:UIControlStateNormal]; + [button setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal]; + button.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + button.frame = CGRectMake(buttonSpace, 60+(buttonHeight+buttonGap)*i, buttonWidth, buttonHeight); + if (i == 0) { + [button addTarget:self action:@selector(undefinedButtonClick:) forControlEvents:UIControlEventTouchUpInside]; + } else { + [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside]; + } + + button.layer.cornerRadius = 5; + button.titleLabel.font = [UIFont systemFontOfSize:14]; + button.backgroundColor = [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1]; + [self.view addSubview:button]; + } +} + +- (void)buttonClick:(UIButton *)button { + NSInteger buttonTag = button.tag; + switch (buttonTag) { + case 1000: { + + } + break; + case 1001: { + [self performSelector:@selector(undefinedVCSelector)]; + } + break; + case 1002: { + SelectorObject *object = [[SelectorObject alloc] init]; + [object instanceFunc]; + } + break; + case 1003: { + [SelectorObject classFunc]; + } + break; + case 1004: { + [[NSNull null] performSelector:@selector(undefinedSelector)]; + } + break; + default: + break; + } +} + + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/KVOCrashObjc.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/KVOCrashObjc.m deleted file mode 100644 index ead26e7..0000000 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/KVOCrashObjc.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// KVOCrashObjc.m -// YSC-Avoid-Crash -// -// Created by WalkingBoy on 2019/8/19. -// Copyright © 2019 bujige. All rights reserved. -// - -#import "KVOCrashObjc.h" - -@implementation KVOCrashObjc - -@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/ViewController.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/ViewController.m index accca45..132ac1b 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/ViewController.m +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/ViewController.m @@ -7,93 +7,112 @@ // #import "ViewController.h" -#import "KVOCrashObjc.h" -#import "YSCObject.h" +#import "BaseDefine.h" +#import "NotificationReceiver.h" -@interface ViewController () +@interface ViewController () -/* <#注释#> */ -@property (nonatomic, strong) KVOCrashObjc *objcc; +/* tableView */ +@property (nonatomic, strong) UITableView *tableView; -/* <#注释#> */ -@property (nonatomic, copy) NSString *test; @end @implementation ViewController +{ + NSArray *_titleArray; +} - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. - [YSCObject aClassFunc]; + _titleArray = @[ + @{ + @"title" : @"Unrecognized Selector Crash", + @"class" : @"TestUnrecognizedSelVC" + }, + @{ + @"title" : @"KVO Crash", + @"class" : @"TestKVOCrashVC" + }, + @{ + @"title" : @"KVC Crash", + @"class" : @"TestKVCCrashVC" + }, + @{ + @"title" : @"Notification Crash", + @"class" : @"TestNotificationCrashVC" + }, + @{ + @"title" : @"NSTimer Crash", + @"class" : @"TestTimerCrashVC" + }, + @{ + @"title" : @"Containers Crash", + @"class" : @"TestContainersVC" + }, + @{ + @"title" : @"NSNull Crash", + @"class" : @"TestNullVC" + } + ]; - [[[YSCObject alloc] init] object]; + [self.view addSubview:self.tableView]; - self.objcc = [[KVOCrashObjc alloc] init]; -} + @autoreleasepool { + NotificationReceiver *receiver = [[NotificationReceiver alloc] init]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"loadingCompelete" object:nil userInfo:@{@"page":@(1)}]; + + NSLog(@"%@",receiver); + } -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - - - [self func2]; - } /** - 观察者是局部变量,会崩溃 - */ -- (void)func1 { - // 崩溃日志:An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. - KVOCrashObjc *obj = [[KVOCrashObjc alloc] init]; - - [self addObserver:obj forKeyPath:@"test" options:NSKeyValueObservingOptionNew - context:nil]; - - self.test = @"111"; -} -/** - 被观察者是局部变量,会崩溃 - */ -- (void)func2 { - // 崩溃日志:An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. - KVOCrashObjc *obj = [[KVOCrashObjc alloc] init]; - [obj addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew - context:nil]; - obj.name = @""; -} -/** - 没有实现observeValueForKeyPath:ofObject:changecontext:方法:,会崩溃 + * tableView初始化 */ -- (void)func3 { - // 崩溃日志:An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. - [self.objcc addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL]; - self.objcc.name = @"0"; +- (UITableView *)tableView { + if (!_tableView) { + _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, UIScreenWidth, UIScreenHeigh) style:UITableViewStyleGrouped]; + _tableView.delegate = self; + _tableView.dataSource = self; + } + return _tableView; } -/** - 重复移除观察者,会崩溃 - */ -- (void)func4 { - // 崩溃日志:because it is not registered as an observer - [self.objcc addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL]; - self.objcc.name = @"0"; - [self.objcc removeObserver:self forKeyPath:@"name"]; - [self.objcc removeObserver:self forKeyPath:@"name"]; + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; } -/** - 重复添加观察者,不会崩溃,但是添加多少次,一次改变就会被观察多少次 - */ -- (void)func5 { - [self.objcc addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL]; - [self.objcc addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL]; - self.objcc.name = @"0"; + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return _titleArray.count; } +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 44; +} -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context { +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *CellID = @"mainCellID"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID]; + if (cell == nil) { + cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID]; + } + cell.textLabel.text = [_titleArray[indexPath.row] objectForKey:@"title"]; + return cell; +} +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + NSDictionary *item = _titleArray[indexPath.row]; + Class cls = NSClassFromString([item objectForKey:@"class"]); + [self presentViewController:[[cls alloc] init] animated:YES completion:nil]; +} - NSLog(@"keyPath = %@", keyPath); +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + + [[NSNotificationCenter defaultCenter] postNotificationName:@"loadingCompelete" object:nil userInfo:@{@"page":@(2)}]; } + @end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.h new file mode 100644 index 0000000..7949b44 --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.h @@ -0,0 +1,17 @@ +// +// NSObject+KVCDefender.h +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/8/27. +// Copyright © 2019 bujige. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSObject (KVCDefender) + +@end + +NS_ASSUME_NONNULL_END diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.m new file mode 100644 index 0000000..15fcd1f --- /dev/null +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVCDefender.m @@ -0,0 +1,54 @@ +// +// NSObject+KVCDefender.m +// YSC-Avoid-Crash +// +// Created by WalkingBoy on 2019/8/27. +// Copyright © 2019 bujige. All rights reserved. +// + +#import "NSObject+KVCDefender.h" +#import "NSObject+MethodSwizzling.h" + +@implementation NSObject (KVCDefender) + +// 不建议拦截 `setValue:forKey:` 方法,会影响系统逻辑判断 ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + + // 拦截 `setValue:forKey:` 方法,替换自定义实现 + [NSObject yscDefenderSwizzlingInstanceMethod:@selector(setValue:forKey:) + withMethod:@selector(ysc_setValue:forKey:) + withClass:[NSObject class]]; + + }); +} + +- (void)ysc_setValue:(id)value forKey:(NSString *)key { + if (key == nil) { + NSString *crashMessages = [NSString stringWithFormat:@"crashMessages : [<%@ %p> setNilValueForKey]: could not set nil as the value for the key %@.",NSStringFromClass([self class]),self,key]; + NSLog(@"%@", crashMessages); + return; + } + + [self ysc_setValue:value forKey:key]; +} + +- (void)setNilValueForKey:(NSString *)key { + NSString *crashMessages = [NSString stringWithFormat:@"crashMessages : [<%@ %p> setNilValueForKey]: could not set nil as the value for the key %@.",NSStringFromClass([self class]),self,key]; + NSLog(@"%@", crashMessages); +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + NSString *crashMessages = [NSString stringWithFormat:@"crashMessages : [<%@ %p> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key: %@,value:%@'",NSStringFromClass([self class]),self,key,value]; + NSLog(@"%@", crashMessages); +} + +- (nullable id)valueForUndefinedKey:(NSString *)key { + NSString *crashMessages = [NSString stringWithFormat:@"crashMessages :[<%@ %p> valueForUndefinedKey:]: this class is not key value coding-compliant for the key: %@",NSStringFromClass([self class]),self,key]; + NSLog(@"%@", crashMessages); + + return self; +} + +@end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+KVODefender.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVODefender.h similarity index 99% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+KVODefender.h rename to YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVODefender.h index c10cac0..13d2bad 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+KVODefender.h +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVODefender.h @@ -8,10 +8,12 @@ #import + NS_ASSUME_NONNULL_BEGIN @interface NSObject (KVODefender) @end + NS_ASSUME_NONNULL_END diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+KVODefender.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVODefender.m similarity index 93% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+KVODefender.m rename to YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVODefender.m index 1fb61e7..7c30d61 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+KVODefender.m +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+KVODefender.m @@ -10,23 +10,6 @@ #import "NSObject+MethodSwizzling.h" #import -// 判断是否是系统类 -static inline BOOL IsSystemClass(Class cls){ - BOOL isSystem = NO; - NSString *className = NSStringFromClass(cls); - if ([className hasPrefix:@"NS"] || [className hasPrefix:@"__NS"] || [className hasPrefix:@"OS_xpc"]) { - isSystem = YES; - return isSystem; - } - NSBundle *mainBundle = [NSBundle bundleForClass:cls]; - if (mainBundle == [NSBundle mainBundle]) { - isSystem = NO; - }else{ - isSystem = YES; - } - return isSystem; -} - #pragma mark - YSCKVOProxy 相关 @@ -219,7 +202,7 @@ - (void)ysc_addObserver:(NSObject *)observer options:(NSKeyValueObservingOptions)options context:(void *)context { - if (!IsSystemClass(self.class)) { + if (!isSystemClass(self.class)) { objc_setAssociatedObject(self, KVODefenderKey, KVODefenderValue, OBJC_ASSOCIATION_RETAIN); if ([self.yscKVOProxy addInfoToMapWithObserver:observer forKeyPath:keyPath options:options context:context]) { // 如果添加 KVO 信息操作成功,则调用系统添加方法 @@ -241,7 +224,7 @@ - (void)ysc_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context { - if (!IsSystemClass(self.class)) { + if (!isSystemClass(self.class)) { if ([self.yscKVOProxy removeInfoInMapWithObserver:observer forKeyPath:keyPath context:context]) { // 如果移除 KVO 信息操作成功,则调用系统移除方法 [self ysc_removeObserver:self.yscKVOProxy forKeyPath:keyPath context:context]; @@ -260,7 +243,7 @@ - (void)ysc_removeObserver:(NSObject *)observer - (void)ysc_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { - if (!IsSystemClass(self.class)) { + if (!isSystemClass(self.class)) { if ([self.yscKVOProxy removeInfoInMapWithObserver:observer forKeyPath:keyPath]) { // 如果移除 KVO 信息操作成功,则调用系统移除方法 [self ysc_removeObserver:self.yscKVOProxy forKeyPath:keyPath]; @@ -279,7 +262,7 @@ - (void)ysc_removeObserver:(NSObject *)observer // 自定义 dealloc 实现方法 - (void)ysc_kvodealloc { @autoreleasepool { - if (!IsSystemClass(self.class)) { + if (!isSystemClass(self.class)) { NSString *value = (NSString *)objc_getAssociatedObject(self, KVODefenderKey); if ([value isEqualToString:KVODefenderValue]) { NSArray *keyPaths = [self.yscKVOProxy getAllKeyPaths]; @@ -297,7 +280,6 @@ - (void)ysc_kvodealloc { } } - [self ysc_kvodealloc]; } diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+MethodSwizzling.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+MethodSwizzling.h similarity index 63% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+MethodSwizzling.h rename to YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+MethodSwizzling.h index 0866d7d..2752492 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+MethodSwizzling.h +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+MethodSwizzling.h @@ -28,4 +28,20 @@ NS_ASSUME_NONNULL_BEGIN @end +// 判断是否是系统类 +static inline BOOL isSystemClass(Class cls) { + BOOL isSystem = NO; + NSString *className = NSStringFromClass(cls); + if ([className hasPrefix:@"NS"] || [className hasPrefix:@"__NS"] || [className hasPrefix:@"OS_xpc"]) { + isSystem = YES; + return isSystem; + } + NSBundle *mainBundle = [NSBundle bundleForClass:cls]; + if (mainBundle == [NSBundle mainBundle]) { + isSystem = NO; + }else{ + isSystem = YES; + } + return isSystem; +} NS_ASSUME_NONNULL_END diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+MethodSwizzling.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+MethodSwizzling.m similarity index 99% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+MethodSwizzling.m rename to YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+MethodSwizzling.m index e661d69..04687fb 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+MethodSwizzling.m +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+MethodSwizzling.m @@ -60,4 +60,5 @@ void swizzlingInstanceMethod(Class class, SEL originalSelector, SEL swizzledSele } } + @end diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+SelectorDefender.h b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+SelectorDefender.h similarity index 100% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+SelectorDefender.h rename to YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+SelectorDefender.h diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+SelectorDefender.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+SelectorDefender.m similarity index 95% rename from YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+SelectorDefender.m rename to YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+SelectorDefender.m index ff7a24c..d3c02f6 100644 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/NSObject+SelectorDefender.m +++ b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCDefender/NSObject+SelectorDefender.m @@ -55,7 +55,9 @@ + (id)ysc_forwardingTargetForSelector:(SEL)aSelector { // 创建一个新类 NSString *errClassName = NSStringFromClass([self class]); NSString *errSel = NSStringFromSelector(aSelector); - NSLog(@"出问题的类,出问题的类方法 == %@ %@", errClassName, errSel); + + NSLog(@"Crash Message: +[%@ %@]: unrecognized selector sent to class %p",errClassName, errSel, self); + NSString *className = @"CrachClass"; Class cls = NSClassFromString(className); @@ -105,7 +107,8 @@ - (id)ysc_forwardingTargetForSelector:(SEL)aSelector { // 创建一个新类 NSString *errClassName = NSStringFromClass([self class]); NSString *errSel = NSStringFromSelector(aSelector); - NSLog(@"出问题的类,出问题的对象方法 == %@ %@", errClassName, errSel); + + NSLog(@"Crash Message: -[%@ %@]: unrecognized selector sent to instance %p",errClassName, errSel, self); NSString *className = @"CrachClass"; Class cls = NSClassFromString(className); diff --git a/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.m b/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.m deleted file mode 100644 index aaf5237..0000000 --- a/YSC-Avoid-Crash/YSC-Avoid-Crash/YSCObject.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// YSCObject.m -// YSC-Avoid-Crash -// -// Created by WalkingBoy on 2019/8/16. -// Copyright © 2019 bujige. All rights reserved. -// - -#import "YSCObject.h" - -@implementation YSCObject - -@end