├── .DS_Store
├── .BayMaxProtector.podspec.swo
├── .BayMaxProtector.podspec.swp
├── DemoBayMaxProtector
├── DemoBayMaxProtector.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata
│ │ │ └── gujitao.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ └── gujitao.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── DemoBayMaxProtector
│ ├── Examples
│ │ ├── Vender
│ │ │ └── SVProgressHUD
│ │ │ │ └── SVProgressHUD
│ │ │ │ ├── SVProgressHUD.bundle
│ │ │ │ ├── info.png
│ │ │ │ ├── error.png
│ │ │ │ ├── error@2x.png
│ │ │ │ ├── error@3x.png
│ │ │ │ ├── info@2x.png
│ │ │ │ ├── info@3x.png
│ │ │ │ ├── success.png
│ │ │ │ ├── angle-mask.png
│ │ │ │ ├── success@2x.png
│ │ │ │ ├── success@3x.png
│ │ │ │ ├── angle-mask@2x.png
│ │ │ │ └── angle-mask@3x.png
│ │ │ │ ├── SVIndefiniteAnimatedView.h
│ │ │ │ ├── SVProgressHUD.h
│ │ │ │ └── SVIndefiniteAnimatedView.m
│ │ ├── KVO
│ │ │ ├── TestKVOErrorVC.h
│ │ │ └── TestKVOErrorVC.m
│ │ ├── Timer
│ │ │ ├── TestTimerErrorVC.h
│ │ │ └── TestTimerErrorVC.m
│ │ ├── Containers
│ │ │ ├── TestContainerVC.h
│ │ │ └── TestContainerVC.m
│ │ ├── Degrade
│ │ │ ├── AutoDegrade
│ │ │ │ ├── TestAutoDegradeVC.h
│ │ │ │ └── TestAutoDegradeVC.m
│ │ │ ├── Webview
│ │ │ │ ├── WebViewController.h
│ │ │ │ └── WebViewController.m
│ │ │ └── ManaulDegrade
│ │ │ │ ├── TestManaulDegradeVC.h
│ │ │ │ └── TestManaulDegradeVC.m
│ │ ├── NSNotifitication
│ │ │ ├── TestNotificationErrorVC.h
│ │ │ └── TestNotificationErrorVC.m
│ │ ├── UnrecognizedSelector
│ │ │ ├── TestViewDidloadUnrecognizedSelVC.h
│ │ │ ├── TestUnrecognizedSelVC.h
│ │ │ ├── TestViewDidloadUnrecognizedSelVC.m
│ │ │ └── TestUnrecognizedSelVC.m
│ │ └── Base
│ │ │ ├── BaseViewController.h
│ │ │ └── BaseViewController.m
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── AssistMicros.h
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── AppDelegate.m
│ └── ViewController.m
├── Podfile.lock
├── Podfile
├── DemoBayMaxProtectorTests
│ ├── Info.plist
│ └── DemoBayMaxProtectorTests.m
└── DemoBayMaxProtectorUITests
│ ├── Info.plist
│ └── DemoBayMaxProtectorUITests.m
├── Class
├── ARC
│ ├── BayMaxWeakProxy.h
│ ├── BayMaxDebugView.h
│ ├── BayMaxTimerSubTarget.h
│ ├── BayMaxKVODelegate.h
│ ├── BayMaxWeakProxy.m
│ ├── BayMaxProtector.h
│ ├── BayMaxCatchError.m
│ ├── BayMaxCatchError.h
│ ├── BayMaxTimerSubTarget.m
│ ├── BayMaxCFunctions.h
│ ├── BayMaxDegradeAssist.h
│ ├── BayMaxKVODelegate.m
│ ├── BayMaxDebugView.m
│ ├── BayMaxDegradeAssist.m
│ └── BayMaxProtector.m
├── BayMaxContainers.h
└── BayMaxContainers.m
├── .gitignore
├── BayMaxProtector.podspec
├── LICENSE
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/.DS_Store
--------------------------------------------------------------------------------
/.BayMaxProtector.podspec.swo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/.BayMaxProtector.podspec.swo
--------------------------------------------------------------------------------
/.BayMaxProtector.podspec.swp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/.BayMaxProtector.podspec.swp
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/info.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/error.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/error@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/error@2x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/error@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/error@3x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/info@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/info@2x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/info@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/info@3x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/success.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/angle-mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/angle-mask.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/success@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/success@2x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/success@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/success@3x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/angle-mask@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/angle-mask@2x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/angle-mask@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle/angle-mask@3x.png
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector.xcodeproj/project.xcworkspace/xcuserdata/gujitao.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunday1990/BayMaxProtector/HEAD/DemoBayMaxProtector/DemoBayMaxProtector.xcodeproj/project.xcworkspace/xcuserdata/gujitao.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/15.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/KVO/TestKVOErrorVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestKVOErrorVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BaseViewController.h"
11 |
12 | @interface TestKVOErrorVC : BaseViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Timer/TestTimerErrorVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestTimerErrorVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BaseViewController.h"
11 |
12 | @interface TestTimerErrorVC : BaseViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Containers/TestContainerVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestContainerVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BaseViewController.h"
11 |
12 | @interface TestContainerVC : BaseViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - BayMaxProtector (2.3.3)
3 |
4 | DEPENDENCIES:
5 | - BayMaxProtector (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | BayMaxProtector:
9 | :path: ../
10 |
11 | SPEC CHECKSUMS:
12 | BayMaxProtector: 224f77bb1965246f0dd579dc8fc312d87dcdbc4c
13 |
14 | PODFILE CHECKSUM: 33dc1d94d44cea8584ffbf5b4bc1aceb320f2546
15 |
16 | COCOAPODS: 1.4.0
17 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Degrade/AutoDegrade/TestAutoDegradeVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestAutoDegradeVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BaseViewController.h"
11 | @interface TestAutoDegradeVC : BaseViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Degrade/Webview/WebViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // WebViewController.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/18.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface WebViewController : UIViewController
12 | @property (nonatomic, copy) NSString *url;
13 | @end
14 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/15.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/NSNotifitication/TestNotificationErrorVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestNotificationErrorVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BaseViewController.h"
11 |
12 | @interface TestNotificationErrorVC : BaseViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/UnrecognizedSelector/TestViewDidloadUnrecognizedSelVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestViewDidloadUnrecognizedSelVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/2.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BaseViewController.h"
10 |
11 | @interface TestViewDidloadUnrecognizedSelVC : BaseViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/15.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Degrade/ManaulDegrade/TestManaulDegradeVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestManaulDegradeVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BaseViewController.h"
11 | @interface TestManaulDegradeVC : BaseViewController
12 | @property (nonatomic, copy) NSString *uid;
13 | @property (nonatomic, copy) NSString *type;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/UnrecognizedSelector/TestUnrecognizedSelVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestUnrecognizedSelVC.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BaseViewController.h"
11 |
12 | @interface TestUnrecognizedSelVC : BaseViewController
13 | @property (nonatomic,copy)NSString *userName;
14 | @property (nonatomic,copy)NSString *userID;
15 | @end
16 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector.xcodeproj/xcuserdata/gujitao.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DemoBayMaxProtector.xcscheme
8 |
9 | orderHint
10 | 4
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxWeakProxy.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxWeakProxy.h
3 | // zgzf
4 | //
5 | // Created by zhugefang on 2018/8/11.
6 | // Copyright © 2018年 zgzf. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface BayMaxWeakProxy : NSObject
14 | @property (nullable, nonatomic, weak, readonly) id target;
15 |
16 | - (instancetype)initWithTarget:(id)target;
17 |
18 | + (instancetype)proxyWithTarget:(id)target;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Base/BaseViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewController.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BayMaxProtector.h"
11 | #import "AssistMicros.h"
12 | @interface BaseViewController : UIViewController
13 |
14 | @end
15 |
16 | @interface NSString (BreadcrumbStringSize)
17 | - (CGFloat)widthForFont:(UIFont *)font;
18 | @end
19 |
20 |
21 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVIndefiniteAnimatedView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVIndefiniteAnimatedView.h
3 | // SVProgressHUD
4 | //
5 | // Created by Guillaume Campagna on 2014-12-05.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface SVIndefiniteAnimatedView : UIView
12 |
13 | @property (nonatomic, assign) CGFloat strokeThickness;
14 | @property (nonatomic, assign) CGFloat radius;
15 | @property (nonatomic, strong) UIColor *strokeColor;
16 |
17 | @end
18 |
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 | *.xcworkspace/
20 |
21 | ## Other
22 | *.moved-aside
23 | *.xccheckout
24 | *.xcscmblueprint
25 |
26 | #CocoaPods
27 | Pods
28 | *.DS_Store
29 | !Podfile
30 | !Podfile.lock
31 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/AssistMicros.h:
--------------------------------------------------------------------------------
1 | //
2 | // AssistMicros.h
3 | // TreeNodeStructure
4 | //
5 | // Created by ccSunday on 2018/1/30.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #ifndef AssistMicros_h
10 | #define AssistMicros_h
11 | #import "SVProgressHUD.h"
12 |
13 | #define HEIGHT [UIScreen mainScreen].bounds.size.height
14 | #define WIDTH [UIScreen mainScreen].bounds.size.width
15 |
16 | #define DEFAULT_COLOR [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1]
17 |
18 | #endif /* AssistMicros_h */
19 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxDebugView.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxDebugView.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 |
8 | //功能:
9 | //1、当有错误信息的时候,加红展示,并记录错误信息的数目,有多少错误信息就展示多少。
10 | //2、当点击后展示所有的错误信息
11 | //3、当收起后,计数清零,错误信息清空。
12 | //4、可以跟随手指移动
13 |
14 |
15 | #import
16 |
17 | @interface BayMaxDebugView : UIView
18 | /**
19 | 获取DebugView单例
20 |
21 | @return DebugView
22 | */
23 | + (instancetype _Nonnull )sharedDebugView;
24 |
25 | - (void)addErrorInfo:(NSDictionary *_Nonnull)errorInfo;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'DemoBayMaxProtector' do
5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
6 | # use_frameworks!
7 |
8 | # Pods for DemoBayMaxProtector
9 | pod 'BayMaxProtector', :path=> '../'
10 |
11 | target 'DemoBayMaxProtectorTests' do
12 | inherit! :search_paths
13 | # Pods for testing
14 | end
15 |
16 | target 'DemoBayMaxProtectorUITests' do
17 | inherit! :search_paths
18 | # Pods for testing
19 | end
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/BayMaxProtector.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "BayMaxProtector"
3 | s.version = "2.3.3"
4 | s.summary = "Crash protector--Take care of your application like BayMax"
5 | s.homepage = "https://github.com/sunday1990/BayMaxProtector"
6 | s.license = "MIT"
7 | s.author = { "ccSunday" => "935143023@qq.com" }
8 | s.platform = :ios, "8.0"
9 | s.source = { :git => "https://github.com/sunday1990/BayMaxProtector.git", :tag => "v2.3.3" }
10 | s.social_media_url = "https://github.com/sunday1990/BayMaxProtector"
11 | s.source_files = 'Class/**/*.{h,m}'
12 | s.requires_arc = false
13 | s.requires_arc = ['Class/ARC/*']
14 | end
15 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxTimerSubTarget.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxTimerSubTarget.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/16.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BayMaxCFunctions.h"
11 |
12 | @interface BayMaxTimerSubTarget : NSObject
13 |
14 | /**
15 | BayMaxTimerSubTarget初始化方法
16 |
17 | @param ti ti
18 | @param aTarget aTarget
19 | @param aSelector aSelector
20 | @param userInfo userInfo
21 | @param yesOrNo yesOrNo
22 | @param errorHandler 错误回调
23 | @return subTarget实例
24 | */
25 | + (instancetype)targetWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo catchErrorHandler:(void(^)(BayMaxCatchError * error))errorHandler;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtectorTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtectorUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtectorTests/DemoBayMaxProtectorTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // DemoBayMaxProtectorTests.m
3 | // DemoBayMaxProtectorTests
4 | //
5 | // Created by 顾吉涛 on 2018/3/14.
6 | // Copyright © 2018年 顾吉涛. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DemoBayMaxProtectorTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation DemoBayMaxProtectorTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017-2019 BayMax (https://github.com/sunday1990/BayMaxProtector)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtectorUITests/DemoBayMaxProtectorUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // DemoBayMaxProtectorUITests.m
3 | // DemoBayMaxProtectorUITests
4 | //
5 | // Created by 顾吉涛 on 2018/3/14.
6 | // Copyright © 2018年 顾吉涛. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DemoBayMaxProtectorUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation DemoBayMaxProtectorUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Degrade/AutoDegrade/TestAutoDegradeVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestAutoDegradeVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestAutoDegradeVC.h"
10 |
11 | @interface TestAutoDegradeVC ()
12 |
13 | @end
14 |
15 | @implementation TestAutoDegradeVC
16 | #pragma mark ======== Life Cycle ========
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view.
20 |
21 |
22 | }
23 |
24 | - (void)didReceiveMemoryWarning {
25 | [super didReceiveMemoryWarning];
26 | // Dispose of any resources that can be recreated.
27 | }
28 |
29 | #pragma mark ======== NetWork ========
30 |
31 | #pragma mark ======== System Delegate ========
32 |
33 | #pragma mark ======== Custom Delegate ========
34 |
35 | #pragma mark ======== Notifications && Observers ========
36 |
37 | #pragma mark ======== Event Response ========
38 |
39 | #pragma mark ======== Private Methods ========
40 |
41 | #pragma mark ======== Setters && Getters ========
42 |
43 | /*
44 | #pragma mark - Navigation
45 |
46 | // In a storyboard-based application, you will often want to do a little preparation before navigation
47 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
48 | // Get the new view controller using [segue destinationViewController].
49 | // Pass the selected object to the new view controller.
50 | }
51 | */
52 |
53 | @end
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxKVODelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxKVODelegate.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/12.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BayMaxKVODelegate : NSObject
12 |
13 | /**
14 | 将添加kvo时的相关信息加入到关系maps中,对应原有的添加观察者
15 | 带成功和失败的回调
16 |
17 | @param observer observer观察者
18 | @param keyPath keyPath
19 | @param options options
20 | @param context context
21 | @param success success 成功的回调
22 | @param failure failure 失败的回调
23 | */
24 | - (void)addKVOInfoToMapsWithObserver:(NSObject *)observer
25 | forKeyPath:(NSString *)keyPath
26 | options:(NSKeyValueObservingOptions)options
27 | context:(void *)context
28 | success:(void(^)(void))success
29 | failure:(void(^)(NSError *error))failure;
30 |
31 | /**
32 | 将添加kvo时的相关信息加入到关系maps中,对应原有的添加观察者
33 | 不带成功和失败的回调
34 | @param observer 实际观察者
35 | @param keyPath keyPath
36 | @param options options
37 | @param context context
38 | @return return 是否添加成功
39 | */
40 | - (BOOL)addKVOInfoToMapsWithObserver:(NSObject *)observer
41 | forKeyPath:(NSString *)keyPath
42 | options:(NSKeyValueObservingOptions)options
43 | context:(void *)context;
44 |
45 | /**
46 | 从关系maps中移除观察者 对应原有的移除观察者操作
47 |
48 | @param observer 实际观察者
49 | @param keyPath keypath
50 | @return 是否移除成功
51 | 如果重复移除,会返回NO
52 | */
53 | - (BOOL)removeKVOInfoInMapsWithObserver:(NSObject *)observer
54 | forKeyPath:(NSString *)keyPath;
55 |
56 | - (NSArray *)getAllKeypaths;
57 | @end
58 |
59 |
60 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 | CFBundleDevelopmentRegion
11 | $(DEVELOPMENT_LANGUAGE)
12 | CFBundleExecutable
13 | $(EXECUTABLE_NAME)
14 | CFBundleIdentifier
15 | $(PRODUCT_BUNDLE_IDENTIFIER)
16 | CFBundleInfoDictionaryVersion
17 | 6.0
18 | CFBundleName
19 | $(PRODUCT_NAME)
20 | CFBundlePackageType
21 | APPL
22 | CFBundleShortVersionString
23 | 1.0
24 | CFBundleVersion
25 | 1
26 | LSRequiresIPhoneOS
27 |
28 | UILaunchStoryboardName
29 | LaunchScreen
30 | UIMainStoryboardFile
31 | Main
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxWeakProxy.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxWeakProxy.m
3 | // zgzf
4 | //
5 | // Created by zhugefang on 2018/8/11.
6 | // Copyright © 2018年 zgzf. All rights reserved.
7 | //
8 |
9 | #import "BayMaxWeakProxy.h"
10 |
11 | @implementation BayMaxWeakProxy
12 | - (instancetype)initWithTarget:(id)target {
13 | _target = target;
14 | return self;
15 | }
16 |
17 | + (instancetype)proxyWithTarget:(id)target {
18 | return [[BayMaxWeakProxy alloc] initWithTarget:target];
19 | }
20 |
21 | - (id)forwardingTargetForSelector:(SEL)selector {
22 | return _target;
23 | }
24 |
25 | - (void)forwardInvocation:(NSInvocation *)invocation {
26 | void *null = NULL;
27 | [invocation setReturnValue:&null];
28 | }
29 |
30 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
31 | return [NSObject instanceMethodSignatureForSelector:@selector(init)];
32 | }
33 |
34 | - (BOOL)respondsToSelector:(SEL)aSelector {
35 | return [_target respondsToSelector:aSelector];
36 | }
37 |
38 | - (BOOL)isEqual:(id)object {
39 | return [_target isEqual:object];
40 | }
41 |
42 | - (NSUInteger)hash {
43 | return [_target hash];
44 | }
45 |
46 | - (Class)superclass {
47 | return [_target superclass];
48 | }
49 |
50 | - (Class)class {
51 | return [_target class];
52 | }
53 |
54 | - (BOOL)isKindOfClass:(Class)aClass {
55 | return [_target isKindOfClass:aClass];
56 | }
57 |
58 | - (BOOL)isMemberOfClass:(Class)aClass {
59 | return [_target isMemberOfClass:aClass];
60 | }
61 |
62 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol {
63 | return [_target conformsToProtocol:aProtocol];
64 | }
65 |
66 | - (BOOL)isProxy {
67 | return YES;
68 | }
69 |
70 | - (NSString *)description {
71 | return [_target description];
72 | }
73 |
74 | - (NSString *)debugDescription {
75 | return [_target debugDescription];
76 | }
77 | @end
78 |
--------------------------------------------------------------------------------
/Class/BayMaxContainers.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxContainers.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/14.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | //针对NSArray/NSMutableArray/NSDictionary/NSMutableDictionary/NSString/NSMutableString进行崩溃保护
10 | /*
11 | ===============================
12 | //insertNil
13 | NSArray->Methods On Protection:
14 | 1、@[nil]
15 | 2、arrayWithObjects:count:
16 | 3、objectAtIndex:
17 |
18 | ===============================
19 |
20 | NSMutableArray->Methods On Protection:
21 | 0、arrayWithObjects:nil
22 | 1、objectAtIndex:
23 | 2、removeObjectAtIndex:
24 | 3、removeObjectsInRange:
25 | 5、insertObject:atIndex:
26 | 6、insertObjects:atIndexes:
27 | 7、addObject:nil
28 | 8、replaceObjectAtIndex:withObject:
29 | 9、replaceObjectsAtIndexes:withObjects:
30 | 10、replaceObjectsInRange:withObjectsFromArray:
31 |
32 | ===============================
33 | NSDictionary->Methods On Protection:
34 | 1 @{nil:nil}
35 | 2、dictionaryWithObject:forKey:
36 | 3、dictionaryWithObjects:forKeys:
37 | 4、dictionaryWithObjects:forKeys:count:
38 |
39 | ===============================
40 | NSMutableDictionary->Methods On Protection:
41 | 1、setObject:forKey:
42 | 2、removeObjectForKey:
43 | ===============================
44 | NSString->Methods On Protection:
45 | 1、characterAtIndex:
46 | 2、substringFromIndex:
47 | 3、substringToIndex:
48 | 4、substringWithRange:
49 |
50 | ===============================
51 | NSMutableString->Methods On Protection:
52 | 2、insertString:atIndex:
53 | 3、deleteCharactersInRange:
54 | */
55 |
56 | #import
57 |
58 | @class BayMaxCatchError;
59 | @interface BayMaxContainers : NSObject
60 | /**
61 | swizzle容器类方法
62 |
63 | @param errorHandler 错误回调
64 | */
65 | + (void)BMPExchangeContainersMethodsWithCatchErrorHandler:(void(^)(BayMaxCatchError * error))errorHandler;
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/NSNotifitication/TestNotificationErrorVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestNotificationErrorVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestNotificationErrorVC.h"
10 |
11 | @interface TestNotificationErrorVC ()
12 |
13 | @end
14 |
15 | @implementation TestNotificationErrorVC
16 | #pragma mark ======== Life Cycle ========
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view.
20 | [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notifyEvent) name:UITextViewTextDidChangeNotification object:nil];
21 | UILabel *tipLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 40, WIDTH-20, 200)];
22 | tipLabel.font = [UIFont systemFontOfSize:14];
23 | tipLabel.textColor = [UIColor darkTextColor];
24 | tipLabel.numberOfLines = 0;
25 | tipLabel.text = @"针对NSNotificationCenter的防护不多,主要是在未移除监听者的时候,自动帮你移除监听者";
26 | [self.view addSubview:tipLabel];
27 |
28 | }
29 |
30 | - (void)notifyEvent{
31 |
32 |
33 | }
34 |
35 | - (void)didReceiveMemoryWarning {
36 | [super didReceiveMemoryWarning];
37 | // Dispose of any resources that can be recreated.
38 | }
39 |
40 | #pragma mark ======== NetWork ========
41 |
42 | #pragma mark ======== System Delegate ========
43 |
44 | #pragma mark ======== Custom Delegate ========
45 |
46 | #pragma mark ======== Notifications && Observers ========
47 |
48 | #pragma mark ======== Event Response ========
49 |
50 | #pragma mark ======== Private Methods ========
51 |
52 | #pragma mark ======== Setters && Getters ========
53 |
54 | /*
55 | #pragma mark - Navigation
56 |
57 | // In a storyboard-based application, you will often want to do a little preparation before navigation
58 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
59 | // Get the new view controller using [segue destinationViewController].
60 | // Pass the selected object to the new view controller.
61 | }
62 | */
63 |
64 | @end
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxProtector.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxProtector.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2017/3/23.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BayMaxCatchError.h"
11 |
12 | typedef NS_ENUM(NSInteger, BayMaxProtectionType) {
13 | /*开启全部保护*/
14 | BayMaxProtectionTypeAll = 0,
15 | /*UnrecognizedSelector保护*/
16 | BayMaxProtectionTypeUnrecognizedSelector = 1<<0,
17 | /*KVO保护*/
18 | BayMaxProtectionTypeKVO = 1<<1,
19 | /*Notification*/
20 | BayMaxProtectionTypeNotification = 1<<2,
21 | /*Timer保护*/
22 | BayMaxProtectionTypeTimer = 1<<3,
23 | /*Containers保护:包括NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、NSString、NSMutableString*/
24 | BayMaxProtectionTypeContainers = 1<<4,
25 | /*BadAccess(onPending)*/
26 | BayMaxProtectionTypeBadAccess = 1<<5
27 | };
28 |
29 | @interface BayMaxProtector : NSObject
30 |
31 | /**
32 | 开启崩溃保护(支持或运算、自动过滤重复开启的操作)
33 |
34 | @param protectionType 要保护的类型protectionType
35 | */
36 | + (void)openProtectionsOn:(BayMaxProtectionType)protectionType;
37 |
38 | /**
39 | 开启崩溃保护(支持或运算并且带错误回调,不支持自动过滤重复操作)
40 |
41 | @param protectionType 保护类型
42 | @param errorHandler 错误回调
43 | */
44 | + (void)openProtectionsOn:(BayMaxProtectionType)protectionType catchErrorHandler:(void(^_Nullable)(BayMaxCatchError * _Nullable error))errorHandler;
45 |
46 | /**
47 | 设置白名单
48 | 作用:忽略对具有以下指定前缀的类的保护,原因一是减少不必要的操作,二是避免kvo异常发生错误,如一些三方库。
49 | 已默认忽略大部分系统类
50 | 使用:如果想忽略带有百度地图“BMK”前缀的类,那么ignorePrefixes为@[@"BMK"]即可。
51 |
52 | 注意:该设置对unrecognizedSelctor错误不起作用。
53 |
54 | @param ignorePrefixes 要忽略的类的前缀
55 | */
56 | + (void)ignoreProtectionsOnClassesWithPrefix:(NSArray *_Nonnull)ignorePrefixes;
57 |
58 | /**
59 | 关闭崩溃保护(支持或运算、自动过滤重复关闭或者之前没有开启过防护的操作)
60 |
61 | @param protectionType 要关闭的类型
62 | */
63 | + (void)closeProtectionsOn:(BayMaxProtectionType)protectionType;
64 |
65 | /**
66 | 显示debugView,可在任意页面开启
67 | 点击后,会将错误信息显示出来
68 | */
69 | + (void)showDebugView;
70 |
71 | /**
72 | 隐藏debugView,可在任意页面关闭
73 | */
74 | + (void)hideDebugView;
75 |
76 | @end
77 |
78 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/UnrecognizedSelector/TestViewDidloadUnrecognizedSelVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestViewDidloadUnrecognizedSelVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/2.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestViewDidloadUnrecognizedSelVC.h"
10 |
11 | @interface TestViewDidloadUnrecognizedSelVC ()
12 |
13 | @end
14 |
15 | @implementation TestViewDidloadUnrecognizedSelVC
16 | #pragma mark ======== Life Cycle ========
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view.
20 | [[NSNull null]performSelector:@selector(length)];
21 | [self performSelector:@selector(abc)];
22 |
23 | UILabel *tipLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 40, WIDTH-20, 150)];
24 | tipLabel.font = [UIFont systemFontOfSize:14];
25 | tipLabel.textColor = [UIColor darkTextColor];
26 | tipLabel.numberOfLines = 0;
27 | tipLabel.text = @"1、ViewDidload中发生两个错误,一个是向NSNull对象发送length消息,还有一个就是向ViewController发送abc消息,这些都是未曾定义,在它们的方法列表中找不到的方法。\n2、针对这种页面进行降级,可以取到对应页面的URL,但是它的参数暂时拿不到。\n 3、当获取到配置后,在进入该页面会直接展示对应的H5页面";
28 | [self.view addSubview:tipLabel];
29 | }
30 |
31 | - (void)didReceiveMemoryWarning {
32 | [super didReceiveMemoryWarning];
33 | // Dispose of any resources that can be recreated.
34 | }
35 |
36 | #pragma mark ======== NetWork ========
37 |
38 | #pragma mark ======== System Delegate ========
39 |
40 | #pragma mark ======== Custom Delegate ========
41 |
42 | #pragma mark ======== Notifications && Observers ========
43 |
44 | #pragma mark ======== Event Response ========
45 |
46 | #pragma mark ======== Private Methods ========
47 |
48 | #pragma mark ======== Setters && Getters ========
49 |
50 | /*
51 | #pragma mark - Navigation
52 |
53 | // In a storyboard-based application, you will often want to do a little preparation before navigation
54 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
55 | // Get the new view controller using [segue destinationViewController].
56 | // Pass the selected object to the new view controller.
57 | }
58 | */
59 |
60 | @end
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxCatchError.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxCatchError.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/18.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BayMaxCatchError.h"
10 |
11 | NSString *const BMPErrorCallStackSymbols = @"ErrorCallStackSymbols";
12 |
13 | NSString *const BMPErrorUnrecognizedSel_Receiver = @"ErrorObject";
14 | NSString *const BMPErrorUnrecognizedSel_Func = @"ErrorSelector";
15 | NSString *const BMPErrorUnrecognizedSel_VC = @"ErrorViewController";
16 | NSString *const BMPErrorUnrecognizedSel_Reason = @"ErrorReason";
17 |
18 | NSString *const BMPErrorKVO_Observer = @"ErrorObserver";
19 | NSString *const BMPErrorKVO_Keypath = @"ErrorKeypath";
20 | NSString *const BMPErrorKVO_Target = @"ErrorKeypathFrom";
21 | NSString *const BMPErrorKVO_Reason = @"ErrorReason";
22 |
23 | NSString *const BMPErrorTimer_Target = @"ErrorTarget";
24 | NSString *const BMPErrorTimer_Reason = @"ErrorReason";
25 |
26 |
27 | NSString *const BMPErrorArray_Beyond = @"ArrayBeyondBounds";
28 | NSString *const BMPErrorArray_NilObject = @"ArrayInsertNil";
29 |
30 | NSString *const BMPErrorDictionary_NilKey = @"DictionaryNilKey";
31 | NSString *const BMPErrorDictionary_UndefinedKey = @"DictionaryUndefinedKey";
32 |
33 | NSString *const BMPErrorString_Beyond = @"StringOutOfBounds";
34 |
35 | @implementation BayMaxCatchError
36 | + (instancetype)BMPErrorWithType:(BayMaxErrorType)errorType infos:(NSDictionary *)errorInfos{
37 | return [[self alloc]initWithType:errorType infos:errorInfos];
38 | }
39 |
40 | - (instancetype)initWithType:(BayMaxErrorType)errorType infos:(NSDictionary *)errorInfos{
41 | if (self = [super init]) {
42 | self.errorType = errorType;
43 | self.errorInfos = errorInfos;
44 | }
45 | return self;
46 | }
47 |
48 | - (NSString *)errorName{
49 | if (!_errorName) {
50 | _errorName = @"BayMaxProtector拦截到的错误";
51 | }
52 | return _errorName;
53 | }
54 |
55 | - (NSArray *)errorCallStackSymbols{
56 | if (!_errorCallStackSymbols) {
57 | if ([self.errorInfos.allKeys containsObject:BMPErrorCallStackSymbols]) {
58 | _errorCallStackSymbols = [self.errorInfos objectForKey:BMPErrorCallStackSymbols];
59 | }else{
60 | _errorCallStackSymbols = @[];
61 | }
62 | }
63 | return _errorCallStackSymbols;
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxCatchError.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxCatchError.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/18.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | FOUNDATION_EXPORT NSString *const BMPErrorCallStackSymbols;
12 |
13 | /*发生错误的类或者对象*/
14 | FOUNDATION_EXPORT NSString *const BMPErrorUnrecognizedSel_Receiver;
15 | /*发生错误的方法*/
16 | FOUNDATION_EXPORT NSString *const BMPErrorUnrecognizedSel_Func;
17 | /*发生错误的视图控制器*/
18 | FOUNDATION_EXPORT NSString *const BMPErrorUnrecognizedSel_VC;
19 | /*发生错误的原因简述*/
20 | FOUNDATION_EXPORT NSString *const BMPErrorUnrecognizedSel_Reason;
21 |
22 |
23 | /*发生KVO重复监听错误的observer*/
24 | FOUNDATION_EXPORT NSString *const BMPErrorKVO_Observer;
25 | /*发生KVO重复监听错误的keypath*/
26 | FOUNDATION_EXPORT NSString *const BMPErrorKVO_Keypath;
27 | /*被重复观察的target*/
28 | FOUNDATION_EXPORT NSString *const BMPErrorKVO_Target;
29 | /*错误原因简述*/
30 | FOUNDATION_EXPORT NSString *const BMPErrorKVO_Reason;
31 |
32 | /*timer绑定的target*/
33 | FOUNDATION_EXPORT NSString *const BMPErrorTimer_Target;
34 | /*timer错误原因简述*/
35 | FOUNDATION_EXPORT NSString *const BMPErrorTimer_Reason;
36 |
37 | /*Containers错误原因描述*/
38 | /*数组越界*/
39 | FOUNDATION_EXPORT NSString *const BMPErrorArray_Beyond;
40 | /*数组insert nil*/
41 | FOUNDATION_EXPORT NSString *const BMPErrorArray_NilObject;
42 | /*字典Nil key*/
43 | FOUNDATION_EXPORT NSString *const BMPErrorDictionary_NilKey;
44 | /*字典 undefinedKey*/
45 | FOUNDATION_EXPORT NSString *const BMPErrorDictionary_UndefinedKey;
46 | /*String out of bounds*/
47 | FOUNDATION_EXPORT NSString *const BMPErrorString_Beyond;
48 |
49 | typedef NS_ENUM(NSInteger, BayMaxErrorType) {
50 | /*UnrecognizedSelector异常*/
51 | BayMaxErrorTypeUnrecognizedSelector = 1,
52 | /*KVO异常*/
53 | BayMaxErrorTypeKVO,
54 | /*Notification异常*/
55 | BayMaxErrorTypeNotification,
56 | /*Timer异常*/
57 | BayMaxErrorTypeTimer,
58 | /*Containers*/
59 | BayMaxErrorTypeContainers
60 | };
61 |
62 | @interface BayMaxCatchError : NSObject
63 |
64 | /**
65 | 错误类型
66 | */
67 | @property (nonatomic, assign) BayMaxErrorType errorType;
68 | /**
69 | 错误信息字典,通过相对应的key获取
70 | */
71 | @property (nonatomic, copy) NSDictionary *errorInfos;
72 | /**
73 | 错误标题
74 | */
75 | @property (nonatomic, copy) NSString *errorName;
76 | /**
77 | 错误堆栈
78 | */
79 | @property (nonatomic, copy) NSArray *errorCallStackSymbols;
80 |
81 | /**
82 | 初始化方法
83 |
84 | @param errorType 错误类型
85 | @param errorInfos 错误信息字典
86 | @return 错误实例
87 | */
88 | + (instancetype)BMPErrorWithType:(BayMaxErrorType)errorType infos:(NSDictionary *)errorInfos;
89 |
90 | @end
91 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Degrade/Webview/WebViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // WebViewController.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/18.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "WebViewController.h"
10 | #import
11 | #import "AssistMicros.h"
12 |
13 | @interface WebViewController ()
14 | {
15 | WKWebView *_webview;
16 | }
17 | @end
18 |
19 | @implementation WebViewController
20 | #pragma mark ======== Life Cycle ========
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 |
24 | // Do any additional setup after loading the view.
25 | _webview = [[WKWebView alloc]initWithFrame:self.view.bounds];
26 | _webview.backgroundColor = [UIColor whiteColor];
27 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:_url]];
28 | request.timeoutInterval = 20;
29 | [_webview loadRequest:request];
30 | [self.view addSubview:_webview];
31 |
32 | UIButton *dismissBtn = [UIButton buttonWithType:UIButtonTypeCustom];
33 | dismissBtn.frame = CGRectMake(12, 12, 40, 40);
34 | [dismissBtn setTitle:@"返回" forState:UIControlStateNormal];
35 | [dismissBtn setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
36 | dismissBtn.titleLabel.font = [UIFont systemFontOfSize:13];
37 | dismissBtn.backgroundColor = DEFAULT_COLOR;
38 | dismissBtn.layer.cornerRadius = 6;
39 | [dismissBtn addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
40 | [self.view addSubview:dismissBtn];
41 | }
42 |
43 | - (void)dismiss{
44 | [self dismissViewControllerAnimated:YES completion:nil];
45 | }
46 |
47 | - (void)didReceiveMemoryWarning {
48 | [super didReceiveMemoryWarning];
49 | // Dispose of any resources that can be recreated.
50 | }
51 |
52 | #pragma mark ======== NetWork ========
53 |
54 | #pragma mark ======== System Delegate ========
55 |
56 | #pragma mark ======== Custom Delegate ========
57 |
58 | #pragma mark ======== Notifications && Observers ========
59 |
60 | #pragma mark ======== Event Response ========
61 |
62 | #pragma mark ======== Private Methods ========
63 |
64 | #pragma mark ======== Setters && Getters ========
65 | - (void)dealloc{
66 | NSLog(@"dealloc webviewcontroller");
67 | }
68 | /*
69 | #pragma mark - Navigation
70 |
71 | // In a storyboard-based application, you will often want to do a little preparation before navigation
72 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
73 | // Get the new view controller using [segue destinationViewController].
74 | // Pass the selected object to the new view controller.
75 | }
76 | */
77 |
78 | @end
79 |
80 |
81 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxTimerSubTarget.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxTimerSubTarget.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/16.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BayMaxTimerSubTarget.h"
10 | #import "BayMaxCatchError.h"
11 |
12 | BMPErrorHandler _Nullable _timerErrorHandler;
13 |
14 | @implementation BayMaxTimerSubTarget{
15 | @package
16 | NSTimeInterval _ti;
17 | __weak id _aTarget;
18 | SEL _aSelector;
19 | __weak id _userInfo;
20 | BOOL _yesOrNo;
21 | NSString *_targetClassName;
22 | }
23 |
24 | + (instancetype)targetWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo catchErrorHandler:(void(^)(BayMaxCatchError * error))errorHandler{
25 | return [[self alloc]initWithTimeInterval:ti target:aTarget selector:aSelector userInfo:userInfo repeats:yesOrNo catchErrorHandler:errorHandler];
26 | }
27 |
28 | - (instancetype)initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo catchErrorHandler:(void(^)(BayMaxCatchError * error))errorHandler{
29 | if (self = [super init]) {
30 | _ti = ti;
31 | _aTarget = aTarget;
32 | _aSelector = aSelector;
33 | _userInfo = userInfo;
34 | _yesOrNo = yesOrNo;
35 | _targetClassName = NSStringFromClass([aTarget class]);
36 | _timerErrorHandler = errorHandler;
37 | }
38 | return self;
39 | }
40 |
41 | - (void)fireProxyTimer:(NSTimer *)timer{
42 | if (_aTarget) {
43 | if ([_aTarget respondsToSelector:_aSelector]) {
44 | BMP_SuppressPerformSelectorLeakWarning(
45 | [_aTarget performSelector:_aSelector withObject:timer];
46 | );
47 | }
48 | }else{
49 | //报错
50 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
51 | NSString *errorDes = [NSString stringWithFormat:@"Timer %@ did not invalidate in Class<%@>",timer,_targetClassName];
52 | BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeTimer infos:@{
53 | BMPErrorTimer_Target:_targetClassName == nil?@"":_targetClassName, BMPErrorTimer_Reason:errorDes, BMPErrorCallStackSymbols:callStackSymbolsArr
54 | }];
55 | if (_timerErrorHandler) {
56 | _timerErrorHandler(bmpError);
57 | }
58 | [timer invalidate];
59 | timer = nil;
60 | }
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Timer/TestTimerErrorVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestTimerErrorVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestTimerErrorVC.h"
10 |
11 | @interface TestTimerErrorVC ()
12 | {
13 | NSTimer *_timer;
14 | }
15 | @end
16 |
17 | @implementation TestTimerErrorVC
18 | #pragma mark ======== Life Cycle ========
19 | - (void)viewDidLoad {
20 | [super viewDidLoad];
21 | // Do any additional setup after loading the view.
22 | //_timer未移除
23 | _timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerEvent) userInfo:nil repeats:YES];
24 | [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
25 |
26 | UILabel *tipLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 40, WIDTH-20, 200)];
27 | tipLabel.font = [UIFont systemFontOfSize:14];
28 | tipLabel.textColor = [UIColor darkTextColor];
29 | tipLabel.numberOfLines = 0;
30 | tipLabel.text = @"针对NSTimer的两个类方法进行保护,一个是+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo,另一个是scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo,退出页面时,会自动invalid计时器";
31 | [self.view addSubview:tipLabel];
32 |
33 | }
34 |
35 | - (void)viewWillAppear:(BOOL)animated{
36 | [super viewWillAppear:animated];
37 |
38 | }
39 |
40 | - (void)viewDidAppear:(BOOL)animated{
41 | [super viewDidAppear:animated];
42 | }
43 |
44 | - (void)viewDidDisappear:(BOOL)animated{
45 | [super viewDidDisappear:animated];
46 | // [_timer invalidate];
47 | // _timer = nil;
48 | }
49 |
50 | - (void)didReceiveMemoryWarning {
51 | [super didReceiveMemoryWarning];
52 | // Dispose of any resources that can be recreated.
53 | }
54 |
55 | #pragma mark ======== NetWork ========
56 |
57 | #pragma mark ======== System Delegate ========
58 |
59 | #pragma mark ======== Custom Delegate ========
60 |
61 | #pragma mark ======== Notifications && Observers ========
62 |
63 | #pragma mark ======== Event Response ========
64 | - (void)timerEvent{
65 | NSLog(@"timer");
66 | }
67 |
68 | - (void)time1Event{
69 | NSLog(@"timer1");
70 | }
71 |
72 | #pragma mark ======== Private Methods ========
73 |
74 | #pragma mark ======== Setters && Getters ========
75 |
76 | /*
77 | #pragma mark - Navigation
78 |
79 | // In a storyboard-based application, you will often want to do a little preparation before navigation
80 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
81 | // Get the new view controller using [segue destinationViewController].
82 | // Pass the selected object to the new view controller.
83 | }
84 | */
85 |
86 | @end
87 |
88 |
89 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxCFunctions.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxCFunctions.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/22.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #ifndef BayMaxCFunctions_h
12 | #define BayMaxCFunctions_h
13 |
14 | #define BMP_SuppressPerformSelectorLeakWarning(Stuff)\
15 | do { \
16 | _Pragma("clang diagnostic push") \
17 | _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
18 | Stuff; \
19 | _Pragma("clang diagnostic pop") \
20 | } while (0)
21 | @class BayMaxCatchError;
22 |
23 | typedef void(^BMPErrorHandler)(BayMaxCatchError * error);
24 |
25 | typedef struct IMPNode *PtrToIMP;
26 | typedef PtrToIMP IMPlist;
27 | struct IMPNode{
28 | IMP imp;
29 | PtrToIMP next;
30 | };
31 |
32 | /*向IMP链表中追加imp*/
33 | static inline void BMP_InsertIMPToList(IMPlist list,IMP imp){
34 | PtrToIMP nextNode = malloc(sizeof(struct IMPNode));
35 | nextNode->imp = imp;
36 | nextNode->next = list->next;
37 | list->next = nextNode;
38 | }
39 |
40 | /*判断IMP链表中有没有此元素。
41 | 注意:libobjc中的c函数无效,这时候需要通过手动建立映射关系来替代
42 | */
43 | static inline BOOL BMP_ImpExistInList(IMPlist list, IMP imp){
44 | if (list->imp == imp) {
45 | return YES;
46 | }else{
47 | if (list->next != NULL) {
48 | return BMP_ImpExistInList(list->next,imp);
49 | }else{
50 | return NO;
51 | }
52 | }
53 | }
54 |
55 | struct ErrorBody{
56 | const char *function_name;
57 | const char *function_class;
58 | };
59 | typedef struct ErrorBody ErrorInfos;
60 | /*创建错误信息*/
61 | static inline ErrorInfos ErrorInfosMake(const char *function_class,const char *function_name)
62 | {
63 | ErrorInfos errorInfos;
64 | errorInfos.function_name = function_name;
65 | errorInfos.function_class = function_class;
66 | return errorInfos;
67 | }
68 | /*交换实例方法*/
69 | static inline void BMP_EXChangeInstanceMethod(Class _originalClass ,SEL _originalSel,Class _targetClass ,SEL _targetSel){
70 | Method methodOriginal = class_getInstanceMethod(_originalClass, _originalSel);
71 | Method methodNew = class_getInstanceMethod(_targetClass, _targetSel);
72 | BOOL didAddMethod = class_addMethod(_originalClass, _originalSel, method_getImplementation(methodNew), method_getTypeEncoding(methodNew));
73 | if (didAddMethod) {
74 | class_replaceMethod(_originalClass, _targetSel, method_getImplementation(methodOriginal), method_getTypeEncoding(methodOriginal));
75 | }else{
76 | method_exchangeImplementations(methodOriginal, methodNew);
77 | }
78 | }
79 | /*交换类方法*/
80 | static inline void BMP_EXChangeClassMethod(Class _class ,SEL _originalSel,SEL _exchangeSel){
81 | Method methodOriginal = class_getClassMethod(_class, _originalSel);
82 | Method methodNew = class_getClassMethod(_class, _exchangeSel);
83 | method_exchangeImplementations(methodOriginal, methodNew);
84 | }
85 |
86 | #endif /* BayMaxCFunctions_h */
87 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Degrade/ManaulDegrade/TestManaulDegradeVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestManaulDegradeVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestManaulDegradeVC.h"
10 |
11 | @interface TestManaulDegradeVC ()
12 | /**
13 | tableView
14 | */
15 | @property (nonatomic, strong) UITableView *tableview;
16 |
17 | @end
18 |
19 | @implementation TestManaulDegradeVC
20 | #pragma mark ======== Life Cycle ========
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | // Do any additional setup after loading the view.
24 | [self.view addSubview:self.tableview];
25 |
26 | UILabel *tipLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 300, WIDTH-20, 200)];
27 | tipLabel.font = [UIFont systemFontOfSize:14];
28 | tipLabel.textColor = [UIColor darkTextColor];
29 | tipLabel.numberOfLines = 0;
30 | tipLabel.text = @"需要主动降级的页面,本身没有发生任何崩溃性的错误,只是业务逻辑发生错误,除了要获取自动降级的配置外,还需要获取需要主动降级的页面,再进来就会展示该页面对应的H5页面,如果有参数,会获取参数,本例中会展示百度的首页";
31 | [self.view addSubview:tipLabel];
32 | }
33 |
34 | - (void)didReceiveMemoryWarning {
35 | [super didReceiveMemoryWarning];
36 | // Dispose of any resources that can be recreated.
37 | }
38 |
39 | #pragma mark ======== NetWork ========
40 |
41 | #pragma mark ======== System Delegate ========
42 | #pragma mark UITableViewDataSource && UITableViewDelegate
43 |
44 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
45 | return 1;
46 | }
47 |
48 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
49 | return 5;
50 | }
51 |
52 |
53 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
54 | static NSString *CellID = @"mainCellID";
55 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];
56 | if (cell == nil) {
57 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID];
58 | }
59 | cell.textLabel.text = [NSString stringWithFormat:@"第%ld行",indexPath.row];
60 | return cell;
61 | }
62 |
63 | #pragma mark ======== Custom Delegate ========
64 |
65 | #pragma mark ======== Notifications && Observers ========
66 |
67 | #pragma mark ======== Event Response ========
68 |
69 | #pragma mark ======== Private Methods ========
70 |
71 | #pragma mark ======== Setters && Getters ========
72 | - (UITableView *)tableview{
73 | if (!_tableview) {
74 | _tableview = [[UITableView alloc]initWithFrame:CGRectMake(0, 44, WIDTH, HEIGHT) style:UITableViewStyleGrouped];
75 | _tableview.delegate = self;
76 | _tableview.dataSource = self;
77 | _tableview.tableFooterView = [[UIView alloc]init];
78 | }
79 | return _tableview;
80 | }
81 | /*
82 | #pragma mark - Navigation
83 |
84 | // In a storyboard-based application, you will often want to do a little preparation before navigation
85 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
86 | // Get the new view controller using [segue destinationViewController].
87 | // Pass the selected object to the new view controller.
88 | }
89 | */
90 |
91 | @end
92 |
93 |
94 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxDegradeAssist.h:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxDegradeAssist.h
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/19.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 | /*
9 | 页面降级辅助类:保存/刷新对应关系、查找对应关系、转换完整url。
10 | 支持手动降级与自动降级。
11 | 其中自动降级只针对unrecognizedSelector与容器类错误【暂未加入】进行降级处理。
12 | */
13 |
14 | #import
15 | #import
16 | /*vc*/
17 | FOUNDATION_EXPORT NSString *const BMPAssistKey_VC;
18 | /*params:H5-iOS参数对应关系*/
19 | FOUNDATION_EXPORT NSString *const BMPAssistKey_Params;
20 | /*url*/
21 | FOUNDATION_EXPORT NSString *const BMPAssistKey_Url;
22 |
23 | @class BayMaxCatchError;
24 | @protocol BayMaxDegradeAssistProtocol
25 | - (void)handleError:(BayMaxCatchError *)error;
26 | @end
27 |
28 | @protocol BayMaxDegradeAssistDataSource
29 | @required;
30 | /**
31 | 共有多少组H5-iOS对应关系
32 | 一个视图控制器对应一组关系
33 | @return 关系数目
34 | */
35 | - (NSInteger)numberOfRelations;
36 |
37 | /**
38 | 第index组iOS试图控制器的名字
39 |
40 | @param index 第几组
41 | @return iOS视图控制器名字
42 | */
43 | - (NSString *)nameOfViewControllerAtIndex:(NSInteger)index;
44 |
45 | /**
46 | 第index组下试图控制器对应的url
47 |
48 | @param index 第几组
49 | @return 对应的url
50 | */
51 | - (NSString *)urlOfViewControllerAtIndex:(NSInteger)index;
52 |
53 | /**
54 | 第index组下H5与iOS之间参数的对应关系集合
55 | 对应关系中key为H5字段名,value为iOS字段名
56 | @param index 第几组
57 | @return 对应关系数组@[
58 | @{H5Param:iOSParam},
59 | @{H5Param:iOSParam},
60 | @{H5Param:iOSParam},
61 | ]
62 | */
63 | - (NSArray *> *)correspondencesBetweenH5AndIOSParametersAtIndex:(NSInteger)index;
64 |
65 | @optional
66 | /**
67 | 主动降级某些页面,处理后,最终还是会走BayMaxDegradeAssistDelegate中的自动降级相关方法
68 | 注意:主动降级也就是让向该对象发送一个不能响应的消息,然后走消息转发流程
69 | @return 视图控制器类名数组
70 | */
71 | - (NSArray *)viewControllersToDegradeInitiative;
72 |
73 | @end
74 |
75 | @protocol BayMaxDegradeAssistDelegate
76 |
77 | /**
78 | 自动降级:
79 | 非viewdidload方法出错,可以获取当前页面对应的H5完整url(带参数),然后进行页面降级
80 |
81 | @param degradeVC 需要降级的视图控制器实例
82 | @param completeURL 完整URL
83 | @param relation 该视图控制器对应的相关信息
84 | */
85 | - (void)autoDegradeInstanceOfViewController:(UIViewController *)degradeVC ifErrorHappensInProcessExceptViewDidLoadWithReplacedCompleteURL:(NSString *)completeURL relation:(NSDictionary *)relation;
86 |
87 | /**
88 | 自动降级:
89 | 在viewdidload方法中出错,可以获取出错页面对应的不完整url(不带参数),然后进行页面降级
90 |
91 | @param degradeCls 需要降级的视图控制器类
92 | @param URL 不带参数的url
93 | @param relation 该视图控制器对应的相关信息
94 | */
95 | - (void)autoDegradeClassOfViewController:(Class)degradeCls ifErrorHappensInViewDidLoadProcessWithReplacedURL:(NSString *)URL relation:(NSDictionary *)relation;
96 |
97 | @end
98 |
99 | @interface BayMaxDegradeAssist : NSObject
100 |
101 | @property (nonatomic, strong) NSMutableArray *relations;
102 |
103 | @property (nonatomic, assign) iddegradeDatasource;
104 |
105 | @property (nonatomic, assign) iddegradeDelegate;
106 |
107 | /**
108 | 获取Assist单例
109 |
110 | @return Assist单例
111 | */
112 | + (instancetype)Assist;
113 |
114 | /**
115 | 获取跟Class的对应关系
116 |
117 | @param cls 视图控制器类
118 | @return 对应关系的字典,字段有控制器名称(NSString *)、参数对应关系(NSArray *)、对应的url(NSString *)
119 |
120 | */
121 | - (NSDictionary *)relationForViewController:(Class)cls;
122 | /**
123 | 刷新对应关系相关配置
124 | */
125 | - (void)reloadRelations;
126 | /**
127 | 获取当前显示的视图控制器
128 |
129 | @return 视图控制器实例
130 | */
131 | - (UIViewController *)topViewController;
132 |
133 | @end
134 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Base/BaseViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewController.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BaseViewController.h"
10 |
11 | @interface BaseViewController ()
12 | @property (nonatomic, strong) UIButton *dismissBtn;
13 |
14 | @end
15 |
16 | @implementation BaseViewController
17 | #pragma mark ======== Life Cycle ========
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 | // Do any additional setup after loading the view.
21 | self.view.backgroundColor = [UIColor whiteColor];
22 | [self.view addSubview:self.dismissBtn];
23 | }
24 |
25 | - (void)didReceiveMemoryWarning {
26 | [super didReceiveMemoryWarning];
27 | // Dispose of any resources that can be recreated.
28 | }
29 |
30 | #pragma mark ======== NetWork ========
31 |
32 | #pragma mark ======== System Delegate ========
33 |
34 | #pragma mark ======== Custom Delegate ========
35 |
36 | #pragma mark ======== Notifications && Observers ========
37 |
38 | #pragma mark ======== Event Response ========
39 | - (void)dismiss{
40 | [self dismissViewControllerAnimated:YES completion:nil];
41 | }
42 | #pragma mark ======== Private Methods ========
43 |
44 | #pragma mark ======== Setters && Getters ========
45 | - (UIButton *)dismissBtn{
46 | if (!_dismissBtn) {
47 | _dismissBtn = [UIButton buttonWithType:UIButtonTypeCustom];
48 | _dismissBtn.frame = CGRectMake(6,12 , 44, 40);
49 | _dismissBtn.contentMode = UIViewContentModeLeft;
50 | [_dismissBtn setTitle:@"返回" forState:UIControlStateNormal];
51 | [_dismissBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
52 | [_dismissBtn addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
53 | }
54 | return _dismissBtn;
55 | }
56 | /*
57 | #pragma mark - Navigation
58 |
59 | // In a storyboard-based application, you will often want to do a little preparation before navigation
60 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
61 | // Get the new view controller using [segue destinationViewController].
62 | // Pass the selected object to the new view controller.
63 | }
64 | */
65 |
66 | @end
67 |
68 | @implementation NSString (BreadcrumbStringSize)
69 | - (CGFloat)widthForFont:(UIFont *)font {
70 | CGSize size = [self sizeForFont:font size:CGSizeMake(HUGE, HUGE) mode:NSLineBreakByWordWrapping];
71 | return size.width;
72 | }
73 |
74 | - (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode {
75 | CGSize result;
76 | if (!font) font = [UIFont systemFontOfSize:12];
77 | if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
78 | NSMutableDictionary *attr = [NSMutableDictionary new];
79 | attr[NSFontAttributeName] = font;
80 | if (lineBreakMode != NSLineBreakByWordWrapping) {
81 | NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
82 | paragraphStyle.lineBreakMode = lineBreakMode;
83 | attr[NSParagraphStyleAttributeName] = paragraphStyle;
84 | }
85 | CGRect rect = [self boundingRectWithSize:size
86 | options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
87 | attributes:attr context:nil];
88 | result = rect.size;
89 | } else {
90 | #pragma clang diagnostic push
91 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
92 | result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
93 | #pragma clang diagnostic pop
94 | }
95 | return result;
96 | }
97 |
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVProgressHUD.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVProgressHUD.h
3 | //
4 | // Copyright 2011-2014 Sam Vermette. All rights reserved.
5 | //
6 | // https://github.com/samvermette/SVProgressHUD
7 | //
8 |
9 | #import
10 | #import
11 |
12 | extern NSString * const SVProgressHUDDidReceiveTouchEventNotification;
13 | extern NSString * const SVProgressHUDDidTouchDownInsideNotification;
14 | extern NSString * const SVProgressHUDWillDisappearNotification;
15 | extern NSString * const SVProgressHUDDidDisappearNotification;
16 | extern NSString * const SVProgressHUDWillAppearNotification;
17 | extern NSString * const SVProgressHUDDidAppearNotification;
18 |
19 | extern NSString * const SVProgressHUDStatusUserInfoKey;
20 |
21 | typedef NS_ENUM(NSUInteger, SVProgressHUDMaskType) {
22 | SVProgressHUDMaskTypeNone = 1, // allow user interactions while HUD is displayed
23 | SVProgressHUDMaskTypeClear, // don't allow user interactions
24 | SVProgressHUDMaskTypeBlack, // don't allow user interactions and dim the UI in the back of the HUD
25 | SVProgressHUDMaskTypeGradient // don't allow user interactions and dim the UI with a a-la-alert-view background gradient
26 | };
27 |
28 | @interface SVProgressHUD : UIView
29 |
30 | #pragma mark - Customization
31 |
32 | + (void)setBackgroundColor:(UIColor*)color; // default is [UIColor whiteColor]
33 | + (void)setForegroundColor:(UIColor*)color; // default is [UIColor blackColor]
34 | + (void)setRingThickness:(CGFloat)width; // default is 4 pt
35 | + (void)setFont:(UIFont*)font; // default is [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]
36 | + (void)setInfoImage:(UIImage*)image; // default is the bundled info image provided by Freepik
37 | + (void)setSuccessImage:(UIImage*)image; // default is the bundled success image provided by Freepik
38 | + (void)setErrorImage:(UIImage*)image; // default is the bundled error image provided by Freepik
39 | + (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType; // default is SVProgressHUDMaskTypeNone
40 | + (void)setViewForExtension:(UIView*)view; // default is nil, only used if #define SV_APP_EXTENSIONS is set
41 |
42 | #pragma mark - Show Methods
43 |
44 | + (void)show;
45 | + (void)showWithMaskType:(SVProgressHUDMaskType)maskType;
46 | + (void)showWithStatus:(NSString*)status;
47 | + (void)showWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType;
48 |
49 | + (void)showProgress:(float)progress;
50 | + (void)showProgress:(float)progress maskType:(SVProgressHUDMaskType)maskType;
51 | + (void)showProgress:(float)progress status:(NSString*)status;
52 | + (void)showProgress:(float)progress status:(NSString*)status maskType:(SVProgressHUDMaskType)maskType;
53 |
54 | + (void)setStatus:(NSString*)string; // change the HUD loading status while it's showing
55 |
56 | // stops the activity indicator, shows a glyph + status, and dismisses HUD a little bit later
57 | + (void)showInfoWithStatus:(NSString *)string;
58 | + (void)showInfoWithStatus:(NSString *)string maskType:(SVProgressHUDMaskType)maskType;
59 |
60 | + (void)showSuccessWithStatus:(NSString*)string;
61 | + (void)showSuccessWithStatus:(NSString*)string maskType:(SVProgressHUDMaskType)maskType;
62 |
63 | + (void)showErrorWithStatus:(NSString *)string;
64 | + (void)showErrorWithStatus:(NSString *)string maskType:(SVProgressHUDMaskType)maskType;
65 |
66 | // use 28x28 white pngs
67 | + (void)showImage:(UIImage*)image status:(NSString*)status;
68 | + (void)showImage:(UIImage*)image status:(NSString*)status maskType:(SVProgressHUDMaskType)maskType;
69 |
70 | + (void)setOffsetFromCenter:(UIOffset)offset;
71 | + (void)resetOffsetFromCenter;
72 |
73 | + (void)popActivity; // decrease activity count, if activity count == 0 the HUD is dismissed
74 | + (void)dismiss;
75 |
76 | + (BOOL)isVisible;
77 |
78 | @end
79 |
80 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/15.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "ViewController.h"
11 |
12 | #import "BayMaxProtector.h"
13 | #import "BayMaxDegradeAssist.h"
14 | #import "WebViewController.h"
15 |
16 | @interface AppDelegate ()
17 | {
18 | }
19 | @end
20 |
21 | @implementation AppDelegate
22 |
23 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
24 | // Override point for customization after application launch.
25 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
26 | self.window.backgroundColor = [UIColor whiteColor];
27 | self.window.rootViewController = [[ViewController alloc]init];
28 | [self.window makeKeyAndVisible];
29 |
30 | /*开启防护模式*/
31 | [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeAll catchErrorHandler:^(BayMaxCatchError * _Nullable error) {
32 | NSArray *callStacks = [error.errorInfos objectForKey:BMPErrorCallStackSymbols];
33 | NSLog(@"callStacks:%@",callStacks);
34 | /*unrecognizedSelector类型的错误,*/
35 | if (error.errorType == BayMaxErrorTypeUnrecognizedSelector) {
36 | NSLog(@"ErrorUnRecognizedSelInfos:%@",error.errorInfos);
37 |
38 | }else if (error.errorType == BayMaxErrorTypeTimer){
39 | NSLog(@"ErrorTimerinfos:%@",error.errorInfos);
40 |
41 |
42 | }else if (error.errorType == BayMaxErrorTypeKVO){
43 | NSLog(@"ErrorKVOinfos:%@",error.errorInfos);
44 |
45 | }else if (error.errorType == BayMaxErrorTypeContainers){
46 | NSLog(@"ErrorContainersinfos:%@",error.errorInfos);
47 |
48 | }else{
49 | NSLog(@"infos:%@",error.errorInfos);
50 | }
51 | }];
52 | [BayMaxProtector showDebugView];
53 | /*开启某一指定防护*/
54 | // [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeUnrecognizedSelector];
55 | // /*开启某几个组合防护*/
56 | // [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeUnrecognizedSelector|BayMaxProtectionTypeTimer];
57 | //设置白名单
58 | // [BayMaxProtector ignoreProtectionsOnClassesWithPrefix:@[@"AV"]];
59 | return YES;
60 | }
61 |
62 | - (void)applicationWillResignActive:(UIApplication *)application {
63 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
64 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
65 | }
66 |
67 |
68 | - (void)applicationDidEnterBackground:(UIApplication *)application {
69 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
70 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
71 | }
72 |
73 |
74 | - (void)applicationWillEnterForeground:(UIApplication *)application {
75 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
76 | }
77 |
78 |
79 | - (void)applicationDidBecomeActive:(UIApplication *)application {
80 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
81 | }
82 |
83 |
84 | - (void)applicationWillTerminate:(UIApplication *)application {
85 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
86 | }
87 |
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/KVO/TestKVOErrorVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestKVOErrorVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestKVOErrorVC.h"
10 |
11 | @interface TestKVOErrorVC ()
12 |
13 | @property (nonatomic,assign) CGFloat progress;
14 |
15 | @property (nonatomic,assign) CGFloat progress1;
16 |
17 | @end
18 |
19 | @implementation TestKVOErrorVC
20 | {
21 | NSArray *_titleArray;
22 | }
23 | #pragma mark ======== Life Cycle ========
24 | - (void)viewDidLoad {
25 | [super viewDidLoad];
26 | // Do any additional setup after loading the view.
27 | _titleArray = @[
28 | @"keypath重复监听",
29 | @"移除了未注册的观察者",
30 | @"移除了不存在的keypath",
31 | @"keypath重复移除",
32 | @"关闭kvo防护",
33 | @"开启kvo防护"
34 | ];
35 | [self setupSubviews];
36 | [self addObserver:self forKeyPath:@"progress" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
37 | }
38 |
39 |
40 | - (void)didReceiveMemoryWarning {
41 | [super didReceiveMemoryWarning];
42 | // Dispose of any resources that can be recreated.
43 | }
44 |
45 | #pragma mark ======== NetWork ========
46 |
47 | #pragma mark ======== System Delegate ========
48 |
49 | #pragma mark ======== Custom Delegate ========
50 |
51 | #pragma mark ======== Notifications && Observers ========
52 |
53 | #pragma mark ======== Event Response ========
54 | - (void)btnClick:(UIButton *)btn{
55 | NSInteger btnTag = btn.tag;
56 | if (1000 == btnTag) {
57 | [self addObserver:self forKeyPath:@"progress" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
58 | }else if (1001 == btnTag){
59 | [self removeObserver:self forKeyPath:@"progress1"];
60 | }else if (1002 == btnTag){
61 | [self removeObserver:self forKeyPath:@"undefinedProgress"];
62 | }else if (1003 == btnTag){
63 | [self removeObserver:self forKeyPath:@"progress"];
64 | [self removeObserver:self forKeyPath:@"progress"];
65 | }else if (1004 == btnTag){
66 | [BayMaxProtector closeProtectionsOn:BayMaxProtectionTypeKVO];
67 | }else if (1005 == btnTag){
68 | [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeKVO];
69 | }
70 | }
71 |
72 | #pragma mark ======== Private Methods ========
73 | - (void)setupSubviews{
74 | CGFloat btnWidth = ([self getMaxLength]+8)>(WIDTH/2-24)?(WIDTH/2-24):([self getMaxLength]+8);
75 | CGFloat btnHeight = 44;
76 | CGFloat borderSpace = 12;
77 | CGFloat btnSpace = (WIDTH - 2 * borderSpace - 2 * btnWidth);
78 | for (int i = 0; i<_titleArray.count; i++) {
79 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
80 | btn.tag = 1000+i;
81 | [btn setTitle:_titleArray[i] forState:UIControlStateNormal];
82 | [btn setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
83 | btn.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
84 | btn.frame = CGRectMake(borderSpace + (btnSpace + btnWidth)*(i%2), 60+(btnHeight+borderSpace)*(i/2), btnWidth, btnHeight);
85 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
86 | btn.layer.cornerRadius = 5;
87 | btn.titleLabel.font = [UIFont systemFontOfSize:14];
88 | btn.backgroundColor = [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1];
89 | [self.view addSubview:btn];
90 | }
91 | }
92 |
93 | - (CGFloat)getMaxLength{
94 | CGFloat maxLength = 0;
95 | for (int i = 0; i<_titleArray.count; i++) {
96 | CGFloat tempLength = [_titleArray[i] widthForFont:[UIFont systemFontOfSize:14]];
97 | if (tempLength>maxLength) {
98 | maxLength = tempLength;
99 | }
100 | }
101 | return maxLength;
102 | }
103 |
104 | - (void)dealloc{
105 | [self removeObserver:self forKeyPath:@"progress"];
106 | }
107 | #pragma mark ======== Setters && Getters ========
108 | /*
109 | #pragma mark - Navigation
110 |
111 | // In a storyboard-based application, you will often want to do a little preparation before navigation
112 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
113 | // Get the new view controller using [segue destinationViewController].
114 | // Pass the selected object to the new view controller.
115 | }
116 | */
117 |
118 | @end
119 |
120 |
121 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/UnrecognizedSelector/TestUnrecognizedSelVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestUnrecognizedSelVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestUnrecognizedSelVC.h"
10 |
11 | @interface TestUnrecognizedSelVC ()
12 | @end
13 |
14 | @implementation TestUnrecognizedSelVC
15 | {
16 | NSArray *_titleArray;
17 | }
18 | #pragma mark ======== Life Cycle ========
19 | - (void)viewDidLoad {
20 | [super viewDidLoad];
21 | // Do any additional setup after loading the view.
22 |
23 | _titleArray = @[
24 | @"找不到btn响应事件",
25 | @"找不到vc中的方法",
26 | @"向null对象发送length消息",
27 | @"关闭UnrecognizedSel防护",
28 | @"开启UnrecognizedSel防护"
29 | ];
30 | [self setupSubviews];
31 | }
32 |
33 | - (void)viewDidDisappear:(BOOL)animated{
34 | [super viewDidDisappear:animated];
35 | }
36 |
37 | - (void)didReceiveMemoryWarning {
38 | [super didReceiveMemoryWarning];
39 | // Dispose of any resources that can be recreated.
40 | }
41 |
42 | #pragma mark ======== NetWork ========
43 |
44 | #pragma mark ======== System Delegate ========
45 |
46 | #pragma mark ======== Custom Delegate ========
47 |
48 | #pragma mark ======== Notifications && Observers ========
49 |
50 | #pragma mark ======== Event Response ========
51 | - (void)btnClick:(UIButton *)btn{
52 | NSInteger btnTag = btn.tag;
53 | if (1000 == btnTag) {
54 | }else if (1001 == btnTag){
55 | [self performSelector:@selector(undefinedVCSelector)];
56 | }else if (1002 == btnTag){
57 | [[NSNull null]performSelector:@selector(length)];
58 | }else if (1003 == btnTag){
59 | [BayMaxProtector closeProtectionsOn:BayMaxProtectionTypeUnrecognizedSelector];
60 | }else if (1004 == btnTag){
61 | [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeUnrecognizedSelector];
62 | }
63 | }
64 |
65 | #pragma mark ======== Private Methods ========
66 | - (void)setupSubviews{
67 | CGFloat btnWidth = ([self getMaxLength]+8)>(WIDTH/2-24)?(WIDTH/2-24):([self getMaxLength]+8);
68 | CGFloat btnHeight = 44;
69 | CGFloat borderSpace = 12;
70 | CGFloat btnSpace = (WIDTH - 2 * borderSpace - 2 * btnWidth);
71 | for (int i = 0; i<_titleArray.count; i++) {
72 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
73 | btn.tag = 1000+i;
74 | [btn setTitle:_titleArray[i] forState:UIControlStateNormal];
75 | [btn setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
76 | btn.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
77 | btn.frame = CGRectMake(borderSpace + (btnSpace + btnWidth)*(i%2), 60+(btnHeight+borderSpace)*(i/2), btnWidth, btnHeight);
78 | if (i == 0) {
79 | [btn addTarget:self action:@selector(undefinedBtnClick) forControlEvents:UIControlEventTouchUpInside];
80 | }else{
81 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
82 | }
83 | btn.layer.cornerRadius = 5;
84 | btn.titleLabel.font = [UIFont systemFontOfSize:14];
85 | btn.backgroundColor = [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1];
86 | [self.view addSubview:btn];
87 | }
88 |
89 | UILabel *tipLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 250, WIDTH-20, 150)];
90 | tipLabel.font = [UIFont systemFontOfSize:14];
91 | tipLabel.textColor = [UIColor darkTextColor];
92 | tipLabel.numberOfLines = 0;
93 | tipLabel.text = @"1、当未获取自动降级配置时,点击前三个按钮后,会拦阻异常,防止崩溃,但不会对该页面进行降级 \n 2、当获取自动降级配置后,再点击会跳转到该页面对应的H5页面,进行降级,展示掘金首页。\n 3、当关闭崩溃保护后,再次点击前三个按钮,会发生崩溃,可点击开启防护后,重新进行防护\n 4、如果有参数会获取参数。";
94 | [self.view addSubview:tipLabel];
95 | }
96 |
97 |
98 | - (CGFloat)getMaxLength{
99 | CGFloat maxLength = 0;
100 | for (int i = 0; i<_titleArray.count; i++) {
101 | CGFloat tempLength = [_titleArray[i] widthForFont:[UIFont systemFontOfSize:14]];
102 | if (tempLength>maxLength) {
103 | maxLength = tempLength;
104 | }
105 | }
106 | return maxLength;
107 | }
108 | #pragma mark ======== Setters && Getters ========
109 |
110 | /*
111 | #pragma mark - Navigation
112 |
113 | // In a storyboard-based application, you will often want to do a little preparation before navigation
114 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
115 | // Get the new view controller using [segue destinationViewController].
116 | // Pass the selected object to the new view controller.
117 | }
118 | */
119 |
120 | @end
121 |
122 |
123 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Vender/SVProgressHUD/SVProgressHUD/SVIndefiniteAnimatedView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVIndefiniteAnimatedView.m
3 | // SVProgressHUD
4 | //
5 | // Created by Guillaume Campagna on 2014-12-05.
6 | //
7 | //
8 |
9 | #import "SVIndefiniteAnimatedView.h"
10 |
11 | #pragma mark SVIndefiniteAnimatedView
12 |
13 | @interface SVIndefiniteAnimatedView ()
14 |
15 | @property (nonatomic, strong) CAShapeLayer *indefiniteAnimatedLayer;
16 |
17 | @end
18 |
19 | @implementation SVIndefiniteAnimatedView
20 |
21 | - (void)willMoveToSuperview:(UIView *)newSuperview {
22 | if (newSuperview) {
23 | [self layoutAnimatedLayer];
24 | } else {
25 | [_indefiniteAnimatedLayer removeFromSuperlayer];
26 | _indefiniteAnimatedLayer = nil;
27 | }
28 | }
29 |
30 | - (void)layoutAnimatedLayer {
31 | CALayer *layer = self.indefiniteAnimatedLayer;
32 |
33 | [self.layer addSublayer:layer];
34 | layer.position = CGPointMake(CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds) / 2, CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds) / 2);
35 | }
36 |
37 | - (CAShapeLayer*)indefiniteAnimatedLayer {
38 | if(!_indefiniteAnimatedLayer) {
39 | CGPoint arcCenter = CGPointMake(self.radius+self.strokeThickness/2+5, self.radius+self.strokeThickness/2+5);
40 | CGRect rect = CGRectMake(0.0f, 0.0f, arcCenter.x*2, arcCenter.y*2);
41 |
42 | UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter
43 | radius:self.radius
44 | startAngle:M_PI*3/2
45 | endAngle:M_PI/2+M_PI*5
46 | clockwise:YES];
47 |
48 | _indefiniteAnimatedLayer = [CAShapeLayer layer];
49 | _indefiniteAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale];
50 | _indefiniteAnimatedLayer.frame = rect;
51 | _indefiniteAnimatedLayer.fillColor = [UIColor clearColor].CGColor;
52 | _indefiniteAnimatedLayer.strokeColor = self.strokeColor.CGColor;
53 | _indefiniteAnimatedLayer.lineWidth = self.strokeThickness;
54 | _indefiniteAnimatedLayer.lineCap = kCALineCapRound;
55 | _indefiniteAnimatedLayer.lineJoin = kCALineJoinBevel;
56 | _indefiniteAnimatedLayer.path = smoothedPath.CGPath;
57 |
58 | CALayer *maskLayer = [CALayer layer];
59 |
60 | NSBundle *bundle = [NSBundle bundleForClass:self.class];
61 | NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"];
62 | NSBundle *imageBundle = [NSBundle bundleWithURL:url];
63 | NSString *path = [imageBundle pathForResource:@"angle-mask" ofType:@"png"];
64 |
65 | maskLayer.contents = (id)[[UIImage imageWithContentsOfFile:path] CGImage];;
66 | maskLayer.frame = _indefiniteAnimatedLayer.bounds;
67 | _indefiniteAnimatedLayer.mask = maskLayer;
68 |
69 | NSTimeInterval animationDuration = 1;
70 | CAMediaTimingFunction *linearCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
71 |
72 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
73 | animation.fromValue = 0;
74 | animation.toValue = [NSNumber numberWithFloat:M_PI*2];
75 | animation.duration = animationDuration;
76 | animation.timingFunction = linearCurve;
77 | animation.removedOnCompletion = NO;
78 | animation.repeatCount = INFINITY;
79 | animation.fillMode = kCAFillModeForwards;
80 | animation.autoreverses = NO;
81 | [_indefiniteAnimatedLayer.mask addAnimation:animation forKey:@"rotate"];
82 |
83 | CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
84 | animationGroup.duration = animationDuration;
85 | animationGroup.repeatCount = INFINITY;
86 | animationGroup.removedOnCompletion = NO;
87 | animationGroup.timingFunction = linearCurve;
88 |
89 | CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
90 | strokeStartAnimation.fromValue = @0.015;
91 | strokeStartAnimation.toValue = @0.515;
92 |
93 | CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
94 | strokeEndAnimation.fromValue = @0.485;
95 | strokeEndAnimation.toValue = @0.985;
96 |
97 | animationGroup.animations = @[strokeStartAnimation, strokeEndAnimation];
98 | [_indefiniteAnimatedLayer addAnimation:animationGroup forKey:@"progress"];
99 |
100 | }
101 | return _indefiniteAnimatedLayer;
102 | }
103 |
104 | - (void)setFrame:(CGRect)frame {
105 | [super setFrame:frame];
106 |
107 | if (self.superview) {
108 | [self layoutAnimatedLayer];
109 | }
110 | }
111 |
112 | - (void)setRadius:(CGFloat)radius {
113 | _radius = radius;
114 |
115 | [_indefiniteAnimatedLayer removeFromSuperlayer];
116 | _indefiniteAnimatedLayer = nil;
117 |
118 | if (self.superview) {
119 | [self layoutAnimatedLayer];
120 | }
121 | }
122 |
123 | - (void)setStrokeColor:(UIColor *)strokeColor {
124 | _strokeColor = strokeColor;
125 | _indefiniteAnimatedLayer.strokeColor = strokeColor.CGColor;
126 | }
127 |
128 | - (void)setStrokeThickness:(CGFloat)strokeThickness {
129 | _strokeThickness = strokeThickness;
130 | _indefiniteAnimatedLayer.lineWidth = _strokeThickness;
131 | }
132 |
133 | - (CGSize)sizeThatFits:(CGSize)size {
134 | return CGSizeMake((self.radius+self.strokeThickness/2+5)*2, (self.radius+self.strokeThickness/2+5)*2);
135 | }
136 |
137 | @end
138 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > BayMaxProtector is a framework that can block common crashes , thereby enhancing your App's stability. Not only that, but you can also use the downgrade mechanism it provides to reduce a page that has a problem to a corresponding web page, So as not to affect the continuation of the business.
2 | > 这是一个可以对常见崩溃进行拦阻,从而增强你App稳定性的框架,不仅如此,你还可以使用它提供的降级机制,将发生问题的页面降为对应的web页面,从而不影响业务的继续。
3 |
4 |
5 | > 个人练手项目,存在一定风险,请谨慎使用
6 |
7 | #### BayMax思路来自网易团队:[大白健康系统--iOS APP运行时Crash自动修复系统](https://neyoufan.github.io/2017/01/13/ios/BayMax_HTSafetyGuard/)
8 |
9 | #### 2.0主要是对[1.0](https://juejin.im/post/5a65b8056fb9a01ca87217fb)的升级与改造。
10 | ## 2月26日新增功能
11 | #### 新增容器类防护,针对NSArray/NSMutableArray/NSDictionary/NSMutableDictionary/NSString/NSMutableString进行崩溃保护。
12 |
13 | ## 一、新增功能
14 | #### 1、增加BayMaxDebugView
15 | `BayMaxDebugView`可以在开发中更直观的展示它所拦截到的异常,会展示捕获异常的数目,并且可以跟随手指移动,点击后可以展示错误的详细信息。收起后,错误信息清零,长按错误信息可以复制分享。
16 |
17 | #### 2、新增自定义IMP方法链表,支持IMP的插入与查找功能
18 | 该功能主要用来帮助判断某些系统方法有没有被替换。
19 | ```
20 | typedef struct IMPNode *PtrToIMP;
21 | typedef PtrToIMP IMPlist;
22 | struct IMPNode{
23 | IMP imp;
24 | PtrToIMP next;
25 | };
26 | /*向IMP链表中追加imp*/
27 | static inline void BMP_InsertIMPToList(IMPlist list,IMP imp){
28 | PtrToIMP nextNode = malloc(sizeof(struct IMPNode));
29 | nextNode->imp = imp;
30 | nextNode->next = list->next;
31 | list->next = nextNode;
32 | }
33 | /*
34 | 递归判断IMP链表中有没有此元素。
35 | */
36 | static inline BOOL BMP_ImpExistInList(IMPlist list, IMP imp){
37 | if (list->imp == imp) {
38 | return YES;
39 | }else{
40 | if (list->next != NULL) {
41 | return BMP_ImpExistInList(list->next,imp);
42 | }else{
43 | return NO;
44 | }
45 | }
46 | }
47 | ```
48 | #### 3、增加关闭防护的功能
49 | 可以在任意页面,关闭或者打开防护功能,并且可以对重复操作进行过滤,重复的添加或者移除,会作为异常显示在`debugView`中。
50 | ```
51 | 1、保存系统原有的IMP
52 | static IMPlist impList;
53 | + (void)load{
54 | //maping_ForwardingTarget_IMP为ForwardingTarget方法的映射
55 | IMP maping_ForwardingTarget_IMP = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingForwardingTargetForSelectorMethod));
56 | //maping_Timer_IMP为原有timer方法的映射
57 | IMP maping_Timer_IMP = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingTimerMethod));
58 | IMP KVO_IMP = class_getMethodImplementation([NSObject class], @selector(addObserver:forKeyPath:options:context:));
59 | IMP notification_IMP = class_getMethodImplementation([NSNotificationCenter class], @selector(addObserver:selector:name:object:));
60 |
61 | impList = malloc(sizeof(struct IMPNode));
62 | impList->next = NULL;
63 |
64 | BMP_InsertIMPToList(impList, maping_ForwardingTarget_IMP);
65 | BMP_InsertIMPToList(impList, KVO_IMP);
66 | BMP_InsertIMPToList(impList, maping_Timer_IMP);
67 | BMP_InsertIMPToList(impList, notification_IMP);
68 | }
69 |
70 | 2、根据操作的protectionType获取对应的IMP,然后判断该IMP在不在原有的impList中,在的话,说明该防护之前没有开启过,不在的话,说明该防护之前开启过。
71 | if (!BMP_ImpExistInList(impList, imp)) {
72 | NSLog(@"关闭保护");
73 | //再执行一次交换操作
74 | [self openProtectionsOn:protectionType catchErrorHandler:nil];
75 | }else{//说明该方法没有被交换,即没有列在保护名单里,空处理即可
76 | NSString * duplicateClose = [NSString stringWithFormat:@"[%@] Is Not In The Protection State Before And Don't Need To Close This Protection Again",protectionName];
77 | [[BayMaxDebugView sharedDebugView]addErrorInfo:@{@"waring":duplicateClose}];
78 | }
79 |
80 | ```
81 | #### 4、增加针对`libobjc.A.dylib`部分方法的方法映射
82 |
83 | ```
84 | #pragma mark libobjc.A.dylib IMP映射
85 | /**
86 | NSObject ForwardingTargetForSelector方法的映射
87 | */
88 | - (void)BMP_mappingForwardingTargetForSelectorMethod{
89 | }
90 | - (void)BMP_excMappingForwardingTargetForSelectorMethod{
91 | }
92 | /**
93 | NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:方法的映射
94 | */
95 | - (void)BMP_mappingTimerMethod{
96 | }
97 | - (void)BMP_excMappingTimerMethod{
98 | }
99 |
100 | ```
101 | #### 5、增加一系列测试用例
102 |
103 | ## 二、原有功能
104 | #### 1、防止`unrecognizedSelector`类型的崩溃
105 |
106 | #### 2、防止`kvo`类型的崩溃
107 | 如keypath重复监听、移除了未注册的观察者、移除了不存在的keypath,观察者未移除
108 | #### 3、防止`Timer`类型的错误
109 | 退出页面时,`timer`可以自动`invalidate`
110 | #### 4、防止`NSNotification`类型的错误
111 | 在未移除监听者的时候,自动帮你移除监听者
112 | #### 5、支持页面自动降级
113 | 可以通过配置在页面发生`unrecognizedSelector`类型错误的时候,自动降级为对应的web页面,自动降级又分两种,一种是能拿到参数,然后拼成一个完整的url传给web,另一种是发生在`viewdidload`中,且接收错误消息的对象不是视图控制器,这时候拿不到参数,只能拿到对应的url。】
114 | #### 6、支持页面主动降级
115 | 在某些页面发生业务逻辑错误时,比如粗心的把价格单位“元”写成了“万元”,可以手动的将该页面将为对应的web页面,本质上是向该页面发送一个它不能够响应的消息,然后再走自动降级的逻辑。
116 |
117 | ## 三、安装
118 | * 手动:将`BayMaxProtector`下的所有文件拖入项目
119 | * `CocoaPod`:`podfile`加入 `pod 'BayMaxProtector'`
120 |
121 | ## 四、使用
122 | #### 1、开启防护
123 | ```
124 | //开启全部防护
125 | [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeAll catchErrorHandler:^(BayMaxCatchError * _Nullable error) {
126 | //do your business
127 | }];
128 | //开启某一防护
129 | [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeUnrecognizedSelector];
130 | //开启组合防护
131 | [BayMaxProtector openProtectionsOn:BayMaxProtectionTypeUnrecognizedSelector|BayMaxProtectionTypeTimer];
132 | //设置白名单
133 | [BayMaxProtector ignoreProtectionsOnClassesWithPrefix:@[@"AV"]];
134 | ```
135 | #### 2、关闭防护
136 | ```
137 | //同上
138 | [BayMaxProtector closeProtectionsOn:BayMaxProtectionTypeAll];
139 |
140 | ```
141 | #### 3、显示DebugView
142 | ```
143 | [BayMaxProtector showDebugView];
144 | ```
145 | #### 4、隐藏DebugView
146 | ```
147 | [BayMaxProtector hideDebugView];
148 | ```
149 | #### 5、页面降级(可选)
150 | 实现相对应的代理方法`BayMaxDegradeAssistDelegate`与数据源协议`BayMaxDegradeAssistDataSource`
151 |
152 | ## 五、在swift环境下的表现
153 | `BayMax`在`swift`环境下绝大部分功能仍然可用,但是如果在`viewdidload`方法中发生`unrecognizedSelector`类型的错误,这时候获取当前显示的视图控制器存在问题,从而会影响自动降级相关的流程,其他的暂时没发现问题,如果使用中有新的问题,请留言。
154 |
155 | ## 六、效果展示
156 | #### 1、unrecognizedSelector防护
157 |
158 | 
159 |
160 | #### 2、unrecognizedSelector-viewdidload防护
161 |
162 | 
163 |
164 | #### 3、TimerErrorBlock
165 | 
166 |
167 | #### 4、KVOErrorBlock
168 |
169 | 
170 | #### 5、自动降级
171 |
172 | 
173 |
174 | #### 6、手动降级
175 |
176 | 
177 |
178 |
179 | GitHub下载地址:[BayMaxProtector](https://github.com/sunday1990/BayMaxProtector)
180 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxKVODelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxKVODelegate.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/12.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BayMaxKVODelegate.h"
10 | #include
11 | #include
12 |
13 | static NSLock *_bmp_kvoLock;
14 |
15 | static inline NSString *BMP_md5StringOfObject(NSObject *object){
16 | NSString *string = [NSString stringWithFormat:@"%p",object];
17 | const char *str = string.UTF8String;
18 | uint8_t buffer[CC_MD5_DIGEST_LENGTH];
19 | CC_MD5(str, (CC_LONG)strlen(str), buffer);
20 | NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
21 | for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
22 | [output appendFormat:@"%02x", buffer[i]];
23 | }
24 | return output;
25 | }
26 |
27 | @interface KVOInfo: NSObject
28 |
29 | @end
30 |
31 | @implementation KVOInfo
32 | {
33 | @package
34 | void *_context;
35 | NSKeyValueObservingOptions _options;
36 | __weak NSObject *_observer;
37 | NSString *_keyPath;
38 | NSString *_md5Str;
39 | }
40 | @end
41 |
42 | @implementation BayMaxKVODelegate
43 |
44 | {
45 | @private
46 | NSMutableDictionary *> *_keyPathMaps;
47 | }
48 |
49 | - (instancetype)init
50 | {
51 | self = [super init];
52 | if (nil != self) {
53 | _keyPathMaps = [NSMutableDictionary dictionary];
54 | _bmp_kvoLock = [[NSLock alloc]init];
55 | }
56 | return self;
57 | }
58 |
59 | - (BOOL)addKVOInfoToMapsWithObserver:(NSObject *)observer
60 | forKeyPath:(NSString *)keyPath
61 | options:(NSKeyValueObservingOptions)options
62 | context:(void *)context{
63 | BOOL success;
64 | //先判断有没有重复添加,有的话报错,没有的话,添加到数组中
65 | [_bmp_kvoLock lock];
66 | NSMutableArray *kvoInfos = [self getKVOInfosForKeypath:keyPath];
67 | __block BOOL isExist = NO;
68 | [kvoInfos enumerateObjectsUsingBlock:^(KVOInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
69 | if (obj->_observer == observer) {
70 | isExist = YES;
71 | }
72 | }];
73 | if (isExist) {//已经存在了
74 | success = NO;
75 | }else{
76 | KVOInfo *info = [[KVOInfo alloc]init];
77 | info->_observer = observer;
78 | info->_md5Str = BMP_md5StringOfObject(observer);
79 | info->_keyPath = keyPath;
80 | info->_options = options;
81 | info->_context = context;
82 | [kvoInfos addObject:info];
83 | [self setKVOInfos:kvoInfos ForKeypath:keyPath];
84 | success = YES;
85 | }
86 | [_bmp_kvoLock unlock];
87 | return success;
88 | }
89 |
90 | - (void)addKVOInfoToMapsWithObserver:(NSObject *)observer
91 | forKeyPath:(NSString *)keyPath
92 | options:(NSKeyValueObservingOptions)options
93 | context:(void *)context
94 | success:(void(^)(void))success
95 | failure:(void(^)(NSError *error))failure{
96 | [_bmp_kvoLock lock];
97 | //先判断有没有重复添加,有的话报错,没有的话,添加到数组中
98 | NSMutableArray *kvoInfos = [self getKVOInfosForKeypath:keyPath];
99 | __block BOOL isExist = NO;
100 | [kvoInfos enumerateObjectsUsingBlock:^(KVOInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
101 | if (obj->_observer == observer) {
102 | isExist = YES;
103 | }
104 | }];
105 | if (isExist) {//已经存在了
106 | if (failure) {
107 | NSInteger code = -1234;
108 | NSString *msg = [NSString stringWithFormat:@"\n observer重复添加:\n observer:%@\n keypath:%@ \n",observer,keyPath];
109 | NSError * error = [NSError errorWithDomain:@"com.BayMax.BayMaxKVODelegate" code:code userInfo:@{@"NSLocalizedDescriptionKey":msg}];
110 | failure(error);
111 | }
112 | }else{
113 | KVOInfo *info = [[KVOInfo alloc]init];
114 | info->_observer = observer;
115 | info->_md5Str = BMP_md5StringOfObject(observer);
116 | info->_keyPath = keyPath;
117 | info->_options = options;
118 | info->_context = context;
119 | [kvoInfos addObject:info];
120 | [self setKVOInfos:kvoInfos ForKeypath:keyPath];
121 | if (success) {
122 | success();
123 | }
124 | }
125 | [_bmp_kvoLock unlock];
126 | }
127 |
128 | - (BOOL)removeKVOInfoInMapsWithObserver:(NSObject *)observer
129 | forKeyPath:(NSString *)keyPath{
130 | [_bmp_kvoLock lock];
131 | BOOL success;
132 | NSMutableArray *kvoInfos = [self getKVOInfosForKeypath:keyPath];
133 | __block BOOL isExist = NO;
134 | __block KVOInfo *kvoInfo;
135 | [kvoInfos enumerateObjectsUsingBlock:^(KVOInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
136 | if ([obj->_md5Str isEqualToString:BMP_md5StringOfObject(observer)]) {
137 | isExist = YES;
138 | kvoInfo = obj;
139 | }
140 | }];
141 | if (kvoInfo) {
142 | [kvoInfos removeObject:kvoInfo];
143 | if (kvoInfos.count == 0) {//说明该keypath没有observer观察,可以移除该键
144 | [_keyPathMaps removeObjectForKey:keyPath];
145 | }
146 | }
147 | success = isExist;
148 | [_bmp_kvoLock unlock];
149 | return success;
150 | }
151 |
152 | #pragma mark 获取keypath对应的所有观察者
153 | - (NSMutableArray *)getKVOInfosForKeypath:(NSString *)keypath{
154 | if ([_keyPathMaps.allKeys containsObject:keypath]) {
155 | return [_keyPathMaps objectForKey:keypath];
156 | }else{
157 | return [NSMutableArray array];
158 | }
159 | }
160 |
161 | #pragma mark 设置keypath对应的观察者数组
162 | - (void)setKVOInfos:(NSMutableArray *)kvoInfos ForKeypath:(NSString *)keypath{
163 | if (![_keyPathMaps.allKeys containsObject:keypath]) {
164 | if (keypath) {
165 | _keyPathMaps[keypath] = kvoInfos;
166 | }
167 | }
168 | }
169 |
170 | #pragma mark 实际观察者执行相对应的监听方法
171 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
172 | NSMutableArray *kvoInfos = [self getKVOInfosForKeypath:keyPath];
173 | [kvoInfos enumerateObjectsUsingBlock:^(KVOInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
174 | if ([obj->_keyPath isEqualToString:keyPath]) {
175 | NSObject *observer = obj->_observer;
176 | if (observer) {
177 | [observer observeValueForKeyPath:keyPath ofObject:object change:change context:context];
178 | }
179 | }
180 | }];
181 | }
182 |
183 | #pragma mark 获取所有被观察的keypaths
184 | - (NSArray *)getAllKeypaths{
185 | NSArray *keyPaths = _keyPathMaps.allKeys;
186 | return keyPaths;
187 | }
188 |
189 | @end
190 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxDebugView.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxDebugView.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BayMaxDebugView.h"
10 |
11 | #define BMPScreenWidth [UIScreen mainScreen].bounds.size.width
12 | #define BMPScreenHeight [UIScreen mainScreen].bounds.size.height
13 |
14 | @interface BayMaxDebugView ()
15 |
16 | @property (nonatomic, strong) UIButton *bubbleView;
17 | @property (nonatomic, strong) UIButton *dismissBtn;
18 | @property (nonatomic, strong) NSMutableArray *errorInfos;
19 | @property (nonatomic, strong) UITextView *textView;
20 | @end
21 |
22 | @implementation BayMaxDebugView
23 |
24 |
25 | /*
26 | // Only override drawRect: if you perform custom drawing.
27 | // An empty implementation adversely affects performance during animation.
28 | - (void)drawRect:(CGRect)rect {
29 | // Drawing code
30 | }
31 | */
32 | static BayMaxDebugView *_instance;
33 |
34 | + (id)allocWithZone:(struct _NSZone *)zone{
35 | static dispatch_once_t onceToken;
36 | dispatch_once(&onceToken, ^{
37 | _instance = [super allocWithZone:zone];
38 | });
39 | return _instance;
40 | }
41 |
42 | + (nonnull instancetype)sharedDebugView{
43 | static dispatch_once_t onceToken;
44 | dispatch_once(&onceToken, ^{
45 | _instance = [[self alloc] init];
46 | });
47 | return _instance;
48 | }
49 |
50 | - (id)copyWithZone:(NSZone *)zone{
51 | return _instance;
52 | }
53 |
54 | - (instancetype)init{
55 | if (self = [super init]) {
56 | UIWindow *keyWindow = [self getWindow];
57 | [keyWindow addSubview:self.bubbleView];
58 | [keyWindow addSubview:self.textView];
59 | [keyWindow addSubview:self.dismissBtn];
60 | }
61 | return self;
62 | }
63 |
64 | #pragma mark ========= Event Responses =========
65 | - (void)showDebugView{
66 | if (self.errorInfos.count == 0) {
67 | return;
68 | }
69 | NSMutableString *text = [NSMutableString string];
70 | [self.errorInfos enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) {
71 | [text appendString:[NSString stringWithFormat:@"%lu 、\n{\n",idx+1]];
72 | [obj enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) {
73 | [text appendString:key];
74 | [text appendString:@":"];
75 | [text appendString:[NSString stringWithFormat:@"%@\n\n",obj]];
76 | }];
77 | [text appendString:@"}\n\n============================\n\n"];
78 |
79 | }];
80 | self.textView.hidden = self.dismissBtn.hidden = NO;
81 | self.textView.text = [NSString stringWithFormat:@"\n\n共为您捕获%lu条异常:\n\n\n%@",(unsigned long)self.errorInfos.count,text];
82 |
83 | [UIView animateWithDuration:0.3 animations:^{
84 | self.textView.frame = CGRectMake(0, 0, BMPScreenWidth, BMPScreenHeight);
85 | self.dismissBtn.frame = CGRectMake(BMPScreenWidth-12-40, 12, 40, 40);
86 | }];
87 | }
88 |
89 | - (void)dismissDebugView{
90 | [self.errorInfos removeAllObjects];
91 | [_bubbleView setTitle:@"BayMax" forState:UIControlStateNormal];
92 | [_bubbleView setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
93 | [UIView animateWithDuration:0.3 animations:^{
94 | self.textView.frame = CGRectMake(0, BMPScreenHeight, BMPScreenWidth, BMPScreenHeight);
95 | self.dismissBtn.frame = CGRectMake(BMPScreenWidth-12-40, BMPScreenHeight+12, 40, 40);
96 |
97 | }completion:^(BOOL finished) {
98 | self.textView.hidden = self.dismissBtn.hidden = YES;
99 | [self.textView endEditing:YES];
100 | }];
101 | }
102 |
103 | - (void) handlePan:(UIPanGestureRecognizer*) recognizer{
104 | CGPoint translation = [recognizer translationInView:[self getWindow]];//self.window.rootViewController.view
105 | CGFloat centerX = recognizer.view.center.x + translation.x;
106 | CGFloat thecenter = 0;
107 | recognizer.view.center=CGPointMake(centerX,
108 | recognizer.view.center.y+ translation.y);
109 | [recognizer setTranslation:CGPointZero inView:[self getWindow]];//self.window.rootViewController.view
110 | if(recognizer.state==UIGestureRecognizerStateEnded || recognizer.state==UIGestureRecognizerStateCancelled) {
111 | if(centerX > BMPScreenWidth/2) {
112 | thecenter = BMPScreenWidth-self.bubbleView.frame.size.width/2-12;
113 | }else{
114 | thecenter = self.bubbleView.frame.size.width/2+12;
115 | }
116 | [UIView animateWithDuration:0.3 animations:^{
117 | recognizer.view.center=CGPointMake(thecenter,
118 | recognizer.view.center.y + translation.y);
119 | }];
120 | }
121 | }
122 |
123 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
124 | [self.textView endEditing:YES];
125 | }
126 |
127 | #pragma mark ========= Private Methods =========
128 |
129 | - (void)addErrorInfo:(NSDictionary *_Nonnull)errorInfo{
130 | [self.errorInfos addObject:errorInfo];
131 | NSString *num = [NSString stringWithFormat:@"%ld",self.errorInfos.count];
132 | [self.bubbleView setTitle:[NSString stringWithFormat:@"+%@",num] forState:UIControlStateNormal];
133 | [self.bubbleView setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
134 | }
135 |
136 | - (UIWindow *)getWindow{
137 | UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
138 | return keyWindow;
139 | }
140 |
141 | #pragma mark ========= Setters && Getters =========
142 |
143 | - (void)setHidden:(BOOL)hidden{
144 | self.bubbleView.hidden = hidden;
145 | }
146 |
147 | - (UIButton *)bubbleView{
148 | if (!_bubbleView) {
149 | _bubbleView = [UIButton buttonWithType:UIButtonTypeCustom];
150 | _bubbleView.frame = CGRectMake(BMPScreenWidth-12- 50, 30, 50, 50);
151 | _bubbleView.titleLabel.font = [UIFont systemFontOfSize:12];
152 | [_bubbleView setTitle:@"BayMax" forState:UIControlStateNormal];
153 | [_bubbleView setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
154 | _bubbleView.layer.cornerRadius = 10;
155 | _bubbleView.backgroundColor = [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1];
156 | [_bubbleView addTarget:self action:@selector(showDebugView) forControlEvents:UIControlEventTouchUpInside];
157 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePan:)];
158 | [_bubbleView addGestureRecognizer:pan];
159 | }
160 | return _bubbleView;
161 | }
162 |
163 | - (UITextView *)textView{
164 | if (!_textView) {
165 | _textView = [[UITextView alloc]init];
166 | _textView.frame = CGRectMake(0, BMPScreenHeight, BMPScreenWidth, BMPScreenHeight);
167 | _textView.backgroundColor = [UIColor whiteColor];
168 | _textView.hidden = YES;
169 | _textView.textColor = [UIColor blackColor];
170 | _textView.editable = NO;
171 | _textView.font = [UIFont systemFontOfSize:14];
172 |
173 | }
174 | return _textView;
175 | }
176 |
177 | - (UIButton *)dismissBtn{
178 | if (!_dismissBtn) {
179 | _dismissBtn = [UIButton buttonWithType:UIButtonTypeCustom];
180 | [_dismissBtn setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
181 | _dismissBtn.titleLabel.font = [UIFont systemFontOfSize:14];
182 | _dismissBtn.backgroundColor = [UIColor colorWithRed:214/255.0 green:235/255.0 blue:253/255.0 alpha:1];
183 | _dismissBtn.titleLabel.font = [UIFont systemFontOfSize:14];
184 | [_dismissBtn setTitle:@"返回" forState:UIControlStateNormal];
185 | _dismissBtn.layer.cornerRadius = 10;
186 | _dismissBtn.frame = CGRectMake(BMPScreenWidth-12-40, BMPScreenHeight+12, 40, 40);
187 | _dismissBtn.hidden = YES;
188 | [_dismissBtn addTarget:self action:@selector(dismissDebugView) forControlEvents:UIControlEventTouchUpInside];
189 | }
190 | return _dismissBtn;
191 | }
192 |
193 | - (NSMutableArray *)errorInfos{
194 | if (!_errorInfos) {
195 | _errorInfos = [NSMutableArray array];
196 | }
197 | return _errorInfos;
198 | }
199 |
200 | @end
201 |
202 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/Examples/Containers/TestContainerVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestContainerVC.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/1.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "TestContainerVC.h"
10 |
11 | @interface TestContainerVC ()
12 |
13 | @end
14 |
15 | @implementation TestContainerVC
16 | #pragma mark ======== Life Cycle ========
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view.
20 | [self testArray];
21 | [self testMutableArray];
22 | [self testDictionary];
23 | [self testMutableDictionary];
24 | [self testString];
25 | [self testMutableString];
26 | }
27 |
28 | - (void)testArray{
29 | /*
30 | NSArray->Methods On Protection:
31 | 1、@[nil]
32 | 2、arrayWithObjects:count:
33 | 3、objectsAtIndexes:
34 | 4、objectAtIndex:
35 | */
36 | NSString *value = nil;
37 | NSString *key = nil;
38 | //1、@[nil]
39 | NSArray *array0 = @[value];
40 | NSLog(@"array0:%@",array0);
41 | //2、arrayWithObjects:count:
42 | NSArray *array1 = [NSArray arrayWithObjects:@"abc",value,value, nil];
43 | NSLog(@"array1:%@",array1);
44 | //3、objectsAtIndexes:
45 | NSArray *array2 = @[@"1",@"2",@"3"];
46 | id objectAtIndex = [array2 objectAtIndex:4];
47 | array2[4];
48 | }
49 | - (void)testMutableArray{
50 | /*
51 | 0、arrayWithObjects:nil
52 | 1、objectAtIndex:
53 | 2、removeObjectAtIndex:
54 | 3、removeObjectsInRange:
55 | 4、removeObjectsAtIndexes:
56 | 5、insertObject:atIndex:
57 | 6、insertObjects:atIndexes:
58 | 7、addObject:nil
59 | 8、replaceObjectAtIndex:withObject:
60 | 9、replaceObjectsAtIndexes:withObjects:
61 | 10、replaceObjectsInRange:withObjectsFromArray:
62 | */
63 | NSString *value = nil;
64 | NSString *key = nil;
65 | //0、arrayWithObjects:nil
66 | NSMutableArray *array0 = [NSMutableArray arrayWithObjects:@"aklkd",value,value, nil];
67 | NSLog(@"array0:%@",array0);
68 | //1、objectAtIndex:
69 | NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
70 | NSString *objectAtIndex = [array1 objectAtIndex:5];
71 | objectAtIndex = array1[4];
72 | //2、removeObjectAtIndex:
73 | [array1 removeObjectAtIndex:5];
74 | //3、removeObjectsInRange:
75 | [array1 removeObjectsInRange:NSMakeRange(2, 3)];
76 | NSLog(@"removeObjectsInRangeArray1:%@",array1);
77 | //4、removeObjectsAtIndexes:
78 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
79 | // [array1 removeObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 4)]];
80 | // NSLog(@"removeObjectsAtIndexesArray:%@",array1);
81 | //5、insertObject:atIndex:
82 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
83 | [array1 insertObject:@"5" atIndex:5];
84 | NSLog(@"insertObjectArray:%@",array1);
85 | //6、insertObjects:atIndexes:
86 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
87 | [array1 insertObjects:@[@"6",@"7",@"8"] atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(5, 3)]];
88 | [array1 insertObjects:@[@"6",@"7",@"8"] atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 3)]];
89 | [array1 insertObjects:@[@"6",@"7",@"8"] atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 2)]];
90 | NSLog(@"insertObjectsAtIndexes%@",array1);
91 | //7、addObject:nil
92 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
93 | [array1 addObject:value];
94 | //8、
95 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
96 | [array1 replaceObjectAtIndex:5 withObject:@"5"];
97 |
98 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
99 | [array1 replaceObjectsInRange:NSMakeRange(1, 4) withObjectsFromArray:@[@"5",@"6",@"7",@"8"]];
100 |
101 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
102 | [array1 replaceObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 4)] withObjects:@[@"5",@"6",@"7",@"8"]];
103 |
104 | array1 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
105 | [array1 replaceObjectAtIndex:2 withObject:nil];
106 |
107 |
108 | }
109 |
110 | - (void)testDictionary{
111 | /*
112 | 1 @{nil:nil}
113 | 2、dictionaryWithObject:forKey:
114 | 3、dictionaryWithObjects:forKeys:
115 | 4、dictionaryWithObjects:forKeys:count:
116 | */
117 | //1 @{nil:nil}
118 | NSString *value = nil;
119 | NSString *key = nil;
120 | NSDictionary *dic = @{@"key":value};
121 | dic = @{key:@"value"};
122 | // 2、dictionaryWithObject:forKey:
123 | [NSDictionary dictionaryWithObject:@"value" forKey:key];
124 | [NSDictionary dictionaryWithObject:value forKey:@"key"];
125 | // 3、dictionaryWithObjects:forKeys:
126 | // [NSDictionary dictionaryWithObjects:@[@"1",@"2",@"3"] forKeys:@[@"1",@"2",key]];
127 | // 4、dictionaryWithObjects:forKeys:count:
128 | }
129 |
130 | - (void)testMutableDictionary{
131 | /*
132 | 1、setObject:forKey:
133 | 2、removeObjectForKey:
134 | */
135 |
136 | NSString *value = nil;
137 | NSString *key = nil;
138 | // 1、setObject:forKey:
139 | NSMutableDictionary *dicM = [NSMutableDictionary dictionary];
140 | [dicM setObject:@"value" forKey:key];
141 | [dicM setObject:value forKey:@"key"];
142 | [dicM setObject:@"value" forKey:@"key"];
143 | NSLog(@"dicM:%@",dicM);
144 | // 2、removeObjectForKey:
145 | [dicM removeObjectForKey:key];
146 | NSLog(@"dicM:%@",dicM);
147 | }
148 |
149 | - (void)testString{
150 | /*
151 |
152 | NSString->Methods On Protection:
153 | 2、substringFromIndex:
154 | 3、substringToIndex:
155 | 4、substringWithRange:
156 | 5、stringByReplacingCharactersInRange:withString:
157 | */
158 | NSString *string = @"abcdefg";
159 | // 1、characterAtIndex:
160 | NSLog(@"characterAtIndex:%c",[string characterAtIndex:20]);
161 | // 2、substringFromIndex:
162 | NSLog(@"substringFromIndex:%@",[string substringFromIndex:20]);
163 | // 3、substringToIndex:
164 | NSLog(@"substringToIndex:%@",[string substringToIndex:20]);
165 | // 4、substringWithRange:
166 | NSLog(@"substringWithRange:%@",[string substringWithRange:NSMakeRange(2, 20)]);
167 | NSLog(@"substringWithRange:%@",[string substringWithRange:NSMakeRange(20, 10)]);
168 | }
169 |
170 | - (void)testMutableString{
171 |
172 | // BMP_EXChangeInstanceMethod(stringClass, @selector(insertString:atIndex:), stringClass, @selector(BMP_insertString:atIndex:));
173 | // BMP_EXChangeInstanceMethod(stringClass, @selector(deleteCharactersInRange:), stringClass, @selector(BMP_deleteCharactersInRange:));
174 |
175 | /*
176 | NSMutableString->Methods On Protection:
177 | 1、replaceCharactersInRange:withString:
178 | 2、insertString:atIndex:
179 | 3、deleteCharactersInRange:
180 | */
181 | NSMutableString *stringM = [NSMutableString stringWithFormat:@"abcdefg"];
182 |
183 | // 2、insertString:atIndex:
184 | stringM = [NSMutableString stringWithFormat:@"abcdefg"];
185 | [stringM insertString:@"****" atIndex:20];
186 | NSLog(@"insertString:%@",stringM);
187 |
188 | // 3、deleteCharactersInRange:
189 | stringM = [NSMutableString stringWithFormat:@"abcdefg"];
190 | [stringM deleteCharactersInRange:NSMakeRange(2, 20)];
191 | NSLog(@"deleteCharactersInRange:%@",stringM);
192 |
193 | stringM = [NSMutableString stringWithFormat:@"abcdefg"];
194 | [stringM deleteCharactersInRange:NSMakeRange(10, 10)];
195 | NSLog(@"deleteCharactersInRange:%@",stringM);
196 |
197 | }
198 |
199 | - (void)didReceiveMemoryWarning {
200 | [super didReceiveMemoryWarning];
201 | // Dispose of any resources that can be recreated.
202 | }
203 |
204 | #pragma mark ======== NetWork ========
205 |
206 | #pragma mark ======== System Delegate ========
207 |
208 | #pragma mark ======== Custom Delegate ========
209 |
210 | #pragma mark ======== Notifications && Observers ========
211 |
212 | #pragma mark ======== Event Response ========
213 |
214 | #pragma mark ======== Private Methods ========
215 |
216 | #pragma mark ======== Setters && Getters ========
217 |
218 | /*
219 | #pragma mark - Navigation
220 |
221 | // In a storyboard-based application, you will often want to do a little preparation before navigation
222 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
223 | // Get the new view controller using [segue destinationViewController].
224 | // Pass the selected object to the new view controller.
225 | }
226 | */
227 |
228 | @end
229 |
230 |
231 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxDegradeAssist.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxDegradeAssist.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/19.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BayMaxDegradeAssist.h"
10 | #import "BayMaxCatchError.h"
11 | #import "BayMaxCFunctions.h"
12 |
13 | NSString *const BMPAssistKey_VC = @"BMP_ViewController";
14 |
15 | NSString *const BMPAssistKey_Params = @"BMP_Params";
16 |
17 | NSString *const BMPAssistKey_Url = @"BMP_Url";
18 |
19 | NSString *const InitiativeMethodName = @"com.bayMaxProtector.degradeViewControllerInitiative";
20 |
21 | static NSArray *_initiativeDegradeVCS;
22 |
23 | @interface UIViewController (DegradeAssist)
24 | @end
25 |
26 | @implementation UIViewController (DegradeAssist)
27 | - (void)BMDA_viewDidAppear:(BOOL)animated{
28 | id degradeDatasource = [BayMaxDegradeAssist Assist].degradeDatasource;
29 | if ([degradeDatasource respondsToSelector:@selector(viewControllersToDegradeInitiative)]) {
30 | NSArray *vcs = [degradeDatasource viewControllersToDegradeInitiative];
31 | if (![vcs isEqual:[NSNull null]]&&vcs.count>0) {
32 | [vcs enumerateObjectsUsingBlock:^(NSString *vcClsName, NSUInteger idx, BOOL * _Nonnull stop) {
33 | if ([vcClsName isEqualToString:NSStringFromClass(self.class)]) {
34 | BMP_SuppressPerformSelectorLeakWarning(
35 | [self performSelector:NSSelectorFromString(InitiativeMethodName)];
36 | );
37 | NSLog(@"页面主动降级成功");
38 | }
39 | }];
40 | }else{
41 | [self BMDA_viewDidAppear:animated];
42 | }
43 | }else{
44 | [self BMDA_viewDidAppear:animated];
45 | }
46 | }
47 |
48 | @end
49 |
50 |
51 | @implementation BayMaxDegradeAssist
52 |
53 | static BayMaxDegradeAssist*_instance;
54 |
55 | + (id)allocWithZone:(struct _NSZone *)zone{
56 | static dispatch_once_t onceToken;
57 | dispatch_once(&onceToken, ^{
58 | _instance = [super allocWithZone:zone];
59 | });
60 | return _instance;
61 | }
62 |
63 | + (nonnull instancetype)Assist{
64 | static dispatch_once_t onceToken;
65 | dispatch_once(&onceToken, ^{
66 | _instance = [[self alloc] init];
67 | });
68 | return _instance;
69 | }
70 |
71 | - (id)copyWithZone:(NSZone *)zone{
72 | return _instance;
73 | }
74 |
75 | - (instancetype)init{
76 | if (self = [super init]) {
77 | _relations = [NSMutableArray array];
78 | }
79 | return self;
80 | }
81 |
82 | - (void)reloadRelations{
83 | [self.relations removeAllObjects];
84 | id degradeDatasource = [BayMaxDegradeAssist Assist].degradeDatasource;
85 | if (degradeDatasource && [degradeDatasource respondsToSelector:@selector(viewControllersToDegradeInitiative)]) {
86 | _initiativeDegradeVCS = [degradeDatasource viewControllersToDegradeInitiative];
87 | if (_initiativeDegradeVCS.count>0) {
88 | BMP_EXChangeInstanceMethod([UIViewController class], @selector(viewDidAppear:), [UIViewController class], @selector(BMDA_viewDidAppear:));
89 | }
90 | }
91 | if (degradeDatasource && [degradeDatasource respondsToSelector:@selector(numberOfRelations)]) {
92 | NSInteger relations = [degradeDatasource numberOfRelations];
93 | for (int i = 0; i0) {
115 | NSLog(@"页面降级相关配置更新成功!");
116 | }
117 |
118 | }
119 | }
120 |
121 | - (NSDictionary *)relationForViewController:(Class)cls{
122 | __block NSDictionary *relation;
123 | NSString *clsName = NSStringFromClass(cls);
124 | [self.relations enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
125 | if ([[obj objectForKey:BMPAssistKey_VC] isEqualToString:clsName]) {
126 | relation = obj;
127 | *stop = YES;
128 | }
129 | }];
130 | return relation;
131 | }
132 |
133 |
134 | #pragma mark BayMaxDegradeAssistProtocol
135 | - (void)handleError:(BayMaxCatchError *)error{
136 | if (error.errorType == BayMaxErrorTypeUnrecognizedSelector) {
137 | id obj = error.errorInfos[BMPErrorUnrecognizedSel_VC];
138 | if ([obj isKindOfClass:[UIViewController class]]) {
139 | UIViewController *vc = (UIViewController *)obj;
140 | NSString *completeURL = [[BayMaxDegradeAssist Assist]getCompleteUrlWithParamsForViewController:vc];
141 | if (completeURL.length>0) {
142 | NSDictionary *relation = [[BayMaxDegradeAssist Assist]relationForViewController:vc.class];
143 | id degradeDelegate = self.degradeDelegate;
144 | if (degradeDelegate && [degradeDelegate respondsToSelector:@selector(autoDegradeInstanceOfViewController:ifErrorHappensInProcessExceptViewDidLoadWithReplacedCompleteURL:relation:)]) {
145 | [degradeDelegate autoDegradeInstanceOfViewController:vc ifErrorHappensInProcessExceptViewDidLoadWithReplacedCompleteURL:completeURL relation:relation];
146 | }
147 | }
148 | }else if([obj isKindOfClass:[NSString class]]){
149 | NSString *cls =(NSString *)obj;
150 | NSDictionary *relation = [[BayMaxDegradeAssist Assist]relationForViewController:NSClassFromString(obj)];
151 | NSString *URL = relation[BMPAssistKey_Url];
152 | if (URL.length>0) {
153 | id degradeDelegate = self.degradeDelegate;
154 | if (degradeDelegate && [degradeDelegate respondsToSelector:@selector(autoDegradeClassOfViewController:ifErrorHappensInViewDidLoadProcessWithReplacedURL:relation:)]) {
155 | [degradeDelegate autoDegradeClassOfViewController:NSClassFromString(cls) ifErrorHappensInViewDidLoadProcessWithReplacedURL:URL relation:relation];
156 | }
157 | }
158 | }
159 | }
160 | }
161 |
162 | #pragma mark others
163 | - (NSString *)getCompleteUrlWithParamsForViewController:(UIViewController *)vc{
164 | NSMutableString *appendString = [NSMutableString string];
165 | NSDictionary *relation = [self relationForViewController:[vc class]];
166 | NSString *url = relation[BMPAssistKey_Url];
167 | if (url == nil) {
168 | return @"";
169 | }
170 | NSArray *params = relation[BMPAssistKey_Params];
171 | [appendString appendString:url];
172 | [appendString appendString:@"?"];
173 | [params enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
174 | NSString *h5Param = obj.allKeys[0];
175 | NSString *iosParam = obj[h5Param];
176 | //keypath需要做判断
177 | NSString *h5Value = [vc valueForKeyPath:iosParam];
178 | if (h5Value) {
179 | [appendString appendString:h5Param];
180 | [appendString appendString:@"="];
181 | [appendString appendString:h5Value];
182 | if (idx1) {
188 | return [appendString substringWithRange:NSMakeRange(0, appendString.length-1)];
189 | }
190 | return appendString;
191 | }
192 |
193 | - (UIViewController *)topViewController {
194 | UIViewController *resultVC;
195 | resultVC = [self _topViewController:[[UIApplication sharedApplication].keyWindow rootViewController]];
196 | while (resultVC.presentedViewController) {
197 | resultVC = [self _topViewController:resultVC.presentedViewController];
198 | }
199 | return resultVC;
200 | }
201 |
202 | - (UIViewController *)_topViewController:(UIViewController *)vc {
203 | if ([vc isKindOfClass:[UINavigationController class]]) {
204 | return [self _topViewController:[(UINavigationController *)vc topViewController]];
205 | } else if ([vc isKindOfClass:[UITabBarController class]]) {
206 | return [self _topViewController:[(UITabBarController *)vc selectedViewController]];
207 | } else {
208 | return vc;
209 | }
210 | return nil;
211 | }
212 |
213 | @end
214 |
--------------------------------------------------------------------------------
/DemoBayMaxProtector/DemoBayMaxProtector/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/1/15.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | #import "TestAutoDegradeVC.h"
12 | #import "TestManaulDegradeVC.h"
13 | #import "WebViewController.h"
14 | #import "AssistMicros.h"
15 |
16 |
17 | #import "BayMaxDegradeAssist.h"
18 |
19 | @interface ViewController ()
20 | {
21 | NSArray *titleArray;
22 |
23 | NSArray *_vcNames;
24 | NSArray *> *_params;
25 | NSArray *_urls;
26 | NSArray *_initiativeVCS;
27 | }
28 | /**
29 | tableView
30 | */
31 | @property (nonatomic, strong) UITableView *tableview;
32 | /**
33 | 获取自动降级配置的按钮
34 | */
35 | @property (nonatomic, strong) UIButton *autoDegradeBtn;
36 | /**
37 | 获取手动降级配置的按钮
38 | */
39 | @property (nonatomic, strong) UIButton *manaulDegradeBtn;
40 |
41 | @end
42 |
43 | @implementation ViewController
44 |
45 | - (void)viewDidLoad {
46 | [super viewDidLoad];
47 | // Do any additional setup after loading the view, typically from a nib.
48 | self.view.backgroundColor = [UIColor whiteColor];
49 | titleArray = @[
50 | @{
51 | @"title":@"UnrecognizedSelector || AutoDegrade",
52 | @"class":@"TestUnrecognizedSelVC"
53 | },
54 | @{
55 | @"title":@"UnrecognizedSelector-ViewDidLoad",
56 | @"class":@"TestViewDidloadUnrecognizedSelVC"
57 | },
58 | @{
59 | @"title":@"TimerError",
60 | @"class":@"TestTimerErrorVC"
61 | },
62 | @{
63 | @"title":@"KVOError",
64 | @"class":@"TestKVOErrorVC"
65 | },
66 | @{
67 | @"title":@"NotificationError",
68 | @"class":@"TestNotificationErrorVC"
69 | },
70 | @{
71 | @"title":@"ManaulDegrade",
72 | @"class":@"TestManaulDegradeVC"
73 | },
74 | @{
75 | @"title":@"Containers",
76 | @"class":@"TestContainerVC"
77 | }
78 | ];
79 | [self.view addSubview:self.tableview];
80 | [self.view addSubview:self.autoDegradeBtn];
81 | [self.view addSubview:self.manaulDegradeBtn];
82 |
83 | /*设置Assist的代理与数据源*/
84 | [BayMaxDegradeAssist Assist].degradeDelegate = self;
85 | [BayMaxDegradeAssist Assist].degradeDatasource = self;
86 |
87 | }
88 |
89 | #pragma mark ======== System Delegate ========
90 |
91 | #pragma mark UITableViewDataSource && UITableViewDelegate
92 |
93 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
94 | return 1;
95 | }
96 |
97 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
98 | return titleArray.count;
99 | }
100 |
101 |
102 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
103 | static NSString *CellID = @"mainCellID";
104 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];
105 | if (cell == nil) {
106 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID];
107 | }
108 | cell.textLabel.text = [titleArray[indexPath.row]objectForKey:@"title"];
109 | return cell;
110 | }
111 |
112 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
113 | NSDictionary *item = titleArray[indexPath.row];
114 | Class cls = NSClassFromString([item objectForKey:@"class"]);
115 | if ([[item objectForKey:@"class"] isEqualToString:@"TestUnrecognizedSelVC"]) {
116 | UIViewController *vc = [[cls alloc]init];
117 | [vc setValue:@"someOne" forKey:@"userName"];
118 | [vc setValue:@"00001" forKey:@"userID"];
119 | [self presentViewController:vc animated:YES completion:nil];
120 | return;//
121 | }else if ([[item objectForKey:@"class"] isEqualToString:@"TestManaulDegradeVC"]){
122 | UIViewController *vc = [[cls alloc]init];
123 | [vc setValue:@"100000" forKey:@"uid"];
124 | [vc setValue:@"type001" forKey:@"type"];
125 | [self presentViewController:vc animated:YES completion:nil];
126 | return;//
127 | }
128 | [self presentViewController:[[cls alloc]init] animated:YES completion:nil];
129 | }
130 |
131 | #pragma mark ======== Custom Delegate ========
132 | #pragma mark BayMaxDegradeAssistDataSource
133 | - (NSInteger)numberOfRelations{
134 | return _vcNames.count;
135 | }
136 |
137 | - (NSString *)nameOfViewControllerAtIndex:(NSInteger)index{
138 | return _vcNames[index];
139 | }
140 |
141 | - (NSArray *> *)correspondencesBetweenH5AndIOSParametersAtIndex:(NSInteger)index{
142 | if (_params.count>index) {
143 | return _params[index];
144 | }else{
145 | return nil;
146 | }
147 | }
148 |
149 | - (NSString *)urlOfViewControllerAtIndex:(NSInteger)index{
150 | if (_urls.count>index) {
151 | return _urls[index];
152 | }else{
153 | return nil;
154 | }
155 | }
156 |
157 | - (NSArray *)viewControllersToDegradeInitiative{
158 | return _initiativeVCS;
159 | }
160 |
161 | #pragma mark BayMaxDegradeAssistDelegate
162 | - (void)autoDegradeInstanceOfViewController:(UIViewController *)degradeVC ifErrorHappensInProcessExceptViewDidLoadWithReplacedCompleteURL:(NSString *)completeURL relation:(NSDictionary *)relation{
163 | dispatch_async(dispatch_get_main_queue(), ^{
164 | [degradeVC.view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
165 | [SVProgressHUD showSuccessWithStatus:[NSString stringWithFormat:@"用来替代该页面的URL为:%@",completeURL] maskType:SVProgressHUDMaskTypeBlack];
166 | //获取拼接后的url
167 | WebViewController *webVC = [[WebViewController alloc]init];
168 | webVC.url = completeURL;
169 | [degradeVC addChildViewController:webVC];
170 | [degradeVC.view addSubview:webVC.view];
171 | });
172 | }
173 |
174 | - (void)autoDegradeClassOfViewController:(Class)degradeCls ifErrorHappensInViewDidLoadProcessWithReplacedURL:(NSString *)URL relation:(NSDictionary *)relation{
175 | WebViewController *webVC = [[WebViewController alloc]init];
176 | webVC.url = URL;
177 | [SVProgressHUD showSuccessWithStatus:[NSString stringWithFormat:@"用来替代该页面的URL为:%@",URL] maskType:SVProgressHUDMaskTypeBlack];
178 | UIViewController *vc = [[BayMaxDegradeAssist Assist]topViewController];
179 | [vc presentViewController:webVC animated:YES completion:nil];
180 | }
181 |
182 |
183 | #pragma mark ======== Event Response ========
184 | - (void)requestAutoDegradeConfiguration{
185 | [SVProgressHUD showWithStatus:@"获取自动降级配置" maskType:SVProgressHUDMaskTypeBlack];
186 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
187 | _vcNames = @[
188 | @"TestUnrecognizedSelVC",
189 | @"TestViewDidloadUnrecognizedSelVC",
190 | @"TestManaulDegradeVC"
191 | ];
192 | /*H5-ios参数对应关系,与上面的vc一一对应,数组可以为空,但不能为Null*/
193 | _params = @[
194 | @[
195 | @{@"userid":@"userID"},
196 | @{ @"username":@"userName"}
197 | ],
198 |
199 | @[
200 | ],
201 |
202 | @[
203 | @{@"uid":@"uid"},
204 | @{@"typeid":@"type"}
205 | ]
206 | ];
207 |
208 | _urls = @[
209 | @"https://juejin.im",
210 | @"https://sina.cn",
211 | @"https://www.baidu.com"
212 | ];
213 | [SVProgressHUD showSuccessWithStatus:@"获取自动降级配置" maskType:SVProgressHUDMaskTypeBlack];
214 | [[BayMaxDegradeAssist Assist]reloadRelations];
215 | });
216 |
217 | }
218 |
219 | - (void)requestManaulDegradeConfiguration{
220 | [SVProgressHUD showWithStatus:@"获取需要手动降级的视图控制器"];
221 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
222 | [SVProgressHUD showSuccessWithStatus:@"获取成功"];
223 | _initiativeVCS = @[
224 | @"TestManaulDegradeVC"
225 | ];
226 | [[BayMaxDegradeAssist Assist]reloadRelations];
227 | });
228 | }
229 |
230 | #pragma mark ======== Private Methods ========
231 | #pragma mark ======== Setters && Getters ========
232 |
233 |
234 | - (UITableView *)tableview{
235 | if (!_tableview) {
236 | _tableview = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT) style:UITableViewStyleGrouped];
237 | _tableview.delegate = self;
238 | _tableview.dataSource = self;
239 | _tableview.rowHeight = 44;
240 | _tableview.tableFooterView = [[UIView alloc]init];
241 | }
242 | return _tableview;
243 | }
244 |
245 | - (UIButton *)autoDegradeBtn{
246 | if (!_autoDegradeBtn) {
247 | _autoDegradeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
248 | _autoDegradeBtn.frame = CGRectMake(12, HEIGHT-120, 120, 50);
249 | [_autoDegradeBtn setTitle:@"获取自动降级配置" forState:UIControlStateNormal];
250 | _autoDegradeBtn.titleLabel.font = [UIFont systemFontOfSize:14];
251 | [_autoDegradeBtn setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
252 | [_autoDegradeBtn addTarget:self action:@selector(requestAutoDegradeConfiguration) forControlEvents:UIControlEventTouchUpInside];
253 | _autoDegradeBtn.backgroundColor = DEFAULT_COLOR;
254 | _autoDegradeBtn.layer.cornerRadius = 10;
255 | }
256 | return _autoDegradeBtn;
257 | }
258 |
259 | - (UIButton *)manaulDegradeBtn{
260 | if (!_manaulDegradeBtn) {
261 | _manaulDegradeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
262 | _manaulDegradeBtn.frame = CGRectMake(12+120+12, HEIGHT-120, 150, 50);
263 | [_manaulDegradeBtn setTitle:@"获取需手动降级的页面" forState:UIControlStateNormal];
264 | _manaulDegradeBtn.titleLabel.font = [UIFont systemFontOfSize:14];
265 | _manaulDegradeBtn.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
266 | [_manaulDegradeBtn setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
267 | [_manaulDegradeBtn addTarget:self action:@selector(requestManaulDegradeConfiguration) forControlEvents:UIControlEventTouchUpInside];
268 | _manaulDegradeBtn.backgroundColor = DEFAULT_COLOR;
269 | _manaulDegradeBtn.layer.cornerRadius = 10;
270 | }
271 | return _manaulDegradeBtn;
272 | }
273 |
274 | - (void)didReceiveMemoryWarning {
275 | [super didReceiveMemoryWarning];
276 | // Dispose of any resources that can be recreated.
277 | }
278 |
279 | @end
280 |
--------------------------------------------------------------------------------
/Class/BayMaxContainers.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxContainers.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2018/2/14.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 |
9 | #import "BayMaxContainers.h"
10 | #import "BayMaxCFunctions.h"
11 | #import "BayMaxCatchError.h"
12 | #import "BayMaxDebugView.h"
13 |
14 |
15 | BMPErrorHandler _Nullable _containerErrorHandler;
16 | //错误信息统一处理
17 | /*
18 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];\
19 | BMPErrorCallStackSymbols:callStackSymbolsArr
20 | */
21 | #define BMP_Container_ErrorHandler(errorType,errorInfo)\
22 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];\
23 | BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeContainers infos:@{\
24 | errorType:errorInfo,\
25 | BMPErrorCallStackSymbols:callStackSymbolsArr\
26 | }];\
27 | if (_containerErrorHandler) {\
28 | _containerErrorHandler(bmpError);\
29 | }
30 |
31 | //#define BMP_Container_ErrorHandler(errorType,errorInfo)\
32 | //BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeContainers infos:@{\
33 | //errorType:errorInfo\
34 | //}];\
35 | //if (_containerErrorHandler) {\
36 | //_containerErrorHandler(bmpError);\
37 | //}
38 |
39 | //不可变数组越界
40 | #define BMP_Array_BeyondBounds_ErrorHandler(ArrayType,ArrayMethod,Index)\
41 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[%@ %@]: index %ld beyond bounds [0 .. %ld]",ArrayType,ArrayMethod,Index,(unsigned long)self.count];\
42 | BMP_Container_ErrorHandler(BMPErrorArray_Beyond,errorInfo)
43 |
44 | //可变数组越界
45 | #define BMP_ArrayM_BeyondBounds_ErrorHandler(ErrorInfo)\
46 | BMP_Container_ErrorHandler(BMPErrorArray_Beyond,ErrorInfo)
47 |
48 | //可变数组插入Nil元素
49 | #define BMP_ArrayM_NilObject_ErrorHandler(ErrorInfo)\
50 | BMP_Container_ErrorHandler(BMPErrorArray_NilObject,ErrorInfo)
51 |
52 | //不可变字典key或者value为Nil
53 | #define BMP_Dictionary_ErrorHandler(ErrorInfo)\
54 | BMP_Container_ErrorHandler(BMPErrorDictionary_NilKey,ErrorInfo)
55 |
56 | //可变字典key或者value为Nil
57 | #define BMP_DictionaryM_ErrorHandler(ErrorInfo)\
58 | BMP_Container_ErrorHandler(BMPErrorDictionary_NilKey,ErrorInfo)
59 |
60 | //#define BMP_String_ErrorHandler(ErrorInfo)\
61 |
62 |
63 | @interface NSArray (BMPProtector)
64 |
65 | @end
66 |
67 | @implementation NSArray (BMPProtector)
68 | // NSArray/__NSArrayI/__NSSingleObjectArrayI/__NSArray0
69 | //objectsAtIndexes:
70 | + (instancetype)BMP_ArrayWithObjects:(id _Nonnull const [])objects count:(NSUInteger)cnt{
71 | NSUInteger index = 0;
72 | id _Nonnull objectsNew[cnt];
73 | for (int i = 0; i= self.count) {
89 | //记录错误
90 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSArrayI objectAtIndexedSubscript:]: index %ld beyond bounds [0 .. %ld]'",(unsigned long)idx,(unsigned long)self.count];
91 | BMP_Container_ErrorHandler(BMPErrorArray_Beyond, errorInfo);
92 | return nil;
93 | }
94 | return [self BMP_objectAtIndexedSubscript:idx];
95 | }
96 |
97 | //objectAtIndex:
98 | - (id)BMP__NSArrayIObjectAtIndex:(NSUInteger)index{
99 | if (index >= self.count) {
100 | BMP_Array_BeyondBounds_ErrorHandler(@"__NSArrayI",NSStringFromSelector(_cmd),(unsigned long)index);
101 | return nil;
102 | }
103 | return [self BMP__NSArrayIObjectAtIndex:index];
104 | }
105 |
106 | - (id)BMP__NSSingleObjectArrayIObjectAtIndex:(NSUInteger)index{
107 | if (index >= self.count) {
108 | BMP_Array_BeyondBounds_ErrorHandler(@"__NSSingleObject",NSStringFromSelector(_cmd),(unsigned long)index);
109 | return nil;
110 | }
111 | return [self BMP__NSSingleObjectArrayIObjectAtIndex:index];
112 | }
113 |
114 | - (id)BMP__NSArray0ObjectAtIndex:(NSUInteger)index{
115 | if (index >= self.count) {
116 | BMP_Array_BeyondBounds_ErrorHandler(@"__NSArray0",NSStringFromSelector(_cmd),(unsigned long)index);
117 | return nil;
118 | }
119 | return [self BMP__NSArray0ObjectAtIndex:index];
120 | }
121 | @end
122 |
123 | @interface NSMutableArray (BMPProtector)
124 |
125 | @end
126 |
127 | @implementation NSMutableArray (BMPProtector)
128 | //objectAtIndex:
129 | - (id)BMP_MArrayObjectAtIndex:(NSUInteger)index{
130 | if (index >= self.count) {
131 | BMP_Array_BeyondBounds_ErrorHandler(@"__NSArrayM",NSStringFromSelector(_cmd),(unsigned long)index);
132 | return nil;
133 | }
134 | return [self BMP_MArrayObjectAtIndex:index];
135 | }
136 |
137 | //objectAtIndexedSubscript
138 | - (id)BMP_MArrayobjectAtIndexedSubscript:(NSUInteger)idx{
139 | if (idx >= self.count) {
140 | //记录错误
141 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSArrayM objectAtIndexedSubscript:]: index %ld beyond bounds [0 .. %ld]'",(unsigned long)idx,(unsigned long)self.count];
142 | BMP_Container_ErrorHandler(BMPErrorArray_Beyond, errorInfo);
143 | return nil;
144 | }
145 | return [self BMP_MArrayobjectAtIndexedSubscript:idx];
146 | }
147 |
148 | //removeObjectAtIndex:
149 | - (void)BMP_MArrayRemoveObjectAtIndex:(NSUInteger)index{
150 | if (index >= self.count) {
151 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSArrayM removeObjectsInRange:]: range {%ld, 1} extends beyond bounds [0 .. %ld]",(unsigned long)index,(unsigned long)self.count];
152 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
153 | return;
154 | }
155 | [self BMP_MArrayRemoveObjectAtIndex:index];
156 | }
157 |
158 |
159 | - (void)BMP_MArrayRemoveObjectsInRange:(NSRange)range{
160 | if (range.location+range.length>self.count) {
161 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSArrayM removeObjectsInRange:]: range {%ld, %ld} extends beyond bounds [0 .. %ld]",(unsigned long)range.location,(unsigned long)range.length,(unsigned long)self.count];
162 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
163 | return;
164 | }
165 | [self BMP_MArrayRemoveObjectsInRange:range];
166 | }
167 |
168 | //insertObject:atIndex:
169 | - (void)BMP_MArrayInsertObject:(id)anObject atIndex:(NSUInteger)index{
170 | if (anObject == nil) {
171 | BMP_ArrayM_NilObject_ErrorHandler(@"*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil");
172 | return;
173 | }
174 | if (index > self.count) {
175 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSArrayM insertObject:atIndex:]: index %ld beyond bounds [0 .. %ld]",(unsigned long)index,(unsigned long)self.count];
176 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
177 | return;
178 | }
179 | [self BMP_MArrayInsertObject:anObject atIndex:index];
180 | }
181 |
182 | - (void)BMP_MArrayInsertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes{
183 | if (indexes.firstIndex > self.count) {
184 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[NSMutableArray insertObjects:atIndexes:]: index %ld in index set beyond bounds [0 .. %ld]",(unsigned long)indexes.firstIndex,(unsigned long)self.count];
185 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
186 | return;
187 | }else if (objects.count != (indexes.count)){
188 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[NSMutableArray insertObjects:atIndexes:]: count of array (%ld) differs from count of index set (%ld)",(unsigned long)objects.count,(unsigned long)indexes.count];
189 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
190 | return;
191 | }
192 | [self BMP_MArrayInsertObjects:objects atIndexes:indexes];
193 | }
194 |
195 | //replaceObjectAtIndex
196 | - (void)BMP_replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject{
197 | if (anObject == nil) {
198 | BMP_ArrayM_NilObject_ErrorHandler(@"*** -[__NSArrayM replaceObjectAtIndex:withObject:]: object cannot be nil");
199 | return;
200 | }
201 | if (index >= self.count) {
202 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSArrayM replaceObjectAtIndex:withObject:]: index %ld beyond bounds [0 .. %ld]",(unsigned long)index,(unsigned long)self.count];
203 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
204 | return;
205 | }
206 | [self BMP_replaceObjectAtIndex:index withObject:anObject];
207 | }
208 |
209 | - (void)BMP_replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects{
210 | if (indexes.lastIndex >= self.count||indexes.firstIndex >= self.count) {
211 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSArrayM replaceObjectsInRange:withObjects:count:]: range {%ld, %ld} extends beyond bounds [0 .. %ld]",(unsigned long)indexes.firstIndex,(unsigned long)indexes.count,(unsigned long)self.count];
212 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
213 | }else{
214 | [self BMP_replaceObjectsAtIndexes:indexes withObjects:objects];
215 | }
216 | }
217 |
218 | -(void)BMP_replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray{
219 | if (range.location+range.length > self.count) {
220 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[NSMutableArray replaceObjectsInRange:withObjectsFromArray:]: range {%ld, %ld} extends beyond bounds [0 .. %ld]",(unsigned long)range.location,(unsigned long)range.length,(unsigned long)self.count];
221 | BMP_ArrayM_BeyondBounds_ErrorHandler(errorInfo);
222 | }else{
223 | [self BMP_replaceObjectsInRange:range withObjectsFromArray:otherArray];
224 | }
225 | }
226 |
227 | @end
228 |
229 | @interface NSDictionary (BMPProtector)
230 |
231 | @end
232 |
233 | @implementation NSDictionary (BMPProtector)
234 |
235 | + (instancetype)BMP_dictionaryWithObjects:(id _Nonnull const [])objects forKeys:(id _Nonnull const [])keys count:(NSUInteger)cnt{
236 | return [self BMP_dictionaryWithObjects:objects forKeys:keys count:cnt];
237 | }
238 |
239 | + (instancetype)BMP_dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray> *)keys{
240 | if (objects.count != keys.count) {
241 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[NSDictionary initWithObjects:forKeys:]: count of objects (%ld) differs from count of keys (%ld)",(unsigned long)objects.count,(unsigned long)keys.count];
242 | BMP_Dictionary_ErrorHandler(errorInfo);
243 | return nil;//huicha
244 | }
245 | NSUInteger index = 0;
246 | id _Nonnull objectsNew[objects.count];
247 | id _Nonnull keysNew[keys.count];
248 | for (int i = 0; i _Nonnull const [])keys count:(NSUInteger)cnt{
262 | NSUInteger index = 0;
263 | id _Nonnull objectsNew[cnt];
264 | id _Nonnull keysNew[cnt];
265 | //'*** -[NSDictionary initWithObjects:forKeys:]: count of objects (1) differs from count of keys (0)'
266 | for (int i = 0; i)aKey{
289 | if (anObject == nil || aKey == nil) {
290 | NSString * errorInfo = @"*** setObjectForKey: object or key cannot be nil";
291 | BMP_DictionaryM_ErrorHandler(errorInfo);
292 | }else{
293 | [self BMP_dictionaryMSetObject:anObject forKey:aKey];
294 | }
295 | }
296 |
297 | //removeObjectForKey:
298 | - (void)BMP_dictionaryMRemoveObjectForKey:(id)aKey{
299 | if (aKey == nil) {
300 | NSString *errorInfo = @"*** -[__NSDictionaryM removeObjectForKey:]: key cannot be nil";
301 | BMP_DictionaryM_ErrorHandler(errorInfo);
302 |
303 | }else{
304 | [self BMP_dictionaryMRemoveObjectForKey:aKey];
305 | }
306 | }
307 |
308 | @end
309 |
310 | @interface NSString (BMPProtector)
311 |
312 | @end
313 |
314 | @implementation NSString (BMPProtector)
315 | - (unichar)BMP_characterAtIndex:(NSUInteger)index{
316 | if (index>=self.length) {
317 | unichar characteristic = 0;
318 | NSString *errorInfo = @"*** -[__NSCFConstantString characterAtIndex:]: Range or index out of bounds";
319 | BMP_Container_ErrorHandler(BMPErrorString_Beyond, errorInfo);
320 | return characteristic;
321 | }
322 | return [self BMP_characterAtIndex:index];
323 | }
324 |
325 | - (NSString *)BMP_substringFromIndex:(NSUInteger)from{
326 | id instance = nil;
327 | @try {
328 | instance = [self BMP_substringFromIndex:from];
329 | }
330 | @catch (NSException *exception) {
331 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSCFConstantString substringFromIndex:]: Index %ld out of bounds; string length %ld",(unsigned long)from,(unsigned long)self.length];
332 | BMP_Container_ErrorHandler(BMPErrorString_Beyond, errorInfo);
333 | }
334 | @finally {
335 | return instance;
336 | }
337 | }
338 |
339 | - (NSString *)BMP_substringToIndex:(NSUInteger)to{
340 | id instance = nil;
341 | @try {
342 | instance = [self BMP_substringToIndex:to];
343 | }
344 | @catch (NSException *exception) {
345 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSCFConstantString substringToIndex:]: Index %ld out of bounds; string length %ld",(unsigned long)to,(unsigned long)self.length];
346 | BMP_Container_ErrorHandler(BMPErrorString_Beyond, errorInfo);
347 | }
348 | @finally {
349 | return instance;
350 | }
351 | }
352 |
353 | - (NSString *)BMP_substringWithRange:(NSRange)range{
354 | id instance = nil;
355 | @try {
356 | instance = [self BMP_substringWithRange:range];
357 | }
358 | @catch (NSException *exception) {
359 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSCFConstantString BMP_substringWithRange:]: Range {%ld, %ld} out of bounds; string length %ld",(unsigned long)range.location,(unsigned long)range.length,(unsigned long)self.length];
360 | BMP_Container_ErrorHandler(BMPErrorString_Beyond, errorInfo);
361 | }
362 | @finally {
363 | return instance;
364 | }
365 | }
366 | @end
367 |
368 | @interface NSMutableString (BMPProtector)
369 |
370 | @end
371 |
372 | @implementation NSMutableString (BMPProtector)
373 | - (void)BMP_insertString:(NSString *)aString atIndex:(NSUInteger)loc{
374 | if (loc > self.length) {
375 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSCFString insertString:atIndex:]: Range or index out of bounds"];
376 | BMP_Container_ErrorHandler(BMPErrorString_Beyond, errorInfo);
377 | }else{
378 | [self BMP_insertString:aString atIndex:loc];
379 | }
380 | }
381 |
382 | - (void)BMP_deleteCharactersInRange:(NSRange)range{
383 | if (range.location+range.length > self.length) {
384 | NSString *errorInfo = [NSString stringWithFormat:@"*** -[__NSCFString deleteCharactersInRange:]: Range or index out of bounds"];
385 | BMP_Container_ErrorHandler(BMPErrorString_Beyond, errorInfo);
386 | if (range.location < self.length) {
387 | [self BMP_deleteCharactersInRange:NSMakeRange(range.location, self.length-range.location)];
388 | }
389 | }else{
390 | [self BMP_deleteCharactersInRange:range];
391 | }
392 | }
393 |
394 | @end
395 |
396 | @implementation BayMaxContainers
397 |
398 | + (void)BMPExchangeContainersMethodsWithCatchErrorHandler:(void(^)(BayMaxCatchError * error))errorHandler{
399 | _containerErrorHandler = errorHandler;
400 | //NSArray
401 | [self exchangeMethodsInNSArray];
402 | //NSMutableArray
403 | [self exchangeMethodsInNSMutableArray];
404 | //NSDictionary
405 | [self exchangeMethodsInNSDictionary];
406 | //NSMutableDictionary
407 | [self exchangeMethodsInNSMutableDictionary];
408 | //NSString
409 | [self exchangeMethodsInNSString];
410 | //NSMutableString
411 | [self exchangeMethodsInNSMutableString];
412 | }
413 |
414 | + (void)exchangeMethodsInNSArray{
415 | Class __NSArray = NSClassFromString(@"NSArray");
416 | Class __NSArrayI = NSClassFromString(@"__NSArrayI");
417 | Class __NSSingleObjectArrayI = NSClassFromString(@"__NSSingleObjectArrayI");
418 | Class __NSArray0 = NSClassFromString(@"__NSArray0");
419 | //insertNil
420 | BMP_EXChangeClassMethod(__NSArray, @selector(arrayWithObjects:count:), @selector(BMP_ArrayWithObjects:count:));
421 | //objectAtIndex:
422 | BMP_EXChangeInstanceMethod(__NSArrayI, @selector(objectAtIndex:), __NSArrayI, @selector(BMP__NSArrayIObjectAtIndex:));
423 | BMP_EXChangeInstanceMethod(__NSArrayI, @selector(objectAtIndexedSubscript:), __NSArrayI, @selector(BMP_objectAtIndexedSubscript:));
424 | //#endif
425 | BMP_EXChangeInstanceMethod(__NSSingleObjectArrayI, @selector(objectAtIndex:), __NSSingleObjectArrayI, @selector(BMP__NSSingleObjectArrayIObjectAtIndex:));
426 | BMP_EXChangeInstanceMethod(__NSArray0, @selector(objectAtIndex:), __NSArray0, @selector(BMP__NSArray0ObjectAtIndex:));
427 | }
428 |
429 | + (void)exchangeMethodsInNSMutableArray{
430 | Class arrayMClass = NSClassFromString(@"__NSArrayM");
431 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(objectAtIndex:), arrayMClass, @selector(BMP_MArrayObjectAtIndex:));
432 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(objectAtIndexedSubscript:), arrayMClass, @selector(BMP_MArrayobjectAtIndexedSubscript:));
433 | //#endif
434 | //remove
435 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(removeObjectAtIndex:), arrayMClass, @selector(BMP_MArrayRemoveObjectAtIndex:));
436 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(removeObjectsInRange:), arrayMClass, @selector(BMP_MArrayRemoveObjectsInRange:));
437 |
438 | //insert
439 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(insertObject:atIndex:), arrayMClass, @selector(BMP_MArrayInsertObject:atIndex:));
440 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(insertObjects:atIndexes:), arrayMClass, @selector(BMP_MArrayInsertObjects:atIndexes:));
441 | //replace
442 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(replaceObjectAtIndex:withObject:), arrayMClass, @selector(BMP_replaceObjectAtIndex:withObject:));
443 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(replaceObjectsAtIndexes:withObjects:), arrayMClass, @selector(BMP_replaceObjectsAtIndexes:withObjects:));
444 | BMP_EXChangeInstanceMethod(arrayMClass, @selector(replaceObjectsInRange:withObjectsFromArray:), arrayMClass, @selector(BMP_replaceObjectsInRange:withObjectsFromArray:));
445 | }
446 |
447 | + (void)exchangeMethodsInNSDictionary{
448 | Class dictionaryClass = NSClassFromString(@"NSDictionary");
449 | Class __NSPlaceholderDictionaryClass = NSClassFromString(@"__NSPlaceholderDictionary");
450 | BMP_EXChangeClassMethod(dictionaryClass, @selector(dictionaryWithObjects:forKeys:count:), @selector(BMP_dictionaryWithObjects:forKeys:count:));
451 | BMP_EXChangeInstanceMethod(__NSPlaceholderDictionaryClass, @selector(initWithObjects:forKeys:count:), __NSPlaceholderDictionaryClass, @selector(BMP_initWithObjects:forKeys:count:));
452 | }
453 |
454 | + (void)exchangeMethodsInNSMutableDictionary{
455 | Class dictionaryM = NSClassFromString(@"__NSDictionaryM");
456 | BMP_EXChangeInstanceMethod(dictionaryM, @selector(setObject:forKey:), dictionaryM, @selector(BMP_dictionaryMSetObject:forKey:));
457 | BMP_EXChangeInstanceMethod(dictionaryM, @selector(removeObjectForKey:), dictionaryM, @selector(BMP_dictionaryMRemoveObjectForKey:));
458 | }
459 |
460 | + (void)exchangeMethodsInNSString{
461 | Class stringClass = NSClassFromString(@"__NSCFConstantString");
462 | BMP_EXChangeInstanceMethod(stringClass, @selector(characterAtIndex:), stringClass, @selector(BMP_characterAtIndex:));
463 | BMP_EXChangeInstanceMethod(stringClass, @selector(substringFromIndex:), stringClass, @selector(BMP_substringFromIndex:));
464 | BMP_EXChangeInstanceMethod(stringClass, @selector(substringToIndex:), stringClass, @selector(BMP_substringToIndex:));
465 | BMP_EXChangeInstanceMethod(stringClass, @selector(substringWithRange:), stringClass, @selector(BMP_substringWithRange:));
466 | }
467 |
468 | + (void)exchangeMethodsInNSMutableString{
469 | Class stringClass = NSClassFromString(@"__NSCFString");
470 | BMP_EXChangeInstanceMethod(stringClass, @selector(insertString:atIndex:), stringClass, @selector(BMP_insertString:atIndex:));
471 | BMP_EXChangeInstanceMethod(stringClass, @selector(deleteCharactersInRange:), stringClass, @selector(BMP_deleteCharactersInRange:));
472 | }
473 |
474 | @end
475 |
476 |
477 |
--------------------------------------------------------------------------------
/Class/ARC/BayMaxProtector.m:
--------------------------------------------------------------------------------
1 | //
2 | // BayMaxProtector.m
3 | // BayMaxProtector
4 | //
5 | // Created by ccSunday on 2017/3/23.
6 | // Copyright © 2018年 ccSunday. All rights reserved.
7 | //
8 | #import
9 | #import
10 | #import "BayMaxProtector.h"
11 | #import "BayMaxKVODelegate.h"
12 | #import "BayMaxTimerSubTarget.h"
13 | #import "BayMaxCFunctions.h"
14 | #import "BayMaxDegradeAssist.h"
15 | #import "BayMaxContainers.h"
16 | #import "BayMaxDebugView.h"
17 | #import "BayMaxCatchError.h"
18 |
19 | //声明一个全局的IMP链表
20 | static IMPlist impList;
21 | //声明一个全局的错误信息结构体
22 | static ErrorInfos errors;
23 | //声明错误信息处理handler
24 | BMPErrorHandler _Nullable _errorHandler;
25 | //声明保存需要忽略的类前缀数组
26 | static NSArray *_ignorePrefixes;
27 | static BOOL _showDebugView;
28 | /*动态添加方法的imp*/
29 | static inline int DynamicAddMethodIMP(id self,SEL _cmd,...){
30 | #ifdef DEBUG
31 | #else
32 | #endif
33 | return 0;
34 | }
35 |
36 | /*是否是系统类*/
37 | static inline BOOL IsSystemClass(Class cls){
38 | __block BOOL isSystem = NO;
39 | NSString *className = NSStringFromClass(cls);
40 | if ([className hasPrefix:@"NS"]) {
41 | isSystem = YES;
42 | return isSystem;
43 | }
44 | NSBundle *mainBundle = [NSBundle bundleForClass:cls];
45 | if (mainBundle == [NSBundle mainBundle]) {
46 | isSystem = NO;
47 | }else{
48 | isSystem = YES;
49 | }
50 | if (_ignorePrefixes.count>0) {
51 | [_ignorePrefixes enumerateObjectsUsingBlock:^(NSString * prefix, NSUInteger idx, BOOL * _Nonnull stop) {
52 | if ([className hasPrefix:prefix]) {
53 | isSystem = YES;
54 | *stop = YES;
55 | }
56 | }];
57 | }
58 | return isSystem;
59 | }
60 |
61 | /*错误发生在viewdidload中的时候获取发生错误的视图控制器的类名*/
62 | static inline NSString *GetClassNameOfViewControllerIfErrorHappensInViewDidloadProcessWithCallStackSymbols(NSArray *callStackSymbolsArr){
63 | __block NSString *className;
64 | if (callStackSymbolsArr != nil) {
65 | for (int i = 3; i < callStackSymbolsArr.count; i++) {
66 | NSString *symbol = callStackSymbolsArr[i];
67 | if ([symbol containsString:@"UIKit"]) {
68 | NSString *lastSymbol = callStackSymbolsArr[i-1];
69 | if ([lastSymbol containsString:@"viewDidLoad"]) {
70 | if ([lastSymbol rangeOfString:@"-["].length>0) {
71 | NSRange beginRange = [lastSymbol rangeOfString:@"-["];
72 | NSRange endRange = [lastSymbol rangeOfString:@"viewDidLoad"];
73 | NSInteger length = endRange.location-1-(beginRange.location+beginRange.length);
74 | className = [lastSymbol substringWithRange:NSMakeRange(beginRange.location+beginRange.length, length)];
75 | break;
76 | }else{
77 |
78 | }
79 | }
80 | }
81 |
82 | }
83 | }
84 | return className;
85 | }
86 |
87 | #pragma mark BayMaxCrashHandler
88 | @interface BayMaxCrashHandler : NSObject
89 | + (nonnull instancetype)sharedBayMaxCrashHandler;
90 | - (void)forwardingCrashMethodInfos:(NSDictionary *_Nullable)infos;
91 | @end
92 |
93 | @implementation BayMaxCrashHandler
94 |
95 | static BayMaxCrashHandler *_instance;
96 |
97 | + (id)allocWithZone:(struct _NSZone *)zone{
98 | static dispatch_once_t onceToken;
99 | dispatch_once(&onceToken, ^{
100 | _instance = [super allocWithZone:zone];
101 | });
102 | return _instance;
103 | }
104 |
105 | + (nonnull instancetype)sharedBayMaxCrashHandler{
106 | static dispatch_once_t onceToken;
107 | dispatch_once(&onceToken, ^{
108 | _instance = [[self alloc] init];
109 | });
110 | return _instance;
111 | }
112 |
113 | - (id)copyWithZone:(NSZone *)zone{
114 | return _instance;
115 | }
116 |
117 | - (void)forwardingCrashMethodInfos:(NSDictionary *_Nullable)infos{
118 | #ifdef DEBUG
119 | #else
120 | #endif
121 | }
122 |
123 | @end
124 |
125 | #pragma mark NSObject + UNRecognizedSelHandler
126 | @interface NSObject (UNRecognizedSelHandler)
127 | @end
128 |
129 | @implementation NSObject (UNRecognizedSelHandler)
130 | static NSString *const ErrorClassName = @"BMPError_ClassName";
131 | static NSString *const ErrorFunctionName = @"BMPError_FunctionName";
132 | static NSString *const ErrorViewController = @"BMPError_ViewController";
133 |
134 | //将崩溃信息转发到一个指定的类中执行FastForwarding
135 | - (id)BMP_forwardingTargetForSelector:(SEL)selector{
136 | /*判断当前类有没有重写消息转发的相关方法*/
137 | if ([self isEqual:[NSNull null]] || ![self overideForwardingMethods]) {//没有重写消息转发方法
138 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
139 | NSString *vcClassName = GetClassNameOfViewControllerIfErrorHappensInViewDidloadProcessWithCallStackSymbols(callStackSymbolsArr);
140 | //判断是否是viewdidload方法出错
141 | errors = ErrorInfosMake([NSStringFromClass(self.class) cStringUsingEncoding:NSASCIIStringEncoding], [NSStringFromSelector(selector) cStringUsingEncoding:NSASCIIStringEncoding]);
142 | class_addMethod([BayMaxCrashHandler class], selector, (IMP)DynamicAddMethodIMP, "v@:");
143 | [[BayMaxCrashHandler sharedBayMaxCrashHandler]forwardingCrashMethodInfos:@{ErrorClassName:NSStringFromClass(self.class),
144 | ErrorFunctionName:NSStringFromSelector(selector),
145 | ErrorViewController:[[BayMaxDegradeAssist Assist]topViewController]
146 | }];
147 | BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeUnrecognizedSelector infos:@{
148 | BMPErrorUnrecognizedSel_Reason:[NSString stringWithFormat:@"UNRecognized Selector:'%@' sent to instance %@",NSStringFromSelector(selector),self],
149 | BMPErrorUnrecognizedSel_VC:vcClassName == nil?([[BayMaxDegradeAssist Assist]topViewController] == nil?@"":[[BayMaxDegradeAssist Assist]topViewController]):vcClassName,
150 | BMPErrorCallStackSymbols:callStackSymbolsArr
151 | }];
152 | if (_showDebugView) {
153 | [[BayMaxDebugView sharedDebugView]addErrorInfo:bmpError.errorInfos];
154 | }
155 | [[BayMaxDegradeAssist Assist]handleError:bmpError];
156 | if (_errorHandler) {
157 | _errorHandler(bmpError);
158 | }
159 | return [BayMaxCrashHandler sharedBayMaxCrashHandler];
160 | }
161 | return [self BMP_forwardingTargetForSelector:selector];
162 | }
163 |
164 | - (BOOL)overideForwardingMethods{
165 | BOOL overide = NO;
166 | overide = (class_getMethodImplementation([NSObject class], @selector(forwardInvocation:)) != class_getMethodImplementation([self class], @selector(forwardInvocation:))) ||
167 | (class_getMethodImplementation([NSObject class], @selector(forwardingTargetForSelector:)) != class_getMethodImplementation([self class], @selector(forwardingTargetForSelector:)));
168 | return overide;
169 | }
170 |
171 | @end
172 |
173 | #pragma mark NSObject + KVOProtector
174 | @interface NSObject (KVOProtector)
175 | @end
176 |
177 | @implementation NSObject (KVOProtector)
178 | static void *KVOProtectorKey = &KVOProtectorKey;
179 | static NSString *const KVOProtectorValue = @"BMP_KVOProtector";
180 | static void *BayMaxKVODelegateKey = &BayMaxKVODelegateKey;
181 |
182 | - (void)setBayMaxKVODelegate:(BayMaxKVODelegate *)BayMaxKVODelegate{
183 | objc_setAssociatedObject(self, BayMaxKVODelegateKey, BayMaxKVODelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
184 | }
185 |
186 | - (BayMaxKVODelegate *)bayMaxKVODelegate{
187 | id bayMaxKVODelegate = objc_getAssociatedObject(self, BayMaxKVODelegateKey);
188 | if (bayMaxKVODelegate == nil) {
189 | bayMaxKVODelegate = [[BayMaxKVODelegate alloc]init];
190 | self.bayMaxKVODelegate = bayMaxKVODelegate;
191 | }
192 | return bayMaxKVODelegate;
193 | }
194 |
195 | - (void)BMP_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{
196 | if (!IsSystemClass(self.class)) {
197 | __weak typeof(self) weakSelf = self;
198 | objc_setAssociatedObject(self, KVOProtectorKey, KVOProtectorValue, OBJC_ASSOCIATION_RETAIN);
199 | [self.bayMaxKVODelegate addKVOInfoToMapsWithObserver:observer forKeyPath:keyPath options:options context:context success:^{
200 | [weakSelf BMP_addObserver:weakSelf.bayMaxKVODelegate forKeyPath:keyPath options:options context:context];
201 | } failure:^(NSError *error) {
202 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
203 | BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeKVO infos:@{
204 | BMPErrorKVO_Reason:[NSString stringWithFormat:@"Repeated additions to the observer:%@ for the key path:'%@' from %@",observer == nil?@"":observer,keyPath,NSStringFromClass(weakSelf.class) == nil?@"":NSStringFromClass(weakSelf.class)]
205 | }];
206 | if (_showDebugView) {
207 | [[BayMaxDebugView sharedDebugView]addErrorInfo:bmpError.errorInfos];
208 | }
209 | if (_errorHandler) {
210 | _errorHandler(bmpError);
211 | }
212 | }];
213 | }else{
214 | [self BMP_addObserver:observer forKeyPath:keyPath options:options context:context];
215 | }
216 | }
217 |
218 | - (void)BMP_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath{
219 | if (!IsSystemClass(self.class)) {
220 | if ([self.bayMaxKVODelegate removeKVOInfoInMapsWithObserver:observer forKeyPath:keyPath]) {
221 | [self BMP_removeObserver:self.bayMaxKVODelegate forKeyPath:keyPath];
222 | }else{
223 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
224 | NSString *reson = [NSString stringWithFormat:@"Cannot remove an observer %@ for the key path '%@' from %@ because it is not registered as an observer",observer,keyPath,NSStringFromClass(self.class) == nil?@"":NSStringFromClass(self.class)];
225 | BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeKVO infos:@{
226 | BMPErrorKVO_Reason:reson
227 | }];
228 | if (_showDebugView) {
229 | [[BayMaxDebugView sharedDebugView]addErrorInfo:bmpError.errorInfos];
230 | }
231 | if (_errorHandler) {
232 | _errorHandler(bmpError);
233 | }
234 | }
235 | }else{
236 | [self BMP_removeObserver:observer forKeyPath:keyPath];
237 | }
238 | }
239 |
240 | - (void)BMP_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context{
241 | if (!IsSystemClass(self.class)) {
242 | if ([self.bayMaxKVODelegate removeKVOInfoInMapsWithObserver:observer forKeyPath:keyPath]) {
243 | [self BMP_removeObserver:self.bayMaxKVODelegate forKeyPath:keyPath];
244 | }else{
245 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
246 | NSString *reson = [NSString stringWithFormat:@"Cannot remove an observer %@ for the key path '%@' from %@ because it is not registered as an observer",observer,keyPath,NSStringFromClass(self.class) == nil?@"":NSStringFromClass(self.class)];
247 | BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeKVO infos:@{
248 | BMPErrorKVO_Reason:reson
249 | }];
250 | if (_showDebugView) {
251 | [[BayMaxDebugView sharedDebugView]addErrorInfo:bmpError.errorInfos];
252 | }
253 | if (_errorHandler) {
254 | _errorHandler(bmpError);
255 | }
256 | }
257 | }else{
258 | [self BMP_removeObserver:observer forKeyPath:keyPath context:context];
259 | }
260 | }
261 |
262 | - (void)BMPKVO_dealloc{
263 | if (!IsSystemClass(self.class)) {
264 | NSString *value = (NSString *)objc_getAssociatedObject(self, KVOProtectorKey);
265 | if ([value isEqualToString:KVOProtectorValue]) {
266 | NSArray *keypaths = [self.bayMaxKVODelegate getAllKeypaths];
267 | if (keypaths.count>0) {
268 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
269 | NSString *reson = [NSString stringWithFormat:@"An instance %@ was deallocated while key value observers were still registered with it. The Keypaths is:'%@'",self,[keypaths componentsJoinedByString:@","]];
270 | BayMaxCatchError *bmpError = [BayMaxCatchError BMPErrorWithType:BayMaxErrorTypeKVO infos:@{
271 | BMPErrorKVO_Reason:reson
272 | }];
273 | if (_showDebugView) {
274 | [[BayMaxDebugView sharedDebugView]addErrorInfo:bmpError.errorInfos];
275 | }
276 | if (_errorHandler) {
277 | _errorHandler(bmpError);
278 | }
279 | }
280 | [keypaths enumerateObjectsUsingBlock:^(NSString *keyPath, NSUInteger idx, BOOL * _Nonnull stop) {
281 | //错误信息
282 | [self BMP_removeObserver:self.bayMaxKVODelegate forKeyPath:keyPath];
283 | }];
284 | }
285 | }
286 | [self BMPKVO_dealloc];
287 | }
288 |
289 | @end
290 |
291 | #pragma mark NSNotificationCenter+NotificationProtector
292 | static void *NSNotificationProtectorKey = &NSNotificationProtectorKey;
293 | static NSString *const NSNotificationProtectorValue = @"BMP_NotificationProtector";
294 |
295 | @interface NSNotificationCenter (NotificationProtector)
296 | @end
297 |
298 | #pragma mark UIViewController+NotificationProtector
299 | @interface UIViewController (NotificationProtector)
300 | @end
301 |
302 | @implementation NSNotificationCenter (NotificationProtector)
303 | - (void)BMP_addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject{
304 | objc_setAssociatedObject(observer, NSNotificationProtectorKey, NSNotificationProtectorValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
305 | [self BMP_addObserver:observer selector:aSelector name:aName object:anObject];
306 | }
307 |
308 | @end
309 |
310 | @implementation UIViewController (NotificationProtector)
311 | - (void)BMP_dealloc{
312 | NSString *value = (NSString *)objc_getAssociatedObject(self, NSNotificationProtectorKey);
313 | if ([value isEqualToString:NSNotificationProtectorValue]) {
314 | [[NSNotificationCenter defaultCenter] removeObserver:self];
315 | }
316 | [self BMP_dealloc];
317 | }
318 |
319 | @end
320 |
321 | #pragma mark NSTimer+TimerProtector
322 | @interface NSTimer (TimerProtector)
323 |
324 | @end
325 |
326 | @implementation NSTimer (TimerProtector)
327 |
328 | + (NSTimer *)BMP_scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo{
329 | if (yesOrNo == NO) {
330 | return [self BMP_scheduledTimerWithTimeInterval:ti target:aTarget selector:aSelector userInfo:userInfo repeats:yesOrNo];
331 | }else{
332 | if (!IsSystemClass([aTarget class])) {
333 | BayMaxTimerSubTarget *subtarget = [BayMaxTimerSubTarget targetWithTimeInterval:ti target:aTarget selector:aSelector userInfo:userInfo repeats:yesOrNo catchErrorHandler:^(BayMaxCatchError *error) {
334 | if (_showDebugView) {
335 | [[BayMaxDebugView sharedDebugView]addErrorInfo:error.errorInfos];
336 | }
337 | if (_errorHandler) {
338 | _errorHandler(error);
339 | }
340 | }];
341 | return [self BMP_scheduledTimerWithTimeInterval:ti target:subtarget selector:NSSelectorFromString(@"fireProxyTimer:") userInfo:userInfo repeats:yesOrNo];
342 | }else{
343 | return [self BMP_scheduledTimerWithTimeInterval:ti target:aTarget selector:aSelector userInfo:userInfo repeats:yesOrNo];
344 | }
345 | }
346 | }
347 |
348 | + (NSTimer *)BMP_timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo{
349 | if (yesOrNo == NO) {
350 | return [self BMP_timerWithTimeInterval:ti target:aTarget selector:aSelector userInfo:userInfo repeats:yesOrNo];
351 | }else{
352 | if (!IsSystemClass([aTarget class])) {
353 | BayMaxTimerSubTarget *subtarget = [BayMaxTimerSubTarget targetWithTimeInterval:ti target:aTarget selector:aSelector userInfo:userInfo repeats:yesOrNo catchErrorHandler:^(BayMaxCatchError *error) {
354 | if (_showDebugView) {
355 | [[BayMaxDebugView sharedDebugView]addErrorInfo:error.errorInfos];
356 | }
357 | if (_errorHandler) {
358 | _errorHandler(error);
359 | } }];
360 | return [self BMP_timerWithTimeInterval:ti target:subtarget selector:NSSelectorFromString(@"fireProxyTimer:") userInfo:userInfo repeats:yesOrNo];
361 | }else{
362 | return [self BMP_timerWithTimeInterval:ti target:aTarget selector:aSelector userInfo:userInfo repeats:yesOrNo];
363 | }
364 | }
365 | }
366 |
367 | @end
368 |
369 | #pragma mark BayMaxProtector
370 | @interface BayMaxProtector()
371 |
372 | @end
373 |
374 | @implementation BayMaxProtector
375 |
376 | + (void)load{
377 | IMP maping_ForwardingTarget_IMP = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingForwardingTargetForSelectorMethod));
378 | IMP KVO_IMP = class_getMethodImplementation([NSObject class], @selector(addObserver:forKeyPath:options:context:));
379 | IMP maping_Timer_IMP = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingTimerMethod));
380 | IMP notification_IMP = class_getMethodImplementation([NSNotificationCenter class], @selector(addObserver:selector:name:object:));
381 | IMP mapping_Containers_IMP = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingContainersMethods));
382 | impList = malloc(sizeof(struct IMPNode));
383 | impList->next = NULL;
384 | BMP_InsertIMPToList(impList, maping_ForwardingTarget_IMP);
385 | BMP_InsertIMPToList(impList, KVO_IMP);
386 | BMP_InsertIMPToList(impList, maping_Timer_IMP);
387 | BMP_InsertIMPToList(impList, notification_IMP);
388 | BMP_InsertIMPToList(impList, mapping_Containers_IMP);
389 | }
390 |
391 | + (void)openProtectionsOn:(BayMaxProtectionType)protectionType{
392 | [self filterProtectionsOn:protectionType operation:YES];
393 | }
394 |
395 | + (void)closeProtectionsOn:(BayMaxProtectionType)protectionType{
396 | [self filterProtectionsOn:protectionType operation:NO];
397 | }
398 |
399 | + (void)filterProtectionsOn:(BayMaxProtectionType)protectionType operation:(BOOL)openOperation{
400 | IMP imp;
401 | if (protectionType > (1<<4)) {
402 | imp = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingContainersMethods));
403 | [self filterProtectionsOn:BayMaxProtectionTypeContainers protectionName:@"Containers" operation:openOperation imp:imp];
404 | protectionType -= (1<<4) ;
405 | }
406 | if (protectionType > (1<<3) && protectionType != BayMaxProtectionTypeContainers) {
407 | imp = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingTimerMethod));
408 | [self filterProtectionsOn:BayMaxProtectionTypeTimer protectionName:@"Timer" operation:openOperation imp:imp];
409 | protectionType -= (1<<3) ;
410 | }
411 | switch (protectionType) {
412 | case BayMaxProtectionTypeUnrecognizedSelector:
413 | imp = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingForwardingTargetForSelectorMethod));
414 | [self filterProtectionsOn:protectionType protectionName:@"UnrecognizedSelector" operation:openOperation imp:imp];
415 | break;
416 |
417 | case BayMaxProtectionTypeKVO:
418 | imp = class_getMethodImplementation([NSObject class], @selector(addObserver:forKeyPath:options:context:));
419 | [self filterProtectionsOn:protectionType protectionName:@"KVO" operation:openOperation imp:imp];
420 | break;
421 | case BayMaxProtectionTypeNotification:
422 | imp = class_getMethodImplementation([NSNotificationCenter class], @selector(addObserver:selector:name:object:));
423 | [self filterProtectionsOn:protectionType protectionName:@"Notification" operation:openOperation imp:imp];
424 | break;
425 | case BayMaxProtectionTypeTimer:
426 | imp = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingTimerMethod));
427 | [self filterProtectionsOn:protectionType protectionName:@"Timer" operation:openOperation imp:imp];
428 | break;
429 | case BayMaxProtectionTypeContainers:
430 | imp = class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingContainersMethods));
431 | [self filterProtectionsOn:protectionType protectionName:@"Containers" operation:openOperation imp:imp];
432 | break;
433 | case BayMaxProtectionTypeAll:
434 | [self filterProtectionsOn:BayMaxProtectionTypeUnrecognizedSelector protectionName:@"UnrecognizedSelector" operation:openOperation imp:class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingForwardingTargetForSelectorMethod))];
435 | [self filterProtectionsOn:BayMaxProtectionTypeKVO protectionName:@"KVO" operation:openOperation imp:class_getMethodImplementation([NSObject class], @selector(addObserver:forKeyPath:options:context:))];
436 | [self filterProtectionsOn:BayMaxProtectionTypeNotification protectionName:@"Notification" operation:openOperation imp:class_getMethodImplementation([NSNotificationCenter class], @selector(addObserver:selector:name:object:))];
437 | [self filterProtectionsOn:BayMaxProtectionTypeTimer protectionName:@"Timer" operation:openOperation imp:class_getMethodImplementation([BayMaxProtector class], @selector(BMP_mappingTimerMethod))];
438 | }
439 | }
440 |
441 | + (void)filterProtectionsOn:(BayMaxProtectionType)protectionType protectionName:(NSString *)protectionName operation:(BOOL)openOperation imp:(IMP)imp{
442 | if (openOperation) {//开启
443 | if (BMP_ImpExistInList(impList, imp)) {//存在该imp,说明没有被交换,此时应该进行交换
444 | NSLog(@"开启保护:%@",protectionName);
445 | [self openProtectionsOn:protectionType catchErrorHandler:nil];
446 | }else{//说明此时已经被交换过了,不需要再次进行交换,空处理即可。
447 | NSString * duplicateProtection = [NSString stringWithFormat:@"[%@] Is Already In The Protection State And Do not Need To Open This Protection mode again",protectionName];
448 | [[BayMaxDebugView sharedDebugView]addErrorInfo:@{@"waring":duplicateProtection}];
449 | }
450 | }else{ //关闭防护
451 | if (!BMP_ImpExistInList(impList, imp)) {//如果此时不存在该imp,说明发生过方法交换,此时应该进行再次交换,已关闭崩溃保护
452 | NSLog(@"关闭保护:%@",protectionName);
453 | [self openProtectionsOn:protectionType catchErrorHandler:nil];
454 | }else{//说明该方法没有被交换,即没有列在保护名单里,空处理即可
455 | NSString * duplicateClose = [NSString stringWithFormat:@"[%@] Is Not In The Protection State Before And Don't Need To Close This Protection Again",protectionName];
456 | [[BayMaxDebugView sharedDebugView]addErrorInfo:@{@"waring":duplicateClose}];
457 | }
458 | }
459 | }
460 |
461 | + (void)openProtectionsOn:(BayMaxProtectionType)protectionType catchErrorHandler:(void(^_Nullable)(BayMaxCatchError * _Nullable error))errorHandler{
462 | _errorHandler = errorHandler;
463 | if (protectionType > (1<<4)) {
464 | [self exchangeMethodWithType:BayMaxProtectionTypeContainers];
465 | protectionType -= (1<<4);
466 | }
467 | if (protectionType > (1<<3) && protectionType != BayMaxProtectionTypeContainers) {
468 | [self exchangeMethodWithType:BayMaxProtectionTypeTimer];
469 | protectionType -= (1<<3) ;
470 | }
471 | switch ((long)protectionType) {
472 | case BayMaxProtectionTypeUnrecognizedSelector:
473 | case BayMaxProtectionTypeKVO:
474 | case BayMaxProtectionTypeNotification:
475 | case BayMaxProtectionTypeTimer:
476 | case BayMaxProtectionTypeContainers:
477 | case BayMaxProtectionTypeAll:
478 | {
479 | [self exchangeMethodWithType:protectionType];
480 | }
481 | break;
482 | case 3:
483 | {
484 | [self exchangeMethodWithType:BayMaxProtectionTypeUnrecognizedSelector];
485 | [self exchangeMethodWithType:BayMaxProtectionTypeKVO];
486 | }
487 | break;
488 | case 5:
489 | {
490 | [self exchangeMethodWithType:BayMaxProtectionTypeUnrecognizedSelector];
491 | [self exchangeMethodWithType:BayMaxProtectionTypeNotification];
492 | }
493 | break;
494 | case 6:
495 | {
496 | [self exchangeMethodWithType:BayMaxProtectionTypeKVO];
497 | [self exchangeMethodWithType:BayMaxProtectionTypeNotification];
498 | }
499 | break;
500 | case 7:
501 | {
502 | [self exchangeMethodWithType:BayMaxProtectionTypeUnrecognizedSelector];
503 | [self exchangeMethodWithType:BayMaxProtectionTypeKVO];
504 | [self exchangeMethodWithType:BayMaxProtectionTypeNotification];
505 | }
506 | break;
507 | }
508 | }
509 |
510 | + (void)exchangeMethodWithType:(BayMaxProtectionType)protectionType{
511 | switch (protectionType) {
512 | case BayMaxProtectionTypeUnrecognizedSelector:
513 | {
514 | BMP_EXChangeInstanceMethod([NSObject class], @selector(forwardingTargetForSelector:), [NSObject class], @selector(BMP_forwardingTargetForSelector:));
515 | BMP_EXChangeInstanceMethod([BayMaxProtector class], @selector(BMP_mappingForwardingTargetForSelectorMethod), [BayMaxProtector class], @selector(BMP_excMappingForwardingTargetForSelectorMethod));
516 | }
517 | break;
518 | case BayMaxProtectionTypeKVO:
519 | {
520 | BMP_EXChangeInstanceMethod([NSObject class], @selector(addObserver:forKeyPath:options:context:), [NSObject class], @selector(BMP_addObserver:forKeyPath:options:context:));
521 | BMP_EXChangeInstanceMethod([NSObject class], @selector(removeObserver:forKeyPath:), [NSObject class], @selector(BMP_removeObserver:forKeyPath:));
522 | BMP_EXChangeInstanceMethod([NSObject class], @selector(removeObserver:forKeyPath:context:), [NSObject class], @selector(BMP_removeObserver:forKeyPath:context:));
523 | BMP_EXChangeInstanceMethod([NSObject class], NSSelectorFromString(@"dealloc"), [NSObject class], @selector(BMPKVO_dealloc));
524 | }
525 | break;
526 |
527 | case BayMaxProtectionTypeNotification:
528 | {
529 | BMP_EXChangeInstanceMethod([NSNotificationCenter class], @selector(addObserver:selector:name:object:), [NSNotificationCenter class], @selector(BMP_addObserver:selector:name:object:));
530 | BMP_EXChangeInstanceMethod([UIViewController class], NSSelectorFromString(@"dealloc"), [UIViewController class], NSSelectorFromString(@"BMP_dealloc"));
531 | }
532 | break;
533 | case BayMaxProtectionTypeTimer:
534 | {
535 | BMP_EXChangeClassMethod([NSTimer class], @selector(scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:), @selector(BMP_scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:));
536 | BMP_EXChangeClassMethod([NSTimer class], @selector(timerWithTimeInterval:target:selector:userInfo:repeats:), @selector(BMP_timerWithTimeInterval:target:selector:userInfo:repeats:));
537 | BMP_EXChangeInstanceMethod([BayMaxProtector class], @selector(BMP_mappingTimerMethod), [BayMaxProtector class], @selector(BMP_excMappingTimerMethod));
538 | }
539 | break;
540 |
541 | case BayMaxProtectionTypeContainers:
542 | {
543 | /*containes*/
544 | [BayMaxContainers BMPExchangeContainersMethodsWithCatchErrorHandler:^(BayMaxCatchError *error) {
545 | if (_showDebugView) {
546 | [[BayMaxDebugView sharedDebugView]addErrorInfo:error.errorInfos];
547 | }
548 | if (_errorHandler) {
549 | _errorHandler(error);
550 | }
551 | }];
552 | BMP_EXChangeInstanceMethod([BayMaxProtector class], @selector(BMP_mappingContainersMethods), [BayMaxProtector class], @selector(BMP_excMappingContainersMethods));
553 |
554 | }
555 | break;
556 | case BayMaxProtectionTypeAll:
557 | {
558 | BMP_EXChangeInstanceMethod([NSObject class], @selector(forwardingTargetForSelector:), [NSObject class], @selector(BMP_forwardingTargetForSelector:));
559 | BMP_EXChangeInstanceMethod([self class], @selector(BMP_mappingForwardingTargetForSelectorMethod), [self class], @selector(BMP_excMappingForwardingTargetForSelectorMethod));
560 | BMP_EXChangeInstanceMethod([NSObject class], @selector(addObserver:forKeyPath:options:context:), [NSObject class], @selector(BMP_addObserver:forKeyPath:options:context:));
561 | BMP_EXChangeInstanceMethod([NSObject class], @selector(removeObserver:forKeyPath:), [NSObject class], @selector(BMP_removeObserver:forKeyPath:));
562 | BMP_EXChangeInstanceMethod([NSObject class], @selector(removeObserver:forKeyPath:context:), [NSObject class], @selector(BMP_removeObserver:forKeyPath:context:));
563 | BMP_EXChangeInstanceMethod([NSObject class], NSSelectorFromString(@"dealloc"), [NSObject class], @selector(BMPKVO_dealloc));
564 | BMP_EXChangeInstanceMethod([NSNotificationCenter class], @selector(addObserver:selector:name:object:), [NSNotificationCenter class], @selector(BMP_addObserver:selector:name:object:));
565 | BMP_EXChangeInstanceMethod([UIViewController class], NSSelectorFromString(@"dealloc"), [UIViewController class], NSSelectorFromString(@"BMP_dealloc"));
566 | BMP_EXChangeClassMethod([NSTimer class], @selector(scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:), @selector(BMP_scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:));
567 | BMP_EXChangeClassMethod([NSTimer class], @selector(timerWithTimeInterval:target:selector:userInfo:repeats:), @selector(BMP_timerWithTimeInterval:target:selector:userInfo:repeats:));
568 | BMP_EXChangeInstanceMethod([self class], @selector(BMP_mappingTimerMethod), [self class], @selector(BMP_excMappingTimerMethod));
569 | /*containers*/
570 | [BayMaxContainers BMPExchangeContainersMethodsWithCatchErrorHandler:^(BayMaxCatchError *error) {
571 | if (_showDebugView) {
572 | [[BayMaxDebugView sharedDebugView]addErrorInfo:error.errorInfos];
573 | }
574 | if (_errorHandler) {
575 | _errorHandler(error);
576 | }
577 | }];
578 | BMP_EXChangeInstanceMethod([BayMaxProtector class], @selector(BMP_mappingContainersMethods), [BayMaxProtector class], @selector(BMP_excMappingContainersMethods));
579 | }
580 | break;
581 | }
582 | }
583 |
584 | + (void)ignoreProtectionsOnClassesWithPrefix:(NSArray *_Nonnull)ignorePrefixes{
585 | _ignorePrefixes = ignorePrefixes;
586 | }
587 |
588 | + (void)showDebugView{
589 | _showDebugView = YES;
590 | [BayMaxDebugView sharedDebugView].hidden = NO;
591 | }
592 |
593 | + (void)hideDebugView{
594 | _showDebugView = NO;
595 | [BayMaxDebugView sharedDebugView].hidden = YES;
596 | }
597 |
598 |
599 | #pragma mark libobjc.A.dylib IMP映射
600 | /**
601 | NSObject ForwardingTargetForSelector方法的映射
602 | */
603 | - (void)BMP_mappingForwardingTargetForSelectorMethod{
604 | }
605 |
606 | - (void)BMP_excMappingForwardingTargetForSelectorMethod{
607 | }
608 | /**
609 | NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:方法的映射
610 | */
611 | - (void)BMP_mappingTimerMethod{
612 | }
613 |
614 | - (void)BMP_excMappingTimerMethod{
615 | }
616 |
617 | #pragma mark Containers IMP映射
618 | - (void)BMP_mappingContainersMethods{
619 | }
620 |
621 | - (void)BMP_excMappingContainersMethods{
622 | }
623 |
624 | @end
625 |
--------------------------------------------------------------------------------