├── IQDataBindingDemo
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── ViewController.h
├── ContentModel.m
├── ContentView.h
├── AppDelegate.h
├── main.m
├── ContentModel.h
├── Info.plist
├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
├── ViewController.m
├── AppDelegate.m
└── ContentView.m
├── IQDataBinding.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ └── IQDataBindingDemo.xcscheme
└── project.pbxproj
├── IQDataBinding
├── IQDataBinding.h
├── Info.plist
├── NSObject+IQDataBinding.h
└── NSObject+IQDataBinding.m
├── LICENSE
├── IQDataBinding.podspec
├── .gitignore
└── README.md
/IQDataBindingDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/IQDataBinding.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/IQDataBinding.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/ContentModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // ContentModel.m
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "ContentModel.h"
10 |
11 | @implementation ContentModel
12 |
13 | - (void)dealloc {
14 | NSLog(@"%s",__func__);
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/ContentView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.h
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/4.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface ContentView : UIView
14 |
15 |
16 | @end
17 |
18 | NS_ASSUME_NONNULL_END
19 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/2.
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 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/2.
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 |
--------------------------------------------------------------------------------
/IQDataBinding/IQDataBinding.h:
--------------------------------------------------------------------------------
1 | //
2 | // IQDataBinding.h
3 | // IQDataBinding
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "NSObject+IQDataBinding.h"
11 |
12 | //! Project version number for IQDataBinding.
13 | FOUNDATION_EXPORT double IQDataBindingVersionNumber;
14 |
15 | //! Project version string for IQDataBinding.
16 | FOUNDATION_EXPORT const unsigned char IQDataBindingVersionString[];
17 |
18 | // In this header, you should import all the public headers of your framework using statements like #import
19 | /**
20 | TODO LIST:
21 | 1.同一view绑定多个model的情况。
22 | 2.view变动->更新viewModel。
23 | */
24 |
25 |
--------------------------------------------------------------------------------
/IQDataBinding/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 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/IQDataBinding/NSObject+IQDataBinding.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+IQDataBinding.h
3 | // IQDataBinding
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | #define update(key,...) update(IQBoxValue(key,(__VA_ARGS__)))
15 | #define IQBoxValue(key,value) autoboxing(@encode(__typeof__((value))),self,key,(value))
16 |
17 | id autoboxing(const char *type, ...);
18 |
19 | typedef void(^observerCallBack)(id changedValue);
20 |
21 | @interface NSObject (IQDataBinding)
22 |
23 | - (void)bindModel:(id)model;
24 |
25 | - (NSObject *(^)(NSString *keyPath,observerCallBack observer))observe;
26 | - (NSObject * (^)(id,...))update;
27 |
28 | @end
29 |
30 | NS_ASSUME_NONNULL_END
31 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/IQDataBinding.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint IQDataBinding.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see https://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |spec|
10 |
11 | spec.name = "IQDataBinding"
12 | spec.version = "0.0.2"
13 | spec.summary = "iOS端View和ViewModel数据绑定框架。基于KVO监听所绑定ViewModel的属性,支持链式调用。"
14 | spec.description = <<-DESC
15 | A solution for decoupling modules in iOS platform.
16 | DESC
17 | spec.homepage = "https://github.com/Lobster-King/IQDataBinding"
18 | spec.license = "MIT"
19 | spec.author = { "Lobster-King" => "zhiwei.geek@gmail.com" }
20 | spec.ios.deployment_target = '7.0'
21 | spec.source = { :git => "https://github.com/Lobster-King/IQDataBinding.git", :tag => "#{spec.version}" }
22 | spec.source_files = "IQDataBinding", "IQDataBinding/**/*.{h,m}"
23 | spec.exclude_files = "IQDataBinding/Exclude"
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/ContentModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // ContentModel.h
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @interface ContentModel : NSObject
15 |
16 | @property (nonatomic, copy) NSString *title;
17 | @property (nonatomic, copy) NSString *content;
18 | @property (nonatomic, assign) CGPoint point;
19 | @property (nonatomic, assign) CGSize size;
20 | @property (nonatomic, assign) double db;
21 | @property (nonatomic, assign) float fl;
22 | @property (nonatomic, assign) long lg;
23 | @property (nonatomic, assign) long long llg;
24 | @property (nonatomic, assign) short st;
25 | @property (nonatomic, assign) char ch;
26 | @property (nonatomic, assign) bool bl;
27 | @property (nonatomic, assign) unsigned char ucha;
28 | @property (nonatomic, assign) unsigned long ulg;
29 | @property (nonatomic, assign) unsigned int uit;
30 | @property (nonatomic, assign) unsigned long long ullg;
31 | @property (nonatomic, assign) unsigned short ust;
32 |
33 | @end
34 |
35 | NS_ASSUME_NONNULL_END
36 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | # CocoaPods
32 | #
33 | # We recommend against adding the Pods directory to your .gitignore. However
34 | # you should judge for yourself, the pros and cons are mentioned at:
35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
36 | #
37 | # Pods/
38 |
39 | # Carthage
40 | #
41 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
42 | # Carthage/Checkouts
43 |
44 | Carthage/Build
45 |
46 | # fastlane
47 | #
48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
49 | # screenshots whenever they are needed.
50 | # For more information about the recommended setup visit:
51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
52 |
53 | fastlane/report.xml
54 | fastlane/Preview.html
55 | fastlane/screenshots/**/*.png
56 | fastlane/test_output
57 |
58 | # Code Injection
59 | #
60 | # After new code Injection tools there's a generated folder /iOSInjectionProject
61 | # https://github.com/johnno1962/injectionforxcode
62 |
63 | iOSInjectionProject/
64 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/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 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/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 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/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 | }
--------------------------------------------------------------------------------
/IQDataBindingDemo/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import
11 | #import "ContentView.h"
12 | #import "ContentModel.h"
13 |
14 | @interface ViewController ()
15 |
16 | @property (nonatomic, strong) ContentView *contentView;
17 | @property (nonatomic, strong) UIButton *changeButton;
18 | @property (nonatomic, strong) ContentModel *contentModel;
19 |
20 | @end
21 |
22 | @implementation ViewController
23 |
24 | - (void)viewDidLoad {
25 | [super viewDidLoad];
26 | [self setUpSubviews];
27 | [self configData];
28 |
29 | // [self testModelDealloc];
30 | // [self testViewDealloc];
31 | }
32 |
33 | - (void)changeButtonClicked {
34 | self.contentModel.title = @"lobster";
35 | self.contentModel.content = @"654321";
36 | }
37 |
38 | - (void)setUpSubviews {
39 | self.contentView = [[ContentView alloc]initWithFrame:CGRectMake(100, 80, 200, 100)];
40 | [self.view addSubview:self.contentView];
41 | self.contentView.center = self.view.center;
42 |
43 | self.changeButton = [UIButton buttonWithType:UIButtonTypeSystem];
44 | self.changeButton.frame = CGRectMake(self.contentView.frame.origin.x, self.contentView.frame.origin.y + 100, 200, 40);
45 |
46 | [self.changeButton setTitle:@"加载默认用户名和密码" forState:UIControlStateNormal];
47 | [self.changeButton addTarget:self action:@selector(changeButtonClicked) forControlEvents:UIControlEventTouchUpInside];
48 | [self.view addSubview:self.changeButton];
49 |
50 | }
51 |
52 | - (void)configData {
53 | self.contentModel = [[ContentModel alloc]init];
54 | self.contentModel.title = @"lobster";
55 | self.contentModel.content = @"123456";
56 |
57 | /*view和viewModel之间绑定*/
58 | [self.contentView bindModel:self.contentModel];
59 |
60 | }
61 |
62 | - (void)testViewDealloc {
63 | [self.contentView removeFromSuperview];
64 | self.contentView = nil;
65 | }
66 |
67 | - (void)testModelDealloc {
68 | self.contentModel = nil;
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import
11 |
12 | @interface AppDelegate ()
13 |
14 | @end
15 |
16 | @implementation AppDelegate
17 |
18 |
19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
20 | // Override point for customization after application launch.
21 | return YES;
22 | }
23 |
24 |
25 | - (void)applicationWillResignActive:(UIApplication *)application {
26 | // 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.
27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
28 | }
29 |
30 |
31 | - (void)applicationDidEnterBackground:(UIApplication *)application {
32 | // 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.
33 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
34 | }
35 |
36 |
37 | - (void)applicationWillEnterForeground:(UIApplication *)application {
38 | // 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.
39 | }
40 |
41 |
42 | - (void)applicationDidBecomeActive:(UIApplication *)application {
43 | // 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.
44 | }
45 |
46 |
47 | - (void)applicationWillTerminate:(UIApplication *)application {
48 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
49 | }
50 |
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/IQDataBindingDemo/ContentView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.m
3 | // IQDataBindingDemo
4 | //
5 | // Created by lobster on 2019/5/4.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "ContentView.h"
10 | #import
11 |
12 | @interface ContentView ()
13 |
14 | @property (nonatomic, strong) UITextField *loginTextField;
15 | @property (nonatomic, strong) UITextField *pwdTextField;
16 |
17 | @end
18 |
19 | @implementation ContentView
20 |
21 | - (void)dealloc {
22 | NSLog(@"%s",__func__);
23 | }
24 |
25 | - (id)initWithFrame:(CGRect)frame {
26 | if (self = [super initWithFrame:frame]) {
27 | [self setUpSubviews];
28 | }
29 | return self;
30 | }
31 |
32 | - (void)setUpSubviews {
33 |
34 | [self addSubview:self.loginTextField];
35 | [self addSubview:self.pwdTextField];
36 |
37 | self.loginTextField.frame = CGRectMake(0, 0, self.bounds.size.width, 30);
38 | self.pwdTextField.frame = CGRectMake(0, 40, self.bounds.size.width, 30);
39 |
40 | __weak typeof(self)weakSelf = self;
41 | self.observe(@"title",^(id value){
42 | weakSelf.loginTextField.text = value;
43 | }).observe(@"content",^(id value){
44 | weakSelf.pwdTextField.text = value;
45 | });
46 |
47 | }
48 | /*
49 | @property (nonatomic, assign) CGPoint point;
50 | @property (nonatomic, assign) CGSize size;
51 | @property (nonatomic, assign) double db;
52 | @property (nonatomic, assign) float fl;
53 | @property (nonatomic, assign) long lg;
54 | @property (nonatomic, assign) long long llg;
55 | @property (nonatomic, assign) short st;
56 | @property (nonatomic, assign) char ch;
57 | @property (nonatomic, assign) bool bl;
58 | @property (nonatomic, assign) unsigned char ucha;
59 | @property (nonatomic, assign) unsigned long ulg;
60 | @property (nonatomic, assign) unsigned int uit;
61 | @property (nonatomic, assign) unsigned long long ullg;
62 | @property (nonatomic, assign) unsigned short ust;
63 | */
64 |
65 | - (BOOL)textFieldShouldReturn:(UITextField *)textField {
66 | [textField resignFirstResponder];
67 | if (textField.text) {
68 | self.update(@"content",textField.text).update(@"point",CGPointMake(10, 20)).update(@"size",CGSizeMake(100, 200)).update(@"db",300).update(@"fl",400.0).update(@"lg",500.0).update(@"llg",70000000).update(@"st",700).update(@"ch","char").update(@"bl",true).update(@"ucha","lobster");
69 | }
70 | return YES;
71 | }
72 |
73 | - (UITextField *)loginTextField {
74 | if (!_loginTextField) {
75 | _loginTextField = [[UITextField alloc]init];
76 | _loginTextField.borderStyle = UITextBorderStyleRoundedRect;
77 | _loginTextField.backgroundColor = [UIColor greenColor];
78 | _loginTextField.placeholder = @"请输入用户名";
79 | _loginTextField.delegate = self;
80 | }
81 | return _loginTextField;
82 | }
83 |
84 | - (UITextField *)pwdTextField {
85 | if (!_pwdTextField) {
86 | _pwdTextField = [[UITextField alloc]init];
87 | _pwdTextField.borderStyle = UITextBorderStyleRoundedRect;
88 | _pwdTextField.backgroundColor = [UIColor redColor];
89 | _pwdTextField.placeholder = @"请输入密码";
90 | _pwdTextField.delegate = self;
91 | }
92 | return _pwdTextField;
93 | }
94 | /*
95 | // Only override drawRect: if you perform custom drawing.
96 | // An empty implementation adversely affects performance during animation.
97 | - (void)drawRect:(CGRect)rect {
98 | // Drawing code
99 | }
100 | */
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/IQDataBinding.xcodeproj/xcshareddata/xcschemes/IQDataBindingDemo.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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IQDataBinding
2 | iOS端View和ViewModel数据绑定框架,实现了自动移除,且支持函数式、链式调用,使用姿势比较优雅。
3 |
4 | ## 使用方式
5 | **一、通过Cocoapods引入工程。**
6 |
7 | ```
8 | pod 'IQDataBinding'
9 | ```
10 |
11 | **二、Controller**
12 |
13 | ```
14 | /*引入NSObject+IQDataBinding头文件*/
15 | - (void)configData {
16 | self.contentModel = [[ContentModel alloc]init];
17 | self.contentModel.title = @"lobster";
18 | self.contentModel.content = @"123456";
19 |
20 | /*View和ViewModel之间绑定*/
21 | [self.contentView bindModel:self.contentModel];
22 |
23 | }
24 |
25 | ```
26 |
27 | **三、View**
28 |
29 | ```
30 | /*ViewModel >>> View*/
31 | - (void)setUpSubviews {
32 |
33 |
34 | [self addSubview:self.loginTextField];
35 | [self addSubview:self.pwdTextField];
36 |
37 | self.loginTextField.frame = CGRectMake(0, 0, self.bounds.size.width, 30);
38 | self.pwdTextField.frame = CGRectMake(0, 40, self.bounds.size.width, 30);
39 |
40 | /*绑定ViewModel中title和content属性,发生改变自动触发View更新操作*/
41 | __weak typeof(self)weakSelf = self;
42 | self.bind(@"title",^(id value){
43 | weakSelf.loginTextField.text = value;
44 | }).bind(@"content",^(id value){
45 | weakSelf.pwdTextField.text = value;
46 | });
47 |
48 | }
49 |
50 | ```
51 | ```
52 | /*View >>> ViewModel*/
53 | - (BOOL)textFieldShouldReturn:(UITextField *)textField {
54 | [textField resignFirstResponder];
55 | if (textField.text) {
56 | /*函数式调用*/
57 | self.update(@"content",textField.text).update(@"title",@"lobster");
58 | }
59 | return YES;
60 | }
61 | ```
62 |
63 | ## IQDataBinding踩坑记
64 |
65 | * View更新ViewModel属性时,如何让一个函数支持传输不同的参数类型?
66 | * View更新ViewModel时,如何避免触发KVO而导致死循环?
67 | * 如何自动移除KVO?
68 |
69 | **View更新ViewModel属性时,如何让一个函数支持传输不同的参数类型?**
70 |
71 | 笔者借鉴了Masonry框架的解决方案,通过宏定义+不定参数解决了传输不同的参数类型的问题。感兴趣的可以了解下Masonry中_MASBoxValue这个函数。
72 |
73 | **View更新ViewModel时,如何避免触发KVO而导致死循环?**
74 |
75 | 很显然,通过setValue:forKey:函数会触发KVO回调,所以我的解决方案是获取到IVar,直接设置实例变量的值。但是object_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value) 函数,只接收id类型的值。Stack Overflow查询之后,发现可以通过函数类型强转的方式来解决。
76 |
77 | **如何自动移除KVO?**
78 |
79 | 这个问题就比较简单了,为了监控View的dealloc函数调用时机,我们可以通过Hook的方式,但是Hook不太推荐。尤其使用类似于Aspects(通过消息转发来实现,代价很高)进行Hook时,对于那种一秒钟调用超过1000次的业务场景会严重影响性能。所以我采用的方案是,通过给View添加一个关联对象来解决。因为我们知道对象释放时会先释放成员变量,然后再释放关联对象,所以我们可以在关联对象的dealloc方法里对观察者进行自动移除。
80 |
81 | ```
82 | /*给view添加一个关联对象IQWatchDog,IQWatchDog职责如下
83 | 1.存储@{绑定的Key,回调Block}对应关系。
84 | 2.根据@{绑定的Key,回调Block}中的Key,进行KVO监听。
85 | 3.监听view Dealloc事件,自动移除KVO监听。
86 | */
87 | IQWatchDog *viewAssociatedModel = objc_getAssociatedObject(self, &kViewAssociatedModelKey);
88 | if (!viewAssociatedModel) {
89 | viewAssociatedModel = [[IQWatchDog alloc]init];
90 | viewAssociatedModel.target = model;
91 | objc_setAssociatedObject(self, &kViewAssociatedModelKey, viewAssociatedModel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
92 | }
93 | ```
94 | ```
95 | @interface IQWatchDog : NSObject
96 |
97 | @property (nonatomic, weak) id target;
98 | @property (nonatomic, strong) NSMutableDictionary *keyPathsAndCallBacks;
99 |
100 | @end
101 |
102 | @implementation IQWatchDog
103 |
104 | - (void)dealloc {
105 | [self.keyPathsAndCallBacks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
106 | [self.target removeObserver:self forKeyPath:key];
107 | }];
108 | }
109 |
110 | - (void)observeKeyPath:(NSString *)keyPath callBack:(observerCallBack)callBack {
111 | NSAssert(keyPath.length, @"keyPath不合法");
112 | /*加载默认值*/
113 | id value = [self.target valueForKeyPath:keyPath];
114 | if (value) {
115 | callBack(value);
116 | }
117 | /*添加观察者*/
118 | [self.keyPathsAndCallBacks setObject:callBack forKey:keyPath];
119 | [self.target addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
120 | }
121 |
122 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
123 | observerCallBack callBack = self.keyPathsAndCallBacks[keyPath];
124 | if (callBack) {
125 | callBack(change[NSKeyValueChangeNewKey]);
126 | }
127 | }
128 |
129 | - (void)removeAllObservers {
130 | [self.keyPathsAndCallBacks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
131 | [self.target removeObserver:self forKeyPath:key];
132 | }];
133 | }
134 |
135 | - (NSMutableDictionary *)keyPathsAndCallBacks {
136 | if (!_keyPathsAndCallBacks) {
137 | _keyPathsAndCallBacks = [NSMutableDictionary dictionary];
138 | }
139 | return _keyPathsAndCallBacks;
140 | }
141 |
142 | @end
143 |
144 | ```
145 |
146 | ## 联系我
147 | PRs or Issues.
148 | Email:[zhiwei.geek@gmail.com](mailto:zhiwei.geek@gmail.com)
149 |
--------------------------------------------------------------------------------
/IQDataBinding/NSObject+IQDataBinding.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+IQDataBinding.m
3 | // IQDataBinding
4 | //
5 | // Created by lobster on 2019/5/2.
6 | // Copyright © 2019 lobster. All rights reserved.
7 | //
8 |
9 | #import "NSObject+IQDataBinding.h"
10 | #import
11 |
12 | static NSString *kViewAssociatedModelKey = @"kViewAssociatedModelKey";
13 | static NSMutableDictionary *stashedObserver = nil;
14 |
15 | @interface IQWatchDog : NSObject
16 |
17 | @property (nonatomic, weak) id target;
18 | @property (nonatomic, strong) NSMutableDictionary *keyPathsAndCallBacks;
19 |
20 | @end
21 |
22 | @implementation IQWatchDog
23 |
24 | - (void)dealloc {
25 | [self.keyPathsAndCallBacks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
26 | [self.target removeObserver:self forKeyPath:key];
27 | }];
28 | }
29 |
30 | - (void)observeKeyPath:(NSString *)keyPath callBack:(observerCallBack)callBack {
31 | NSAssert(keyPath.length, @"keyPath不合法");
32 | /*加载默认值*/
33 | id value = [self.target valueForKeyPath:keyPath];
34 | if (value) {
35 | callBack(value);
36 | }
37 | /*添加观察者*/
38 | [self.keyPathsAndCallBacks setObject:callBack forKey:keyPath];
39 | [self.target addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
40 | }
41 |
42 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
43 | observerCallBack callBack = self.keyPathsAndCallBacks[keyPath];
44 | if (callBack) {
45 | callBack(change[NSKeyValueChangeNewKey]);
46 | }
47 | }
48 |
49 | - (void)removeAllObservers {
50 | [self.keyPathsAndCallBacks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
51 | [self.target removeObserver:self forKeyPath:key];
52 | }];
53 | }
54 |
55 | - (NSMutableDictionary *)keyPathsAndCallBacks {
56 | if (!_keyPathsAndCallBacks) {
57 | _keyPathsAndCallBacks = [NSMutableDictionary dictionary];
58 | }
59 | return _keyPathsAndCallBacks;
60 | }
61 |
62 | @end
63 |
64 | @implementation NSObject (IQDataBinding)
65 |
66 | - (void)bindModel:(id)model {
67 | /*给view添加一个关联对象IQWatchDog,IQWatchDog职责如下
68 | 1.存储@{绑定的Key,回调Block}对应关系。
69 | 2.根据@{绑定的Key,回调Block}中的Key,进行KVO监听。
70 | 3.监听view Dealloc事件,自动移除KVO监听。
71 | */
72 | IQWatchDog *viewAssociatedModel = objc_getAssociatedObject(self, &kViewAssociatedModelKey);
73 | if (viewAssociatedModel) {
74 | objc_setAssociatedObject(self, &kViewAssociatedModelKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
75 | }
76 |
77 | viewAssociatedModel = [[IQWatchDog alloc]init];
78 | viewAssociatedModel.target = model;
79 | objc_setAssociatedObject(self, &kViewAssociatedModelKey, viewAssociatedModel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
80 |
81 | /*借鉴Git stash暂存命令理念,stashedObserver职责如下
82 | 1.如果bindModel调用在绑定keyPath之后调用,会自动把当前@{绑定的Key,回调Block}结构保存到暂存区。
83 | 2.调用bindModel的时候先根据当前view的地址指针去stashedObserver取暂存的数据。
84 | 3.如果暂存区有数据则调用IQWatchDog注册方法进行自动注册。
85 | 4.注册完成进行stash pop操作。
86 | */
87 | NSString *viewP = [NSString stringWithFormat:@"%p",self];
88 |
89 | NSDictionary *viewStashMap = stashedObserver[viewP];
90 |
91 | if (viewStashMap) {
92 | [viewStashMap enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
93 | [viewAssociatedModel observeKeyPath:key callBack:obj];
94 | }];
95 | /*stash pop*/
96 | [stashedObserver removeObjectForKey:viewP];
97 | }
98 | }
99 |
100 | - (NSObject *(^)(NSString *keyPath,observerCallBack observer))observe {
101 | if (!stashedObserver) {
102 | stashedObserver = [NSMutableDictionary dictionary];
103 | }
104 |
105 | IQWatchDog *viewAssociatedModel = objc_getAssociatedObject(self, &kViewAssociatedModelKey);
106 |
107 | return ^(NSString *keyPath,observerCallBack observer){
108 | /*viewAssociatedModel为空,说明在绑定属性前没有绑定model,此处进行stash暂存*/
109 | if (!viewAssociatedModel) {
110 | /*stash push*/
111 | NSString *viewP = [NSString stringWithFormat:@"%p",self];
112 | NSMutableDictionary *viewStashMap = [NSMutableDictionary dictionaryWithDictionary:stashedObserver[viewP]];
113 |
114 | if (!viewStashMap) {
115 | viewStashMap = [NSMutableDictionary new];
116 | }
117 |
118 | [viewStashMap setObject:observer forKey:keyPath];
119 |
120 | [stashedObserver setObject:viewStashMap forKey:viewP];
121 | return self;
122 | }
123 | [viewAssociatedModel observeKeyPath:keyPath callBack:observer];
124 | return self;
125 | };
126 | }
127 |
128 | - (NSObject * (^)(id,...))update {
129 | return ^id(id attribute,...) {
130 | return self;
131 | };
132 | }
133 |
134 | id autoboxing(const char *type, ...) {
135 |
136 | va_list v;
137 | va_start(v, type);
138 |
139 | NSObject *pointer = va_arg(v, id);
140 | NSString *key = va_arg(v, NSString *);
141 |
142 | IQWatchDog *watchDog = objc_getAssociatedObject(pointer, &kViewAssociatedModelKey);
143 | Ivar ivar = class_getInstanceVariable([watchDog.target class], [[NSString stringWithFormat:@"_%@",key] UTF8String]);
144 |
145 | id obj = nil;
146 | if (strcmp(type, @encode(id)) == 0) {
147 | id actual = va_arg(v, id);
148 | object_setIvar(watchDog.target,ivar,actual);
149 | } else if (strcmp(type, @encode(CGPoint)) == 0) {
150 | #warning fix me!!!
151 | CGPoint actual = (CGPoint)va_arg(v, CGPoint);
152 | void (*fcgpoint)(id, Ivar, CGPoint) = (void (*)(id, Ivar, CGPoint))object_setIvar;
153 | fcgpoint(watchDog.target,ivar,actual);
154 | } else if (strcmp(type, @encode(CGSize)) == 0) {
155 | #warning fix me!!!
156 | CGSize actual = (CGSize)va_arg(v, CGSize);
157 | void (*fcgsize)(id, Ivar, CGSize) = (void (*)(id, Ivar, CGSize))object_setIvar;
158 | fcgsize(watchDog.target,ivar,actual);
159 | } else if (strcmp(type, @encode(double)) == 0) {
160 | double actual = (double)va_arg(v, double);
161 | void (*fdouble)(id, Ivar, double) = (void (*)(id, Ivar, double))object_setIvar;
162 | fdouble(watchDog.target,ivar,actual);
163 | } else if (strcmp(type, @encode(float)) == 0) {
164 | float actual = (float)va_arg(v, double);
165 | void (*ffloat)(id, Ivar, float) = (void (*)(id, Ivar, float))object_setIvar;
166 | ffloat(watchDog.target,ivar,actual);
167 | } else if (strcmp(type, @encode(int)) == 0) {
168 | int actual = (int)va_arg(v, int);
169 | void (*fint)(id, Ivar, int) = (void (*)(id, Ivar, int))object_setIvar;
170 | fint(watchDog.target,ivar,actual);
171 | } else if (strcmp(type, @encode(long)) == 0) {
172 | long actual = (long)va_arg(v, long);
173 | void (*flong)(id, Ivar, long) = (void (*)(id, Ivar, long))object_setIvar;
174 | flong(watchDog.target,ivar,actual);
175 | } else if (strcmp(type, @encode(long long)) == 0) {
176 | long long actual = (long long)va_arg(v, long long);
177 | void (*flonglong)(id, Ivar, long long) = (void (*)(id, Ivar, long long))object_setIvar;
178 | flonglong(watchDog.target,ivar,actual);
179 | } else if (strcmp(type, @encode(short)) == 0) {
180 | short actual = (short)va_arg(v, int);
181 | void (*fshort)(id, Ivar, short) = (void (*)(id, Ivar, short))object_setIvar;
182 | fshort(watchDog.target,ivar,actual);
183 | } else if (strcmp(type, @encode(char)) == 0) {
184 | char actual = (char)va_arg(v, int);
185 | void (*fchar)(id, Ivar, char) = (void (*)(id, Ivar, char))object_setIvar;
186 | fchar(watchDog.target,ivar,actual);
187 | } else if (strcmp(type, @encode(bool)) == 0) {
188 | bool actual = (bool)va_arg(v, int);
189 | void (*fbool)(id, Ivar, bool) = (void (*)(id, Ivar, bool))object_setIvar;
190 | fbool(watchDog.target,ivar,actual);
191 | } else if (strcmp(type, @encode(unsigned char)) == 0) {
192 | unsigned char actual = (unsigned char)va_arg(v, unsigned int);
193 | void (*funsignedchar)(id, Ivar, unsigned char) = (void (*)(id, Ivar, unsigned char))object_setIvar;
194 | funsignedchar(watchDog.target,ivar,actual);
195 | } else if (strcmp(type, @encode(unsigned int)) == 0) {
196 | unsigned int actual = (unsigned int)va_arg(v, unsigned int);
197 | void (*funsignedint)(id, Ivar, unsigned int) = (void (*)(id, Ivar, unsigned int))object_setIvar;
198 | funsignedint(watchDog.target,ivar,actual);
199 | } else if (strcmp(type, @encode(unsigned long)) == 0) {
200 | unsigned long actual = (unsigned long)va_arg(v, unsigned long);
201 | void (*funsignedlong)(id, Ivar, unsigned long) = (void (*)(id, Ivar, unsigned long))object_setIvar;
202 | funsignedlong(watchDog.target,ivar,actual);
203 | } else if (strcmp(type, @encode(unsigned long long)) == 0) {
204 | unsigned long long actual = (unsigned long long)va_arg(v, unsigned long long);
205 | void (*funsignedlonglong)(id, Ivar, unsigned long long) = (void (*)(id, Ivar, unsigned long long))object_setIvar;
206 | funsignedlonglong(watchDog.target,ivar,actual);
207 | } else if (strcmp(type, @encode(unsigned short)) == 0) {
208 | unsigned short actual = (unsigned short)va_arg(v, unsigned int);
209 | void (*funsignedshort)(id, Ivar, unsigned short) = (void (*)(id, Ivar, unsigned short))object_setIvar;
210 | funsignedshort(watchDog.target,ivar,actual);
211 | }
212 | va_end(v);
213 | return obj;
214 | }
215 |
216 | @end
217 |
--------------------------------------------------------------------------------
/IQDataBinding.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | BA4129C2227BC50500EA8099 /* NSObject+IQDataBinding.m in Sources */ = {isa = PBXBuildFile; fileRef = BAFD163C227B3CB8002D98EB /* NSObject+IQDataBinding.m */; };
11 | BA68B9A4227DD4F1005F4819 /* ContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = BA68B9A3227DD4F1005F4819 /* ContentView.m */; };
12 | BAFD161B227B39DF002D98EB /* IQDataBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = BAFD1619227B39DF002D98EB /* IQDataBinding.h */; settings = {ATTRIBUTES = (Public, ); }; };
13 | BAFD1629227B3A85002D98EB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BAFD1628227B3A85002D98EB /* AppDelegate.m */; };
14 | BAFD162C227B3A85002D98EB /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BAFD162B227B3A85002D98EB /* ViewController.m */; };
15 | BAFD162F227B3A85002D98EB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BAFD162D227B3A85002D98EB /* Main.storyboard */; };
16 | BAFD1631227B3A86002D98EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BAFD1630227B3A86002D98EB /* Assets.xcassets */; };
17 | BAFD1634227B3A86002D98EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BAFD1632227B3A86002D98EB /* LaunchScreen.storyboard */; };
18 | BAFD1637227B3A86002D98EB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BAFD1636227B3A86002D98EB /* main.m */; };
19 | BAFD163D227B3CB8002D98EB /* NSObject+IQDataBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = BAFD163B227B3CB8002D98EB /* NSObject+IQDataBinding.h */; };
20 | BAFD163E227B3CB8002D98EB /* NSObject+IQDataBinding.m in Sources */ = {isa = PBXBuildFile; fileRef = BAFD163C227B3CB8002D98EB /* NSObject+IQDataBinding.m */; };
21 | BAFD1645227B3EB5002D98EB /* ContentModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BAFD1644227B3EB5002D98EB /* ContentModel.m */; };
22 | /* End PBXBuildFile section */
23 |
24 | /* Begin PBXFileReference section */
25 | BA68B9A2227DD4F1005F4819 /* ContentView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContentView.h; sourceTree = ""; };
26 | BA68B9A3227DD4F1005F4819 /* ContentView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContentView.m; sourceTree = ""; };
27 | BAFD1616227B39DF002D98EB /* IQDataBinding.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IQDataBinding.framework; sourceTree = BUILT_PRODUCTS_DIR; };
28 | BAFD1619227B39DF002D98EB /* IQDataBinding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IQDataBinding.h; sourceTree = ""; };
29 | BAFD161A227B39DF002D98EB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | BAFD1625227B3A85002D98EB /* IQDataBindingDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IQDataBindingDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
31 | BAFD1627227B3A85002D98EB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
32 | BAFD1628227B3A85002D98EB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
33 | BAFD162A227B3A85002D98EB /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
34 | BAFD162B227B3A85002D98EB /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
35 | BAFD162E227B3A85002D98EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
36 | BAFD1630227B3A86002D98EB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
37 | BAFD1633227B3A86002D98EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
38 | BAFD1635227B3A86002D98EB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
39 | BAFD1636227B3A86002D98EB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
40 | BAFD163B227B3CB8002D98EB /* NSObject+IQDataBinding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+IQDataBinding.h"; sourceTree = ""; };
41 | BAFD163C227B3CB8002D98EB /* NSObject+IQDataBinding.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+IQDataBinding.m"; sourceTree = ""; };
42 | BAFD1643227B3EB5002D98EB /* ContentModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContentModel.h; sourceTree = ""; };
43 | BAFD1644227B3EB5002D98EB /* ContentModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContentModel.m; sourceTree = ""; };
44 | /* End PBXFileReference section */
45 |
46 | /* Begin PBXFrameworksBuildPhase section */
47 | BAFD1613227B39DF002D98EB /* Frameworks */ = {
48 | isa = PBXFrameworksBuildPhase;
49 | buildActionMask = 2147483647;
50 | files = (
51 | );
52 | runOnlyForDeploymentPostprocessing = 0;
53 | };
54 | BAFD1622227B3A85002D98EB /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | BAFD160C227B39DF002D98EB = {
65 | isa = PBXGroup;
66 | children = (
67 | BAFD1618227B39DF002D98EB /* IQDataBinding */,
68 | BAFD1626227B3A85002D98EB /* IQDataBindingDemo */,
69 | BAFD1617227B39DF002D98EB /* Products */,
70 | BAFD1648227B4ED2002D98EB /* Frameworks */,
71 | );
72 | sourceTree = "";
73 | };
74 | BAFD1617227B39DF002D98EB /* Products */ = {
75 | isa = PBXGroup;
76 | children = (
77 | BAFD1616227B39DF002D98EB /* IQDataBinding.framework */,
78 | BAFD1625227B3A85002D98EB /* IQDataBindingDemo.app */,
79 | );
80 | name = Products;
81 | sourceTree = "";
82 | };
83 | BAFD1618227B39DF002D98EB /* IQDataBinding */ = {
84 | isa = PBXGroup;
85 | children = (
86 | BAFD1619227B39DF002D98EB /* IQDataBinding.h */,
87 | BAFD163B227B3CB8002D98EB /* NSObject+IQDataBinding.h */,
88 | BAFD163C227B3CB8002D98EB /* NSObject+IQDataBinding.m */,
89 | BAFD161A227B39DF002D98EB /* Info.plist */,
90 | );
91 | path = IQDataBinding;
92 | sourceTree = "";
93 | };
94 | BAFD1626227B3A85002D98EB /* IQDataBindingDemo */ = {
95 | isa = PBXGroup;
96 | children = (
97 | BAFD1627227B3A85002D98EB /* AppDelegate.h */,
98 | BAFD1628227B3A85002D98EB /* AppDelegate.m */,
99 | BAFD162A227B3A85002D98EB /* ViewController.h */,
100 | BAFD162B227B3A85002D98EB /* ViewController.m */,
101 | BA68B9A2227DD4F1005F4819 /* ContentView.h */,
102 | BA68B9A3227DD4F1005F4819 /* ContentView.m */,
103 | BAFD1643227B3EB5002D98EB /* ContentModel.h */,
104 | BAFD1644227B3EB5002D98EB /* ContentModel.m */,
105 | BAFD162D227B3A85002D98EB /* Main.storyboard */,
106 | BAFD1630227B3A86002D98EB /* Assets.xcassets */,
107 | BAFD1632227B3A86002D98EB /* LaunchScreen.storyboard */,
108 | BAFD1635227B3A86002D98EB /* Info.plist */,
109 | BAFD1636227B3A86002D98EB /* main.m */,
110 | );
111 | path = IQDataBindingDemo;
112 | sourceTree = "";
113 | };
114 | BAFD1648227B4ED2002D98EB /* Frameworks */ = {
115 | isa = PBXGroup;
116 | children = (
117 | );
118 | name = Frameworks;
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXHeadersBuildPhase section */
124 | BAFD1611227B39DF002D98EB /* Headers */ = {
125 | isa = PBXHeadersBuildPhase;
126 | buildActionMask = 2147483647;
127 | files = (
128 | BAFD163D227B3CB8002D98EB /* NSObject+IQDataBinding.h in Headers */,
129 | BAFD161B227B39DF002D98EB /* IQDataBinding.h in Headers */,
130 | );
131 | runOnlyForDeploymentPostprocessing = 0;
132 | };
133 | /* End PBXHeadersBuildPhase section */
134 |
135 | /* Begin PBXNativeTarget section */
136 | BAFD1615227B39DF002D98EB /* IQDataBinding */ = {
137 | isa = PBXNativeTarget;
138 | buildConfigurationList = BAFD161E227B39DF002D98EB /* Build configuration list for PBXNativeTarget "IQDataBinding" */;
139 | buildPhases = (
140 | BAFD1611227B39DF002D98EB /* Headers */,
141 | BAFD1612227B39DF002D98EB /* Sources */,
142 | BAFD1613227B39DF002D98EB /* Frameworks */,
143 | BAFD1614227B39DF002D98EB /* Resources */,
144 | );
145 | buildRules = (
146 | );
147 | dependencies = (
148 | );
149 | name = IQDataBinding;
150 | productName = IQDataBinding;
151 | productReference = BAFD1616227B39DF002D98EB /* IQDataBinding.framework */;
152 | productType = "com.apple.product-type.framework";
153 | };
154 | BAFD1624227B3A85002D98EB /* IQDataBindingDemo */ = {
155 | isa = PBXNativeTarget;
156 | buildConfigurationList = BAFD163A227B3A86002D98EB /* Build configuration list for PBXNativeTarget "IQDataBindingDemo" */;
157 | buildPhases = (
158 | BAFD1621227B3A85002D98EB /* Sources */,
159 | BAFD1622227B3A85002D98EB /* Frameworks */,
160 | BAFD1623227B3A85002D98EB /* Resources */,
161 | );
162 | buildRules = (
163 | );
164 | dependencies = (
165 | );
166 | name = IQDataBindingDemo;
167 | productName = IQDataBindingDemo;
168 | productReference = BAFD1625227B3A85002D98EB /* IQDataBindingDemo.app */;
169 | productType = "com.apple.product-type.application";
170 | };
171 | /* End PBXNativeTarget section */
172 |
173 | /* Begin PBXProject section */
174 | BAFD160D227B39DF002D98EB /* Project object */ = {
175 | isa = PBXProject;
176 | attributes = {
177 | LastUpgradeCheck = 1020;
178 | ORGANIZATIONNAME = lobster;
179 | TargetAttributes = {
180 | BAFD1615227B39DF002D98EB = {
181 | CreatedOnToolsVersion = 10.2.1;
182 | };
183 | BAFD1624227B3A85002D98EB = {
184 | CreatedOnToolsVersion = 10.2.1;
185 | };
186 | };
187 | };
188 | buildConfigurationList = BAFD1610227B39DF002D98EB /* Build configuration list for PBXProject "IQDataBinding" */;
189 | compatibilityVersion = "Xcode 9.3";
190 | developmentRegion = en;
191 | hasScannedForEncodings = 0;
192 | knownRegions = (
193 | en,
194 | Base,
195 | );
196 | mainGroup = BAFD160C227B39DF002D98EB;
197 | productRefGroup = BAFD1617227B39DF002D98EB /* Products */;
198 | projectDirPath = "";
199 | projectRoot = "";
200 | targets = (
201 | BAFD1615227B39DF002D98EB /* IQDataBinding */,
202 | BAFD1624227B3A85002D98EB /* IQDataBindingDemo */,
203 | );
204 | };
205 | /* End PBXProject section */
206 |
207 | /* Begin PBXResourcesBuildPhase section */
208 | BAFD1614227B39DF002D98EB /* Resources */ = {
209 | isa = PBXResourcesBuildPhase;
210 | buildActionMask = 2147483647;
211 | files = (
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | };
215 | BAFD1623227B3A85002D98EB /* Resources */ = {
216 | isa = PBXResourcesBuildPhase;
217 | buildActionMask = 2147483647;
218 | files = (
219 | BAFD1634227B3A86002D98EB /* LaunchScreen.storyboard in Resources */,
220 | BAFD1631227B3A86002D98EB /* Assets.xcassets in Resources */,
221 | BAFD162F227B3A85002D98EB /* Main.storyboard in Resources */,
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | };
225 | /* End PBXResourcesBuildPhase section */
226 |
227 | /* Begin PBXSourcesBuildPhase section */
228 | BAFD1612227B39DF002D98EB /* Sources */ = {
229 | isa = PBXSourcesBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | BAFD163E227B3CB8002D98EB /* NSObject+IQDataBinding.m in Sources */,
233 | );
234 | runOnlyForDeploymentPostprocessing = 0;
235 | };
236 | BAFD1621227B3A85002D98EB /* Sources */ = {
237 | isa = PBXSourcesBuildPhase;
238 | buildActionMask = 2147483647;
239 | files = (
240 | BA4129C2227BC50500EA8099 /* NSObject+IQDataBinding.m in Sources */,
241 | BAFD162C227B3A85002D98EB /* ViewController.m in Sources */,
242 | BA68B9A4227DD4F1005F4819 /* ContentView.m in Sources */,
243 | BAFD1645227B3EB5002D98EB /* ContentModel.m in Sources */,
244 | BAFD1637227B3A86002D98EB /* main.m in Sources */,
245 | BAFD1629227B3A85002D98EB /* AppDelegate.m in Sources */,
246 | );
247 | runOnlyForDeploymentPostprocessing = 0;
248 | };
249 | /* End PBXSourcesBuildPhase section */
250 |
251 | /* Begin PBXVariantGroup section */
252 | BAFD162D227B3A85002D98EB /* Main.storyboard */ = {
253 | isa = PBXVariantGroup;
254 | children = (
255 | BAFD162E227B3A85002D98EB /* Base */,
256 | );
257 | name = Main.storyboard;
258 | sourceTree = "";
259 | };
260 | BAFD1632227B3A86002D98EB /* LaunchScreen.storyboard */ = {
261 | isa = PBXVariantGroup;
262 | children = (
263 | BAFD1633227B3A86002D98EB /* Base */,
264 | );
265 | name = LaunchScreen.storyboard;
266 | sourceTree = "";
267 | };
268 | /* End PBXVariantGroup section */
269 |
270 | /* Begin XCBuildConfiguration section */
271 | BAFD161C227B39DF002D98EB /* Debug */ = {
272 | isa = XCBuildConfiguration;
273 | buildSettings = {
274 | ALWAYS_SEARCH_USER_PATHS = NO;
275 | CLANG_ANALYZER_NONNULL = YES;
276 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
278 | CLANG_CXX_LIBRARY = "libc++";
279 | CLANG_ENABLE_MODULES = YES;
280 | CLANG_ENABLE_OBJC_ARC = YES;
281 | CLANG_ENABLE_OBJC_WEAK = YES;
282 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
283 | CLANG_WARN_BOOL_CONVERSION = YES;
284 | CLANG_WARN_COMMA = YES;
285 | CLANG_WARN_CONSTANT_CONVERSION = YES;
286 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
287 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
288 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
289 | CLANG_WARN_EMPTY_BODY = YES;
290 | CLANG_WARN_ENUM_CONVERSION = YES;
291 | CLANG_WARN_INFINITE_RECURSION = YES;
292 | CLANG_WARN_INT_CONVERSION = YES;
293 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
294 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
295 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
296 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
297 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
298 | CLANG_WARN_STRICT_PROTOTYPES = YES;
299 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
300 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
301 | CLANG_WARN_UNREACHABLE_CODE = YES;
302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
303 | CODE_SIGN_IDENTITY = "iPhone Developer";
304 | COPY_PHASE_STRIP = NO;
305 | CURRENT_PROJECT_VERSION = 1;
306 | DEBUG_INFORMATION_FORMAT = dwarf;
307 | ENABLE_STRICT_OBJC_MSGSEND = YES;
308 | ENABLE_TESTABILITY = YES;
309 | GCC_C_LANGUAGE_STANDARD = gnu11;
310 | GCC_DYNAMIC_NO_PIC = NO;
311 | GCC_NO_COMMON_BLOCKS = YES;
312 | GCC_OPTIMIZATION_LEVEL = 0;
313 | GCC_PREPROCESSOR_DEFINITIONS = (
314 | "DEBUG=1",
315 | "$(inherited)",
316 | );
317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
318 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
319 | GCC_WARN_UNDECLARED_SELECTOR = YES;
320 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
321 | GCC_WARN_UNUSED_FUNCTION = YES;
322 | GCC_WARN_UNUSED_VARIABLE = YES;
323 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
324 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
325 | MTL_FAST_MATH = YES;
326 | ONLY_ACTIVE_ARCH = YES;
327 | SDKROOT = iphoneos;
328 | VERSIONING_SYSTEM = "apple-generic";
329 | VERSION_INFO_PREFIX = "";
330 | };
331 | name = Debug;
332 | };
333 | BAFD161D227B39DF002D98EB /* Release */ = {
334 | isa = XCBuildConfiguration;
335 | buildSettings = {
336 | ALWAYS_SEARCH_USER_PATHS = NO;
337 | CLANG_ANALYZER_NONNULL = YES;
338 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
339 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
340 | CLANG_CXX_LIBRARY = "libc++";
341 | CLANG_ENABLE_MODULES = YES;
342 | CLANG_ENABLE_OBJC_ARC = YES;
343 | CLANG_ENABLE_OBJC_WEAK = YES;
344 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
345 | CLANG_WARN_BOOL_CONVERSION = YES;
346 | CLANG_WARN_COMMA = YES;
347 | CLANG_WARN_CONSTANT_CONVERSION = YES;
348 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
349 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
350 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
351 | CLANG_WARN_EMPTY_BODY = YES;
352 | CLANG_WARN_ENUM_CONVERSION = YES;
353 | CLANG_WARN_INFINITE_RECURSION = YES;
354 | CLANG_WARN_INT_CONVERSION = YES;
355 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
356 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
357 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
358 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
359 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
360 | CLANG_WARN_STRICT_PROTOTYPES = YES;
361 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
362 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
363 | CLANG_WARN_UNREACHABLE_CODE = YES;
364 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
365 | CODE_SIGN_IDENTITY = "iPhone Developer";
366 | COPY_PHASE_STRIP = NO;
367 | CURRENT_PROJECT_VERSION = 1;
368 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
369 | ENABLE_NS_ASSERTIONS = NO;
370 | ENABLE_STRICT_OBJC_MSGSEND = YES;
371 | GCC_C_LANGUAGE_STANDARD = gnu11;
372 | GCC_NO_COMMON_BLOCKS = YES;
373 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
374 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
375 | GCC_WARN_UNDECLARED_SELECTOR = YES;
376 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
377 | GCC_WARN_UNUSED_FUNCTION = YES;
378 | GCC_WARN_UNUSED_VARIABLE = YES;
379 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
380 | MTL_ENABLE_DEBUG_INFO = NO;
381 | MTL_FAST_MATH = YES;
382 | SDKROOT = iphoneos;
383 | VALIDATE_PRODUCT = YES;
384 | VERSIONING_SYSTEM = "apple-generic";
385 | VERSION_INFO_PREFIX = "";
386 | };
387 | name = Release;
388 | };
389 | BAFD161F227B39DF002D98EB /* Debug */ = {
390 | isa = XCBuildConfiguration;
391 | buildSettings = {
392 | CODE_SIGN_IDENTITY = "";
393 | CODE_SIGN_STYLE = Automatic;
394 | DEFINES_MODULE = YES;
395 | DYLIB_COMPATIBILITY_VERSION = 1;
396 | DYLIB_CURRENT_VERSION = 1;
397 | DYLIB_INSTALL_NAME_BASE = "@rpath";
398 | INFOPLIST_FILE = IQDataBinding/Info.plist;
399 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
400 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
401 | LD_RUNPATH_SEARCH_PATHS = (
402 | "$(inherited)",
403 | "@executable_path/Frameworks",
404 | "@loader_path/Frameworks",
405 | );
406 | OTHER_LDFLAGS = "";
407 | PRODUCT_BUNDLE_IDENTIFIER = com.lobster.IQDataBinding;
408 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
409 | SKIP_INSTALL = YES;
410 | TARGETED_DEVICE_FAMILY = "1,2";
411 | };
412 | name = Debug;
413 | };
414 | BAFD1620227B39DF002D98EB /* Release */ = {
415 | isa = XCBuildConfiguration;
416 | buildSettings = {
417 | CODE_SIGN_IDENTITY = "";
418 | CODE_SIGN_STYLE = Automatic;
419 | DEFINES_MODULE = YES;
420 | DYLIB_COMPATIBILITY_VERSION = 1;
421 | DYLIB_CURRENT_VERSION = 1;
422 | DYLIB_INSTALL_NAME_BASE = "@rpath";
423 | INFOPLIST_FILE = IQDataBinding/Info.plist;
424 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
425 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
426 | LD_RUNPATH_SEARCH_PATHS = (
427 | "$(inherited)",
428 | "@executable_path/Frameworks",
429 | "@loader_path/Frameworks",
430 | );
431 | OTHER_LDFLAGS = "";
432 | PRODUCT_BUNDLE_IDENTIFIER = com.lobster.IQDataBinding;
433 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
434 | SKIP_INSTALL = YES;
435 | TARGETED_DEVICE_FAMILY = "1,2";
436 | };
437 | name = Release;
438 | };
439 | BAFD1638227B3A86002D98EB /* Debug */ = {
440 | isa = XCBuildConfiguration;
441 | buildSettings = {
442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
443 | CODE_SIGN_STYLE = Automatic;
444 | INFOPLIST_FILE = IQDataBindingDemo/Info.plist;
445 | LD_RUNPATH_SEARCH_PATHS = (
446 | "$(inherited)",
447 | "@executable_path/Frameworks",
448 | );
449 | OTHER_LDFLAGS = "";
450 | OTHER_LIBTOOLFLAGS = "-ObjC";
451 | PRODUCT_BUNDLE_IDENTIFIER = com.lobster.IQDataBindingDemo;
452 | PRODUCT_NAME = "$(TARGET_NAME)";
453 | TARGETED_DEVICE_FAMILY = "1,2";
454 | };
455 | name = Debug;
456 | };
457 | BAFD1639227B3A86002D98EB /* Release */ = {
458 | isa = XCBuildConfiguration;
459 | buildSettings = {
460 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
461 | CODE_SIGN_STYLE = Automatic;
462 | INFOPLIST_FILE = IQDataBindingDemo/Info.plist;
463 | LD_RUNPATH_SEARCH_PATHS = (
464 | "$(inherited)",
465 | "@executable_path/Frameworks",
466 | );
467 | OTHER_LDFLAGS = "";
468 | OTHER_LIBTOOLFLAGS = "-ObjC";
469 | PRODUCT_BUNDLE_IDENTIFIER = com.lobster.IQDataBindingDemo;
470 | PRODUCT_NAME = "$(TARGET_NAME)";
471 | TARGETED_DEVICE_FAMILY = "1,2";
472 | };
473 | name = Release;
474 | };
475 | /* End XCBuildConfiguration section */
476 |
477 | /* Begin XCConfigurationList section */
478 | BAFD1610227B39DF002D98EB /* Build configuration list for PBXProject "IQDataBinding" */ = {
479 | isa = XCConfigurationList;
480 | buildConfigurations = (
481 | BAFD161C227B39DF002D98EB /* Debug */,
482 | BAFD161D227B39DF002D98EB /* Release */,
483 | );
484 | defaultConfigurationIsVisible = 0;
485 | defaultConfigurationName = Release;
486 | };
487 | BAFD161E227B39DF002D98EB /* Build configuration list for PBXNativeTarget "IQDataBinding" */ = {
488 | isa = XCConfigurationList;
489 | buildConfigurations = (
490 | BAFD161F227B39DF002D98EB /* Debug */,
491 | BAFD1620227B39DF002D98EB /* Release */,
492 | );
493 | defaultConfigurationIsVisible = 0;
494 | defaultConfigurationName = Release;
495 | };
496 | BAFD163A227B3A86002D98EB /* Build configuration list for PBXNativeTarget "IQDataBindingDemo" */ = {
497 | isa = XCConfigurationList;
498 | buildConfigurations = (
499 | BAFD1638227B3A86002D98EB /* Debug */,
500 | BAFD1639227B3A86002D98EB /* Release */,
501 | );
502 | defaultConfigurationIsVisible = 0;
503 | defaultConfigurationName = Release;
504 | };
505 | /* End XCConfigurationList section */
506 | };
507 | rootObject = BAFD160D227B39DF002D98EB /* Project object */;
508 | }
509 |
--------------------------------------------------------------------------------