├── SmartDemo.gif
├── SmartBlock
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── ViewController.h
├── BaseView.h
├── ThridView.h
├── SecondView.h
├── AppDelegate.h
├── main.m
├── SecondView.m
├── BaseView.m
├── ThridView.m
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── SmartBlock
│ ├── NSObject+SmartBlock.h
│ └── NSObject+SmartBlock.m
├── ViewController.m
└── AppDelegate.m
├── .gitignore
├── SmartBlock.xcodeproj
├── xcuserdata
│ └── lobster.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── SmartBlock.xcscheme
├── project.xcworkspace
│ ├── xcuserdata
│ │ └── lobster.xcuserdatad
│ │ │ ├── UserInterfaceState.xcuserstate
│ │ │ └── IDEFindNavigatorScopes.plist
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
├── LICENSE
└── README.md
/SmartDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lobster-King/SmartBlock/HEAD/SmartDemo.gif
--------------------------------------------------------------------------------
/SmartBlock/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_Store
3 | SmartBlock.xcodeproj/project.xcworkspace/xcuserdata/lobster.xcuserdatad/UserInterfaceState.xcuserstate
4 |
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/xcuserdata/lobster.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/project.xcworkspace/xcuserdata/lobster.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lobster-King/SmartBlock/HEAD/SmartBlock.xcodeproj/project.xcworkspace/xcuserdata/lobster.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/project.xcworkspace/xcuserdata/lobster.xcuserdatad/IDEFindNavigatorScopes.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SmartBlock/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SmartBlock/BaseView.h:
--------------------------------------------------------------------------------
1 | //
2 | // BaseView.h
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface BaseView : UIView
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SmartBlock/ThridView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ThridView.h
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface ThridView : UIView
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/SmartBlock/SecondView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SecondView.h
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface SecondView : UIView
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/SmartBlock/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. 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 |
--------------------------------------------------------------------------------
/SmartBlock/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. 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 |
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/xcuserdata/lobster.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SmartBlock.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | BA73255022240C44000A1B5E
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SmartBlock/SecondView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SecondView.m
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "SecondView.h"
10 | #import "ThridView.h"
11 |
12 | @implementation SecondView
13 |
14 | - (id)initWithFrame:(CGRect)frame {
15 | if (self = [super initWithFrame:frame]) {
16 | self.backgroundColor = [UIColor greenColor];
17 | [self setUpSubviews];
18 | }
19 | return self;
20 | }
21 |
22 | - (void)setUpSubviews {
23 | ThridView *view = [[ThridView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
24 | view.center = self.center;
25 | [self addSubview:view];
26 | }
27 | /*
28 | // Only override drawRect: if you perform custom drawing.
29 | // An empty implementation adversely affects performance during animation.
30 | - (void)drawRect:(CGRect)rect {
31 | // Drawing code
32 | }
33 | */
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SmartBlock/BaseView.m:
--------------------------------------------------------------------------------
1 | //
2 | // BaseView.m
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "BaseView.h"
10 | #import "SecondView.h"
11 | #import "NSObject+SmartBlock.h"
12 |
13 | @implementation BaseView
14 |
15 | - (id)initWithFrame:(CGRect)frame {
16 | if (self = [super initWithFrame:frame]) {
17 | self.backgroundColor = [UIColor redColor];
18 | [self setUpSubviews];
19 | }
20 | return self;
21 | }
22 |
23 | - (void)setUpSubviews {
24 | SecondView *view = [[SecondView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
25 | view.center = self.center;
26 | [self addSubview:view];
27 |
28 | [self observeCallBackUsingKey:@"BaseViewCallBack" callBack:^(){
29 |
30 | }];
31 | }
32 |
33 | - (void)dealloc {
34 | NSLog(@"%s",__func__);
35 | }
36 |
37 | /*
38 | // Only override drawRect: if you perform custom drawing.
39 | // An empty implementation adversely affects performance during animation.
40 | - (void)drawRect:(CGRect)rect {
41 | // Drawing code
42 | }
43 | */
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/SmartBlock/ThridView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ThridView.m
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "ThridView.h"
10 | #import "NSObject+SmartBlock.h"
11 |
12 | @implementation ThridView
13 |
14 | - (id)initWithFrame:(CGRect)frame {
15 | if (self = [super initWithFrame:frame]) {
16 | self.backgroundColor = [UIColor yellowColor];
17 | [self setUpSubviews];
18 | }
19 | return self;
20 | }
21 |
22 | - (void)setUpSubviews {
23 | UILabel *text = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 80)];
24 | [text setFont:[UIFont systemFontOfSize:13]];
25 | [text setNumberOfLines:0];
26 | [text setText:@"点我!然后我穿越山和大海把值传给contrller~~~"];
27 | [self addSubview:text];
28 |
29 | text.center = self.center;
30 |
31 | }
32 |
33 | /*
34 | // Only override drawRect: if you perform custom drawing.
35 | // An empty implementation adversely affects performance during animation.
36 | - (void)drawRect:(CGRect)rect {
37 | // Drawing code
38 | }
39 | */
40 |
41 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
42 | /*改变controller view的背景色,跨多个view回调*/
43 | [self callBackUsingKey:@"touchCallBack",@"msg1",@"msg2",nil];
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/SmartBlock/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/SmartBlock/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 |
--------------------------------------------------------------------------------
/SmartBlock/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 |
--------------------------------------------------------------------------------
/SmartBlock/SmartBlock/NSObject+SmartBlock.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+SmartBlock.h
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | 使用场景:
13 | 1.跨多个界面回调,例如:ViewA -> ViewB -> ViewC 点击ViewC 回调给ViewA或者ViewA所在的controller。(解决多级回调等繁琐问题)
14 | 2.轻量级的通知模式解决方案。
15 |
16 | 使用方式:
17 | 1.引入该分类头文件。
18 | 2.调用observeCallBackUsingKey方法,传入key和callBack block。
19 | 3.在需要处理回调的地方调用callBackUsingKey方法,传入key。
20 |
21 | 注意事项:
22 | 1.提供BlockDestructionDefault和BlockDestructionBlockInvoked两种模式。
23 | 2.block入参个数与调用时的参数个数确保一致,否则会丢弃block的执行。
24 | 3.谨慎使用option BlockDestructionBlockInvoked
25 |
26 | 与通知对比:
27 | 1.使用通知忘记dealloc移除观察者在iOS9之前会出现崩溃。
28 | 2.发送通知和接收通知的处理是同步的。
29 | 3.如果要实现发送通知和接收通知在不同线程,系统原生通知实现比较复杂。
30 |
31 | TODO List:
32 | 1.多线程安全问题。
33 | 2.宿主对象清理策略。
34 | 3.性能优化。
35 | */
36 |
37 | NS_ASSUME_NONNULL_BEGIN
38 |
39 | typedef NS_OPTIONS(NSUInteger, BlockDestructionOption) {
40 | BlockDestructionDefault = 0,/*当前object,即self释放后进行block清理*/
41 | BlockDestructionBlockInvoked = 1,/*block调用后即清理*/
42 | };
43 |
44 | typedef NS_OPTIONS(NSUInteger, BlockRunModeOption) {
45 | BlockRunModeDefault = 0,/*执行block线程和触发callBackUsingKey线程一致*/
46 | BlockRunModeOnObserverThread = 1,/*执行block线程和注册observeCallBackUsingKey线程一致*/
47 | };
48 |
49 | @interface NSObject (SmartBlock)
50 |
51 | - (void)observeCallBackUsingKey:(NSString *)key callBack:(id)block;
52 | - (void)observeCallBackUsingKey:(NSString *)key callBack:(id)block destructionOption:(BlockDestructionOption)option;
53 | - (void)observeCallBackUsingKey:(NSString *)key callBack:(id)block destructionOption:(BlockDestructionOption)option blockRunModeOption:(BlockRunModeOption)runMode;
54 |
55 | - (void)callBackUsingKey:(NSString *)key,...NS_REQUIRES_NIL_TERMINATION;
56 |
57 | @end
58 |
59 | NS_ASSUME_NONNULL_END
60 |
--------------------------------------------------------------------------------
/SmartBlock/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 | }
--------------------------------------------------------------------------------
/SmartBlock/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "BaseView.h"
11 | #import "NSObject+SmartBlock.h"
12 |
13 | @interface ViewController ()
14 |
15 | @property (nonatomic, strong) BaseView *baseView;
16 |
17 | @end
18 |
19 | @implementation ViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 |
24 | self.baseView = [[BaseView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
25 | self.baseView.center = self.view.center;
26 | [self.view addSubview:self.baseView];
27 |
28 | NSString *address = [NSString stringWithFormat:@"%p",self.baseView];
29 | NSString *retrievedObject;
30 | sscanf([address cStringUsingEncoding:NSUTF8StringEncoding], "%p", &retrievedObject);
31 |
32 |
33 | __weak typeof(self)weakSelf = self;
34 | [self observeCallBackUsingKey:@"touchCallBack" callBack:^(NSString *msg,NSString *second) {
35 | NSLog(@"%s",__func__);
36 | weakSelf.view.backgroundColor = [UIColor orangeColor];
37 | } destructionOption:BlockDestructionDefault];
38 | //
39 | // [NSThread detachNewThreadSelector:@selector(addObserver) toTarget:self withObject:nil];
40 | // NSLog(@"子线程中注册Block");
41 |
42 | }
43 |
44 | - (void)addObserver {
45 | NSLog(@"注册block线程:%@",[NSThread currentThread]);
46 | __weak typeof(self)weakSelf = self;
47 | [self observeCallBackUsingKey:@"touchCallBack" callBack:^(NSString *msg) {
48 | NSLog(@"block执行线程:%@",[NSThread currentThread]);
49 | dispatch_async(dispatch_get_main_queue(), ^{
50 | weakSelf.view.backgroundColor = [UIColor orangeColor];
51 | });
52 | } destructionOption:BlockDestructionDefault blockRunModeOption:BlockRunModeOnObserverThread];
53 | NSLog(@"阻塞当前线程");
54 | }
55 |
56 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
57 |
58 | }
59 |
60 | - (void)testObjc:(NSString *)obj {
61 |
62 | }
63 |
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SmartBlock
2 |
3 | ## 使用场景:
4 | * 跨多个界面回调,例如:ViewA -> ViewB -> ViewC 点击ViewC 回调给ViewA或者ViewA所在的controller。(解决多级回调等繁琐问题)
5 | * 轻量级的通知模式替代方案。
6 |
7 | ## Demo演示:
8 |
9 | 
10 |
11 | ## 使用方式:
12 | * 引入该分类头文件。
13 | * 调用observeCallBackUsingKey方法,传入key和callBack block。
14 | * 在需要处理回调的地方调用callBackUsingKey方法,传入key。
15 |
16 | ### 跨界面传值
17 |
18 | ```bash
19 | /*注册*/
20 | __weak typeof(self)weakSelf = self;
21 | [self observeCallBackUsingKey:@"touchCallBack" callBack:^(NSString *msg) {
22 | NSLog(@"%s",__func__);
23 | weakSelf.view.backgroundColor = [UIColor orangeColor];
24 | } destructionOption:BlockDestructionDefault];
25 | /*发送*/
26 | [self callBackUsingKey:@"touchCallBack",@"msg",nil];
27 | ```
28 |
29 | ### Block执行线程和注册线程一致
30 |
31 | ```bash
32 | /*注册*/
33 | [NSThread detachNewThreadSelector:@selector(addObserver) toTarget:self withObject:nil];
34 |
35 | - (void)addObserver {
36 | NSLog(@"注册block线程:%@",[NSThread currentThread]);
37 | __weak typeof(self)weakSelf = self;
38 | [self observeCallBackUsingKey:@"touchCallBack" callBack:^(NSString *msg) {
39 | NSLog(@"block执行线程:%@",[NSThread currentThread]);
40 | dispatch_async(dispatch_get_main_queue(), ^{
41 | weakSelf.view.backgroundColor = [UIColor orangeColor];
42 | });
43 | } destructionOption:BlockDestructionDefault blockRunModeOption:BlockRunModeOnObserverThread];
44 | }
45 | /*发送*/
46 | [self callBackUsingKey:@"touchCallBack",@"msg",nil];
47 | ```
48 |
49 | ## 注意事项:
50 | * 提供BlockDestructionDefault和BlockDestructionBlockInvoked两种模式。
51 | * block入参个数与调用时的参数个数确保一致,否则会丢弃block的执行。
52 | * 谨慎使用option BlockDestructionBlockInvoked
53 |
54 | ## 与原生通知对比:
55 | * 使用通知忘记dealloc移除观察者在iOS9之前因为__unsafed_unretained会出现野指针崩溃。
56 | * 发送通知和接收通知的处理是同步的。
57 | * 如果要实现发送通知和接收通知在不同线程,系统原生通知实现比较复杂。
58 | * 系统原生通知不支持传不定参数,不够灵活。
59 |
60 | ## TODO List:
61 | * 多线程安全问题。
62 | * 性能优化。
63 |
64 | ## Have a problem?
65 |
66 | You can contact me in the following ways
67 |
68 | * PRs or Issues.
69 | * Email :[zhiwei.geek@gmail.com](mailto:zhiwei.geek@gmail.com)
70 |
71 |
--------------------------------------------------------------------------------
/SmartBlock/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // 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.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // 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.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // 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.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // 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.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/xcuserdata/lobster.xcuserdatad/xcschemes/SmartBlock.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/SmartBlock/SmartBlock/NSObject+SmartBlock.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+SmartBlock.m
3 | // SmartBlock
4 | //
5 | // Created by lobster on 2019/2/25.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "NSObject+SmartBlock.h"
10 | #import
11 |
12 | static NSString *kBlockDefaultKey = @"kBlockDefaultKey";
13 |
14 | #pragma mark--BlockInfo(存储回调等信息)
15 | @interface BlockInfo : NSObject
16 |
17 | @property (nonatomic, copy) NSString *key;
18 | @property (nonatomic, copy) NSString *address;
19 | @property (nonatomic, copy) id block;
20 | @property (nonatomic, assign) BlockDestructionOption option;
21 | @property (nonatomic, strong) NSThread *blockThread;
22 | @property (nonatomic, assign) BOOL finished;
23 |
24 | @end
25 |
26 | @implementation BlockInfo
27 |
28 | + (id)initBlockInfoUsingBlock:(id)block option:(BlockDestructionOption)option {
29 | NSParameterAssert(block);
30 | return [BlockInfo initBlockInfoUsingKey:kBlockDefaultKey block:block option:option];
31 | }
32 |
33 | + (id)initBlockInfoUsingKey:(NSString *)key block:(id)block option:(BlockDestructionOption)option {
34 | return [BlockInfo initBlockInfoUsingKey:key block:block thread:[NSThread currentThread] option:option];
35 | }
36 |
37 | + (id)initBlockInfoUsingKey:(NSString *)key block:(id)block thread:(NSThread *)currentThread option:(BlockDestructionOption)option {
38 | BlockInfo *info = [[BlockInfo alloc]init];
39 | info.key = key;
40 | info.block = block;
41 | info.option = option;
42 | info.blockThread= currentThread;
43 | return info;
44 | }
45 |
46 | @end
47 |
48 | struct __Block_literal_ {
49 | void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
50 | int flags;
51 | int reserved;
52 | void (*invoke)(void *, ...);
53 | struct Block_descriptor_1 {
54 | unsigned long int reserved; // NULL
55 | unsigned long int size; // sizeof(struct Block_literal_1)
56 | // optional helper functions
57 | // void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
58 | // void (*dispose_helper)(void *src); // IFF (1<<25)
59 | // required ABI.2010.3.16
60 | // const char *signature; // IFF (1<<30)
61 | void* rest[1];
62 | } *descriptor;
63 | // imported variables
64 | };
65 |
66 | static const char *__BlockSignature__(id blockRef)
67 | {
68 | struct __Block_literal_ *block = (__bridge void *)blockRef;
69 | struct Block_descriptor_1 *descriptor = block->descriptor;
70 | int copyDisposeFlag = 1 << 25;
71 | int signatureFlag = 1 << 30;
72 | assert(block->flags & signatureFlag);
73 | int offset = 0;
74 | if(block->flags & copyDisposeFlag)
75 | offset += 2;
76 | return (const char*)(descriptor->rest[offset]);
77 | }
78 |
79 | static NSString *kAssociatedObjectKey = @"smartBlockKey";
80 | static BOOL initialized = NO;
81 | static NSMutableDictionary *globalMap = nil;
82 | static NSMutableArray *argumentsRef = nil;
83 | static NSMutableArray *destructionInvokedArray = nil;
84 |
85 | #pragma mark--宿主对象观察者(宿主对象释放后,在观察者dealloc方法中把block清理掉)
86 | @interface ObserverWatcher : NSObject
87 |
88 | @property (nonatomic, copy) NSString *hostAddress;
89 |
90 | @end
91 |
92 | @implementation ObserverWatcher
93 |
94 | - (void)dealloc {
95 | /*当前宿主对象释放之后,其关联对象随之被清理,在此方法内把全局的Block清理掉*/
96 | [self destroyBlocks];
97 | }
98 |
99 | - (void)destroyBlocks {
100 | #warning 需要考虑多线程问题
101 | for (NSMutableArray *observers in [globalMap allValues]) {
102 | NSMutableArray *blocksTemp = [NSMutableArray array];
103 | for (BlockInfo *blockInfo in observers) {
104 | if ([blockInfo.address isEqualToString:self.hostAddress]) {
105 | [blocksTemp addObject:blockInfo];
106 | }
107 | }
108 | [observers removeObjectsInArray:blocksTemp];
109 | }
110 | }
111 |
112 | @end
113 |
114 | @implementation NSObject (SmartBlock)
115 |
116 | - (void)observeCallBackUsingKey:(NSString *)key callBack:(id)block {
117 | [self observeCallBackUsingKey:key callBack:block destructionOption:BlockDestructionDefault];
118 | }
119 |
120 | - (void)observeCallBackUsingKey:(NSString *)key callBack:(id)block destructionOption:(BlockDestructionOption)option {
121 | [self observeCallBackUsingKey:key callBack:block destructionOption:option blockRunModeOption:BlockRunModeDefault];
122 | }
123 |
124 | - (void)observeCallBackUsingKey:(NSString *)key callBack:(id)block destructionOption:(BlockDestructionOption)option blockRunModeOption:(BlockRunModeOption)runMode {
125 | NSParameterAssert(key);
126 | NSParameterAssert(block);
127 |
128 | if (!initialized) {
129 | globalMap = [NSMutableDictionary new];
130 | initialized = YES;
131 | }
132 |
133 | #warning fix me!!!可能存在通过内存地址访问对象,可能会因对象释放而出现bad_access导致程序直接挂掉,目前只是内存地址比对,没有访问内存指针,所以暂时不会存在问题。
134 | NSString *address = [NSString stringWithFormat:@"%p",self];
135 |
136 | id associatedObj = objc_getAssociatedObject(self, &kAssociatedObjectKey);
137 | if (!associatedObj) {
138 | ObserverWatcher *watcher = [ObserverWatcher new];
139 | watcher.hostAddress = address;
140 | objc_setAssociatedObject(self, &kAssociatedObjectKey, watcher, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
141 | }
142 |
143 | NSMutableArray *blocks = [globalMap objectForKey:key];
144 | if (!blocks) {
145 | blocks = [NSMutableArray array];
146 | }
147 |
148 | BlockInfo *info = [BlockInfo initBlockInfoUsingKey:key block:block option:option];
149 | info.address = address;
150 | [blocks addObject:info];
151 |
152 | [globalMap setObject:blocks forKey:key];
153 |
154 | if ([[NSThread currentThread] isMainThread]) {
155 | /*主线程单独处理,主线程不需要开启runloop,默认就是开启的*/
156 | info.blockThread = nil;
157 | } else if (runMode == BlockRunModeOnObserverThread) {
158 | /*子线程并且要求block执行在注册blcok线程,需要开启当前线程的runloop*/
159 | [self startRunLoopUsingBlockInfo:info];
160 | }
161 | }
162 |
163 | - (void)startRunLoopUsingBlockInfo:(BlockInfo *)info {
164 | [[NSRunLoop currentRunLoop] addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
165 | while (!info.finished) {
166 | [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
167 | }
168 | NSLog(@"over!!!");
169 | }
170 |
171 | - (void)callBackUsingKey:(NSString *)key,...NS_REQUIRES_NIL_TERMINATION {
172 | NSParameterAssert(key);
173 |
174 | NSMutableArray *blocks = [globalMap objectForKey:key];
175 |
176 | if (!blocks.count) {
177 | NSLog(@"未找到与Key:%@匹配的回调!!!",key);
178 | return;
179 | }
180 |
181 | va_list args;
182 | va_start(args, key);
183 | [self invokeMsgWithKey:key arguments:args];
184 | va_end(args);
185 | }
186 |
187 | - (void)invokeMsgWithKey:(NSString *)key arguments:(va_list)args {
188 | NSMutableArray *argsArray = [NSMutableArray array];
189 | id param = nil;
190 | while ((param = va_arg(args, id))) {
191 | [argsArray addObject:param];
192 | }
193 | [self invokeBlockUsingKey:key arguments:argsArray];
194 | }
195 |
196 | - (void)invokeBlockUsingKey:(NSString *)key arguments:(NSMutableArray *)args {
197 | argumentsRef = args;
198 | NSMutableArray *blocks = [globalMap objectForKey:key];
199 | destructionInvokedArray = [NSMutableArray array];
200 |
201 | for (id block in blocks) {
202 | BlockInfo *info = (BlockInfo *)block;
203 | if (info.blockThread == nil) {
204 | [self performSelector:@selector(invokeBlockOnDefaultThreadWithInfo:) withObject:info];
205 | }
206 |
207 | if (![info.blockThread isMainThread]) {
208 | [self performSelector:@selector(invokeBlockOnObserverThreadWithInfo:) onThread:info.blockThread withObject:info waitUntilDone:NO];
209 | }
210 |
211 | if (info.option == BlockDestructionBlockInvoked) {
212 | [destructionInvokedArray addObject:info];
213 | }
214 | }
215 |
216 | [self disposeBlockInfos:blocks];
217 | }
218 |
219 | - (void)invokeBlockOnDefaultThreadWithInfo:(BlockInfo *)blockInfo {
220 | NSMutableArray *args = argumentsRef;
221 | id block = blockInfo.block;
222 | NSMethodSignature *blockSignature = [NSMethodSignature signatureWithObjCTypes:__BlockSignature__(block)];
223 |
224 | if (argumentsRef.count != ([blockSignature numberOfArguments] - 1)) {
225 | /*参数个数不符合,直接丢弃本次block调用*/
226 | NSLog(@"Smart_Block_参数个数不符!");
227 | return;
228 | }
229 |
230 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:blockSignature];
231 | NSInteger index = 1;
232 | for (id arg in args) {
233 | #pragma clang diagnostic push
234 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
235 | [invocation setArgument:&arg atIndex:index];
236 | #pragma clang diagnostic pop
237 | index++;
238 | }
239 | [invocation invokeWithTarget:block];
240 | }
241 |
242 | - (void)invokeBlockOnObserverThreadWithInfo:(BlockInfo *)blockInfo {
243 | NSMutableArray *args = argumentsRef;
244 | id block = blockInfo.block;
245 | NSMethodSignature *blockSignature = [NSMethodSignature signatureWithObjCTypes:__BlockSignature__(block)];
246 |
247 | if (argumentsRef.count != ([blockSignature numberOfArguments] - 1)) {
248 | /*参数个数不符合,直接丢弃本次block调用*/
249 | NSLog(@"Smart_Block_参数个数不符!");
250 | return;
251 | }
252 |
253 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:blockSignature];
254 | NSInteger index = 1;
255 | for (id arg in args) {
256 | #pragma clang diagnostic push
257 | #pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
258 | [invocation setArgument:&arg atIndex:index];
259 | #pragma clang diagnostic pop
260 | index++;
261 | }
262 | [invocation invokeWithTarget:block];
263 |
264 | blockInfo.finished = YES;
265 | }
266 |
267 | - (void)disposeBlockInfos:(NSMutableArray *)blocks{
268 | [blocks removeObjectsInArray:destructionInvokedArray];
269 | }
270 |
271 | @end
272 |
--------------------------------------------------------------------------------
/SmartBlock.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | BA0D18ED22252A0E00C5577C /* NSObject+SmartBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = BA0D18EB22252A0E00C5577C /* NSObject+SmartBlock.m */; };
11 | BA73255622240C44000A1B5E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BA73255522240C44000A1B5E /* AppDelegate.m */; };
12 | BA73255922240C44000A1B5E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BA73255822240C44000A1B5E /* ViewController.m */; };
13 | BA73255C22240C44000A1B5E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BA73255A22240C44000A1B5E /* Main.storyboard */; };
14 | BA73255E22240C45000A1B5E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BA73255D22240C45000A1B5E /* Assets.xcassets */; };
15 | BA73256122240C46000A1B5E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BA73255F22240C46000A1B5E /* LaunchScreen.storyboard */; };
16 | BA73256422240C46000A1B5E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BA73256322240C46000A1B5E /* main.m */; };
17 | BA73256C22240C68000A1B5E /* BaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = BA73256B22240C68000A1B5E /* BaseView.m */; };
18 | BA73256F22240C75000A1B5E /* SecondView.m in Sources */ = {isa = PBXBuildFile; fileRef = BA73256E22240C75000A1B5E /* SecondView.m */; };
19 | BA73257222240C83000A1B5E /* ThridView.m in Sources */ = {isa = PBXBuildFile; fileRef = BA73257122240C83000A1B5E /* ThridView.m */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | BA0D18EB22252A0E00C5577C /* NSObject+SmartBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SmartBlock.m"; sourceTree = ""; };
24 | BA0D18EC22252A0E00C5577C /* NSObject+SmartBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SmartBlock.h"; sourceTree = ""; };
25 | BA73255122240C44000A1B5E /* SmartBlock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SmartBlock.app; sourceTree = BUILT_PRODUCTS_DIR; };
26 | BA73255422240C44000A1B5E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
27 | BA73255522240C44000A1B5E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
28 | BA73255722240C44000A1B5E /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
29 | BA73255822240C44000A1B5E /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
30 | BA73255B22240C44000A1B5E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
31 | BA73255D22240C45000A1B5E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
32 | BA73256022240C46000A1B5E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
33 | BA73256222240C46000A1B5E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | BA73256322240C46000A1B5E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
35 | BA73256A22240C68000A1B5E /* BaseView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseView.h; sourceTree = ""; };
36 | BA73256B22240C68000A1B5E /* BaseView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BaseView.m; sourceTree = ""; };
37 | BA73256D22240C75000A1B5E /* SecondView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecondView.h; sourceTree = ""; };
38 | BA73256E22240C75000A1B5E /* SecondView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecondView.m; sourceTree = ""; };
39 | BA73257022240C83000A1B5E /* ThridView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThridView.h; sourceTree = ""; };
40 | BA73257122240C83000A1B5E /* ThridView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ThridView.m; sourceTree = ""; };
41 | /* End PBXFileReference section */
42 |
43 | /* Begin PBXFrameworksBuildPhase section */
44 | BA73254E22240C44000A1B5E /* Frameworks */ = {
45 | isa = PBXFrameworksBuildPhase;
46 | buildActionMask = 2147483647;
47 | files = (
48 | );
49 | runOnlyForDeploymentPostprocessing = 0;
50 | };
51 | /* End PBXFrameworksBuildPhase section */
52 |
53 | /* Begin PBXGroup section */
54 | BA0D18EA22252A0E00C5577C /* SmartBlock */ = {
55 | isa = PBXGroup;
56 | children = (
57 | BA0D18EC22252A0E00C5577C /* NSObject+SmartBlock.h */,
58 | BA0D18EB22252A0E00C5577C /* NSObject+SmartBlock.m */,
59 | );
60 | path = SmartBlock;
61 | sourceTree = "";
62 | };
63 | BA73254822240C44000A1B5E = {
64 | isa = PBXGroup;
65 | children = (
66 | BA73255322240C44000A1B5E /* SmartBlock */,
67 | BA73255222240C44000A1B5E /* Products */,
68 | );
69 | sourceTree = "";
70 | };
71 | BA73255222240C44000A1B5E /* Products */ = {
72 | isa = PBXGroup;
73 | children = (
74 | BA73255122240C44000A1B5E /* SmartBlock.app */,
75 | );
76 | name = Products;
77 | sourceTree = "";
78 | };
79 | BA73255322240C44000A1B5E /* SmartBlock */ = {
80 | isa = PBXGroup;
81 | children = (
82 | BA0D18EA22252A0E00C5577C /* SmartBlock */,
83 | BA73255422240C44000A1B5E /* AppDelegate.h */,
84 | BA73255522240C44000A1B5E /* AppDelegate.m */,
85 | BA73255722240C44000A1B5E /* ViewController.h */,
86 | BA73255822240C44000A1B5E /* ViewController.m */,
87 | BA73255A22240C44000A1B5E /* Main.storyboard */,
88 | BA73255D22240C45000A1B5E /* Assets.xcassets */,
89 | BA73255F22240C46000A1B5E /* LaunchScreen.storyboard */,
90 | BA73256222240C46000A1B5E /* Info.plist */,
91 | BA73256322240C46000A1B5E /* main.m */,
92 | BA73256A22240C68000A1B5E /* BaseView.h */,
93 | BA73256B22240C68000A1B5E /* BaseView.m */,
94 | BA73256D22240C75000A1B5E /* SecondView.h */,
95 | BA73256E22240C75000A1B5E /* SecondView.m */,
96 | BA73257022240C83000A1B5E /* ThridView.h */,
97 | BA73257122240C83000A1B5E /* ThridView.m */,
98 | );
99 | path = SmartBlock;
100 | sourceTree = "";
101 | };
102 | /* End PBXGroup section */
103 |
104 | /* Begin PBXNativeTarget section */
105 | BA73255022240C44000A1B5E /* SmartBlock */ = {
106 | isa = PBXNativeTarget;
107 | buildConfigurationList = BA73256722240C46000A1B5E /* Build configuration list for PBXNativeTarget "SmartBlock" */;
108 | buildPhases = (
109 | BA73254D22240C44000A1B5E /* Sources */,
110 | BA73254E22240C44000A1B5E /* Frameworks */,
111 | BA73254F22240C44000A1B5E /* Resources */,
112 | );
113 | buildRules = (
114 | );
115 | dependencies = (
116 | );
117 | name = SmartBlock;
118 | productName = SendVauleWithAssi;
119 | productReference = BA73255122240C44000A1B5E /* SmartBlock.app */;
120 | productType = "com.apple.product-type.application";
121 | };
122 | /* End PBXNativeTarget section */
123 |
124 | /* Begin PBXProject section */
125 | BA73254922240C44000A1B5E /* Project object */ = {
126 | isa = PBXProject;
127 | attributes = {
128 | LastUpgradeCheck = 1000;
129 | ORGANIZATIONNAME = lobster;
130 | TargetAttributes = {
131 | BA73255022240C44000A1B5E = {
132 | CreatedOnToolsVersion = 10.0;
133 | };
134 | };
135 | };
136 | buildConfigurationList = BA73254C22240C44000A1B5E /* Build configuration list for PBXProject "SmartBlock" */;
137 | compatibilityVersion = "Xcode 9.3";
138 | developmentRegion = en;
139 | hasScannedForEncodings = 0;
140 | knownRegions = (
141 | en,
142 | Base,
143 | );
144 | mainGroup = BA73254822240C44000A1B5E;
145 | productRefGroup = BA73255222240C44000A1B5E /* Products */;
146 | projectDirPath = "";
147 | projectRoot = "";
148 | targets = (
149 | BA73255022240C44000A1B5E /* SmartBlock */,
150 | );
151 | };
152 | /* End PBXProject section */
153 |
154 | /* Begin PBXResourcesBuildPhase section */
155 | BA73254F22240C44000A1B5E /* Resources */ = {
156 | isa = PBXResourcesBuildPhase;
157 | buildActionMask = 2147483647;
158 | files = (
159 | BA73256122240C46000A1B5E /* LaunchScreen.storyboard in Resources */,
160 | BA73255E22240C45000A1B5E /* Assets.xcassets in Resources */,
161 | BA73255C22240C44000A1B5E /* Main.storyboard in Resources */,
162 | );
163 | runOnlyForDeploymentPostprocessing = 0;
164 | };
165 | /* End PBXResourcesBuildPhase section */
166 |
167 | /* Begin PBXSourcesBuildPhase section */
168 | BA73254D22240C44000A1B5E /* Sources */ = {
169 | isa = PBXSourcesBuildPhase;
170 | buildActionMask = 2147483647;
171 | files = (
172 | BA73255922240C44000A1B5E /* ViewController.m in Sources */,
173 | BA73256422240C46000A1B5E /* main.m in Sources */,
174 | BA0D18ED22252A0E00C5577C /* NSObject+SmartBlock.m in Sources */,
175 | BA73257222240C83000A1B5E /* ThridView.m in Sources */,
176 | BA73255622240C44000A1B5E /* AppDelegate.m in Sources */,
177 | BA73256F22240C75000A1B5E /* SecondView.m in Sources */,
178 | BA73256C22240C68000A1B5E /* BaseView.m in Sources */,
179 | );
180 | runOnlyForDeploymentPostprocessing = 0;
181 | };
182 | /* End PBXSourcesBuildPhase section */
183 |
184 | /* Begin PBXVariantGroup section */
185 | BA73255A22240C44000A1B5E /* Main.storyboard */ = {
186 | isa = PBXVariantGroup;
187 | children = (
188 | BA73255B22240C44000A1B5E /* Base */,
189 | );
190 | name = Main.storyboard;
191 | sourceTree = "";
192 | };
193 | BA73255F22240C46000A1B5E /* LaunchScreen.storyboard */ = {
194 | isa = PBXVariantGroup;
195 | children = (
196 | BA73256022240C46000A1B5E /* Base */,
197 | );
198 | name = LaunchScreen.storyboard;
199 | sourceTree = "";
200 | };
201 | /* End PBXVariantGroup section */
202 |
203 | /* Begin XCBuildConfiguration section */
204 | BA73256522240C46000A1B5E /* Debug */ = {
205 | isa = XCBuildConfiguration;
206 | buildSettings = {
207 | ALWAYS_SEARCH_USER_PATHS = NO;
208 | CLANG_ANALYZER_NONNULL = YES;
209 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
210 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
211 | CLANG_CXX_LIBRARY = "libc++";
212 | CLANG_ENABLE_MODULES = YES;
213 | CLANG_ENABLE_OBJC_ARC = YES;
214 | CLANG_ENABLE_OBJC_WEAK = YES;
215 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
216 | CLANG_WARN_BOOL_CONVERSION = YES;
217 | CLANG_WARN_COMMA = YES;
218 | CLANG_WARN_CONSTANT_CONVERSION = YES;
219 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
220 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
221 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
222 | CLANG_WARN_EMPTY_BODY = YES;
223 | CLANG_WARN_ENUM_CONVERSION = YES;
224 | CLANG_WARN_INFINITE_RECURSION = YES;
225 | CLANG_WARN_INT_CONVERSION = YES;
226 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
227 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
228 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
229 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
230 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
231 | CLANG_WARN_STRICT_PROTOTYPES = YES;
232 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
233 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
234 | CLANG_WARN_UNREACHABLE_CODE = YES;
235 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
236 | CODE_SIGN_IDENTITY = "iPhone Developer";
237 | COPY_PHASE_STRIP = NO;
238 | DEBUG_INFORMATION_FORMAT = dwarf;
239 | ENABLE_STRICT_OBJC_MSGSEND = YES;
240 | ENABLE_TESTABILITY = YES;
241 | GCC_C_LANGUAGE_STANDARD = gnu11;
242 | GCC_DYNAMIC_NO_PIC = NO;
243 | GCC_NO_COMMON_BLOCKS = YES;
244 | GCC_OPTIMIZATION_LEVEL = 0;
245 | GCC_PREPROCESSOR_DEFINITIONS = (
246 | "DEBUG=1",
247 | "$(inherited)",
248 | );
249 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
250 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
251 | GCC_WARN_UNDECLARED_SELECTOR = YES;
252 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
253 | GCC_WARN_UNUSED_FUNCTION = YES;
254 | GCC_WARN_UNUSED_VARIABLE = YES;
255 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
256 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
257 | MTL_FAST_MATH = YES;
258 | ONLY_ACTIVE_ARCH = YES;
259 | SDKROOT = iphoneos;
260 | };
261 | name = Debug;
262 | };
263 | BA73256622240C46000A1B5E /* Release */ = {
264 | isa = XCBuildConfiguration;
265 | buildSettings = {
266 | ALWAYS_SEARCH_USER_PATHS = NO;
267 | CLANG_ANALYZER_NONNULL = YES;
268 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
269 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
270 | CLANG_CXX_LIBRARY = "libc++";
271 | CLANG_ENABLE_MODULES = YES;
272 | CLANG_ENABLE_OBJC_ARC = YES;
273 | CLANG_ENABLE_OBJC_WEAK = YES;
274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_COMMA = YES;
277 | CLANG_WARN_CONSTANT_CONVERSION = YES;
278 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
279 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
280 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
281 | CLANG_WARN_EMPTY_BODY = YES;
282 | CLANG_WARN_ENUM_CONVERSION = YES;
283 | CLANG_WARN_INFINITE_RECURSION = YES;
284 | CLANG_WARN_INT_CONVERSION = YES;
285 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
286 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
287 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
288 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
289 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
290 | CLANG_WARN_STRICT_PROTOTYPES = YES;
291 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
292 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
293 | CLANG_WARN_UNREACHABLE_CODE = YES;
294 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
295 | CODE_SIGN_IDENTITY = "iPhone Developer";
296 | COPY_PHASE_STRIP = NO;
297 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
298 | ENABLE_NS_ASSERTIONS = NO;
299 | ENABLE_STRICT_OBJC_MSGSEND = YES;
300 | GCC_C_LANGUAGE_STANDARD = gnu11;
301 | GCC_NO_COMMON_BLOCKS = YES;
302 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
303 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
304 | GCC_WARN_UNDECLARED_SELECTOR = YES;
305 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
306 | GCC_WARN_UNUSED_FUNCTION = YES;
307 | GCC_WARN_UNUSED_VARIABLE = YES;
308 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
309 | MTL_ENABLE_DEBUG_INFO = NO;
310 | MTL_FAST_MATH = YES;
311 | SDKROOT = iphoneos;
312 | VALIDATE_PRODUCT = YES;
313 | };
314 | name = Release;
315 | };
316 | BA73256822240C46000A1B5E /* Debug */ = {
317 | isa = XCBuildConfiguration;
318 | buildSettings = {
319 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
320 | CODE_SIGN_STYLE = Automatic;
321 | INFOPLIST_FILE = "$(SRCROOT)/SmartBlock/Info.plist";
322 | LD_RUNPATH_SEARCH_PATHS = (
323 | "$(inherited)",
324 | "@executable_path/Frameworks",
325 | );
326 | PRODUCT_BUNDLE_IDENTIFIER = com.lobster.SmartBlock;
327 | PRODUCT_NAME = "$(TARGET_NAME)";
328 | TARGETED_DEVICE_FAMILY = "1,2";
329 | };
330 | name = Debug;
331 | };
332 | BA73256922240C46000A1B5E /* Release */ = {
333 | isa = XCBuildConfiguration;
334 | buildSettings = {
335 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
336 | CODE_SIGN_STYLE = Automatic;
337 | INFOPLIST_FILE = "$(SRCROOT)/SmartBlock/Info.plist";
338 | LD_RUNPATH_SEARCH_PATHS = (
339 | "$(inherited)",
340 | "@executable_path/Frameworks",
341 | );
342 | PRODUCT_BUNDLE_IDENTIFIER = com.lobster.SmartBlock;
343 | PRODUCT_NAME = "$(TARGET_NAME)";
344 | TARGETED_DEVICE_FAMILY = "1,2";
345 | };
346 | name = Release;
347 | };
348 | /* End XCBuildConfiguration section */
349 |
350 | /* Begin XCConfigurationList section */
351 | BA73254C22240C44000A1B5E /* Build configuration list for PBXProject "SmartBlock" */ = {
352 | isa = XCConfigurationList;
353 | buildConfigurations = (
354 | BA73256522240C46000A1B5E /* Debug */,
355 | BA73256622240C46000A1B5E /* Release */,
356 | );
357 | defaultConfigurationIsVisible = 0;
358 | defaultConfigurationName = Release;
359 | };
360 | BA73256722240C46000A1B5E /* Build configuration list for PBXNativeTarget "SmartBlock" */ = {
361 | isa = XCConfigurationList;
362 | buildConfigurations = (
363 | BA73256822240C46000A1B5E /* Debug */,
364 | BA73256922240C46000A1B5E /* Release */,
365 | );
366 | defaultConfigurationIsVisible = 0;
367 | defaultConfigurationName = Release;
368 | };
369 | /* End XCConfigurationList section */
370 | };
371 | rootObject = BA73254922240C44000A1B5E /* Project object */;
372 | }
373 |
--------------------------------------------------------------------------------