├── 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 | ![Demo gif](https://github.com/Lobster-King/SmartBlock/blob/master/SmartDemo.gif) 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 | --------------------------------------------------------------------------------