├── .gitignore ├── .travis.yml ├── Demo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Demo-Bridging-Header.h ├── Info.plist ├── SwiftViewController.swift ├── ViewController.h ├── ViewController.m └── main.m ├── LICENSE ├── Package.swift ├── README.md ├── Sources ├── UITextView+Placeholder.h └── UITextView+Placeholder.m ├── Supporting Files ├── Info.plist └── module.modulemap ├── Tests ├── Tests.swift └── Utils.swift ├── UITextView+Placeholder.podspec └── UITextView+Placeholder.xcodeproj ├── project.pbxproj ├── project.xcworkspace └── contents.xcworkspacedata ├── xcshareddata └── xcschemes │ ├── Demo.xcscheme │ └── UITextView+Placeholder.xcscheme └── xcuserdata └── xoul.xcuserdatad └── xcschemes └── xcschememanagement.plist /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | build 4 | 5 | **/xcuserdata 6 | **/xcshareddata 7 | *.pbxuser 8 | *.mode1v3 9 | 10 | Podfile.lock 11 | Pods 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode11 3 | sudo: false 4 | 5 | env: 6 | global: 7 | - PROJECT="UITextView+Placeholder.xcodeproj" 8 | - SCHEME="UITextView+Placeholder" 9 | matrix: 10 | - SDK="iphonesimulator11.4" DESTINATION="platform=iOS Simulator,name=iPhone 8,OS=11.4" 11 | - SDK="iphonesimulator12.4" DESTINATION="platform=iOS Simulator,name=iPhone 8,OS=12.4" 12 | - SDK="iphonesimulator13.0" DESTINATION="platform=iOS Simulator,name=iPhone 8,OS=13.0" 13 | 14 | script: 15 | - xcodebuild clean test 16 | -project "$PROJECT" 17 | -scheme "$SCHEME" 18 | -sdk "$SDK" 19 | -destination "$DESTINATION" 20 | -configuration Debug 21 | CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty -c 22 | -------------------------------------------------------------------------------- /Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | #import 24 | 25 | @interface AppDelegate : UIResponder 26 | 27 | @property (strong, nonatomic) UIWindow *window; 28 | 29 | 30 | @end 31 | 32 | -------------------------------------------------------------------------------- /Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | #import "AppDelegate.h" 24 | 25 | @interface AppDelegate () 26 | 27 | @end 28 | 29 | @implementation AppDelegate 30 | 31 | 32 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 33 | // Override point for customization after application launch. 34 | return YES; 35 | } 36 | 37 | - (void)applicationWillResignActive:(UIApplication *)application { 38 | // 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. 39 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 40 | } 41 | 42 | - (void)applicationDidEnterBackground:(UIApplication *)application { 43 | // 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. 44 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 45 | } 46 | 47 | - (void)applicationWillEnterForeground:(UIApplication *)application { 48 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 49 | } 50 | 51 | - (void)applicationDidBecomeActive:(UIApplication *)application { 52 | // 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. 53 | } 54 | 55 | - (void)applicationWillTerminate:(UIApplication *)application { 56 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Demo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Demo/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 | -------------------------------------------------------------------------------- /Demo/Demo-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | -------------------------------------------------------------------------------- /Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Demo/SwiftViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftViewController.swift 3 | // UITextView+Placeholder 4 | // 5 | // Created by Yoshiyuki Kawashima on 2017/05/15. 6 | // Copyright © 2017年 Suyeol Jeon. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SwiftViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | let textView: UITextView = UITextView() 17 | textView.frame = CGRect.init(x: 0, y: 20, width: view.frame.width, height: view.frame.height) 18 | textView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 19 | textView.placeholder = "Are you sure you don\'t want to reconsider? Could you tell us why you wish to leave StyleShare? Your opinion helps us improve StyleShare into a better place for fashionistas from all around the world. We are always listening to our users. Help us improve!" 20 | view.addSubview(textView) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Demo/ViewController.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | #import 24 | 25 | @interface ViewController : UIViewController 26 | 27 | 28 | @end 29 | 30 | -------------------------------------------------------------------------------- /Demo/ViewController.m: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | #import "ViewController.h" 24 | #import 25 | 26 | @implementation ViewController 27 | 28 | - (void)viewDidLoad { 29 | [super viewDidLoad]; 30 | 31 | UITextView *textView = [[UITextView alloc] init]; 32 | textView.frame = CGRectMake(50, 120, 200, 200); 33 | textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 34 | textView.placeholder = @"Are you sure you don\'t want to reconsider? Could you tell us why you wish to leave StyleShare? Your opinion helps us improve StyleShare into a better place for fashionistas from all around the world. We are always listening to our users. Help us improve!"; 35 | // NSDictionary *attrs = @ { 36 | // NSFontAttributeName: [UIFont boldSystemFontOfSize:20], 37 | // }; 38 | // textView.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"Hi" attributes:attrs]; 39 | textView.font = [UIFont systemFontOfSize:15]; 40 | textView.layer.borderColor = UIColor.redColor.CGColor; 41 | textView.layer.borderWidth = 1.0; 42 | textView.textContainerInset = UIEdgeInsetsMake(20, 20, 20, 20); 43 | UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 50, 50)]; 44 | textView.textContainer.exclusionPaths = @[path]; 45 | [self.view addSubview:textView]; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Demo 4 | // 5 | // Created by 전수열 on 4/12/16. 6 | // Copyright © 2016 Suyeol Jeon. 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Suyeol Jeon (http://xoul.kr) 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "UITextView+Placeholder", 8 | products: [ 9 | .library( 10 | name: "UITextView+Placeholder", 11 | targets: ["UITextView+Placeholder"]), 12 | ], 13 | dependencies: [], 14 | targets: [ 15 | .target( 16 | name: "UITextView+Placeholder", 17 | path: "Sources", 18 | publicHeadersPath: "Sources"), 19 | ] 20 | ) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | UITextView+Placeholder 2 | ====================== 3 | 4 | [![Build Status](https://travis-ci.org/devxoul/UITextView-Placeholder.svg?branch=master)](https://travis-ci.org/devxoul/UITextView-Placeholder) 5 | [![CocoaPods](http://img.shields.io/cocoapods/v/UITextView+Placeholder.svg?style=flat)](http://cocoapods.org/?q=name%3AUITextView%2BPlaceholder) 6 | 7 | A missing placeholder for UITextView. 8 | 9 | 10 | Installation 11 | ------------ 12 | 13 | Use [CocoaPods](http://cocoapods.org). 14 | 15 | ```ruby 16 | pod 'UITextView+Placeholder' 17 | ``` 18 | 19 | 20 | Usage 21 | ----- 22 | 23 | - **Import Dynamic Framework**: 24 | 25 | e.g. If you're using CocoaPods with `use_frameworks!` flag. 26 | 27 | ```objc 28 | @import UITextView_Placeholder; 29 | ``` 30 | 31 | - **Import Static Library**: 32 | 33 | ```objc 34 | #import 35 | ``` 36 | 37 | Then create `UITextView` and set `placeholder`. 38 | 39 | - **Implement Objective-C**: 40 | 41 | ```objc 42 | UITextView *textView = [[UITextView alloc] init]; 43 | textView.placeholder = @"How are you?"; 44 | textView.placeholderColor = [UIColor lightGrayColor]; // optional 45 | textView.attributedPlaceholder = ... // NSAttributedString (optional) 46 | ``` 47 | 48 | - **Implement Swift**: 49 | 50 | ```swift 51 | let textView = UITextView() 52 | textView.placeholder = "How are you?" 53 | textView.placeholderColor = UIColor.lightGray // optional 54 | textView.attributedPlaceholder = ... // NSAttributedString (optional) 55 | ``` 56 | 57 | Congratulations! You're done. 🎉 58 | 59 | 60 | License 61 | ------- 62 | 63 | UITextView+Placeholder is under MIT license. See the [LICENSE](LICENSE) file for more information. 64 | -------------------------------------------------------------------------------- /Sources/UITextView+Placeholder.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | #if __has_feature(modules) 24 | @import UIKit; 25 | #else 26 | #import 27 | #endif 28 | 29 | FOUNDATION_EXPORT double UITextView_PlaceholderVersionNumber; 30 | FOUNDATION_EXPORT const unsigned char UITextView_PlaceholderVersionString[]; 31 | 32 | @interface UITextView (Placeholder) 33 | 34 | @property (nonatomic, readonly) UITextView *placeholderTextView NS_SWIFT_NAME(placeholderTextView); 35 | 36 | @property (nonatomic, strong) IBInspectable NSString *placeholder; 37 | @property (nonatomic, strong) NSAttributedString *attributedPlaceholder; 38 | @property (nonatomic, strong) IBInspectable UIColor *placeholderColor; 39 | 40 | + (UIColor *)defaultPlaceholderColor; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Sources/UITextView+Placeholder.m: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | #import 24 | #import "UITextView+Placeholder.h" 25 | 26 | @implementation UITextView (Placeholder) 27 | 28 | #pragma mark - Swizzle Dealloc 29 | 30 | + (void)load { 31 | // is this the best solution? 32 | method_exchangeImplementations(class_getInstanceMethod(self.class, NSSelectorFromString(@"dealloc")), 33 | class_getInstanceMethod(self.class, @selector(swizzledDealloc))); 34 | } 35 | 36 | - (void)swizzledDealloc { 37 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 38 | UITextView *textView = objc_getAssociatedObject(self, @selector(placeholderTextView)); 39 | if (textView) { 40 | for (NSString *key in self.class.observingKeys) { 41 | @try { 42 | [self removeObserver:self forKeyPath:key]; 43 | } 44 | @catch (NSException *exception) { 45 | // Do nothing 46 | } 47 | } 48 | } 49 | [self swizzledDealloc]; 50 | } 51 | 52 | 53 | #pragma mark - Class Methods 54 | #pragma mark `defaultPlaceholderColor` 55 | 56 | + (UIColor *)defaultPlaceholderColor { 57 | if (@available(iOS 13, *)) { 58 | SEL selector = NSSelectorFromString(@"placeholderTextColor"); 59 | if ([UIColor respondsToSelector:selector]) { 60 | return [UIColor performSelector:selector]; 61 | } 62 | } 63 | static UIColor *color = nil; 64 | static dispatch_once_t onceToken; 65 | dispatch_once(&onceToken, ^{ 66 | UITextField *textField = [[UITextField alloc] init]; 67 | textField.placeholder = @" "; 68 | NSDictionary *attributes = [textField.attributedPlaceholder attributesAtIndex:0 effectiveRange:nil]; 69 | color = attributes[NSForegroundColorAttributeName]; 70 | if (!color) { 71 | color = [UIColor colorWithRed:0 green:0 blue:0.0980392 alpha:0.22]; 72 | } 73 | }); 74 | return color; 75 | } 76 | 77 | 78 | #pragma mark - `observingKeys` 79 | 80 | + (NSArray *)observingKeys { 81 | return @[@"attributedText", 82 | @"bounds", 83 | @"font", 84 | @"frame", 85 | @"text", 86 | @"textAlignment", 87 | @"textContainerInset", 88 | @"textContainer.lineFragmentPadding", 89 | @"textContainer.exclusionPaths"]; 90 | } 91 | 92 | 93 | #pragma mark - Properties 94 | #pragma mark `placeholderTextView` 95 | 96 | - (UITextView *)placeholderTextView { 97 | UITextView *textView = objc_getAssociatedObject(self, @selector(placeholderTextView)); 98 | if (!textView) { 99 | NSAttributedString *originalText = self.attributedText; 100 | self.text = @" "; // lazily set font of `UITextView`. 101 | self.attributedText = originalText; 102 | 103 | textView = [[UITextView alloc] init]; 104 | textView.backgroundColor = [UIColor clearColor]; 105 | textView.textColor = [self.class defaultPlaceholderColor]; 106 | textView.userInteractionEnabled = NO; 107 | textView.isAccessibilityElement = NO; 108 | objc_setAssociatedObject(self, @selector(placeholderTextView), textView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 109 | 110 | self.needsUpdateFont = YES; 111 | [self updatePlaceholderTextView]; 112 | self.needsUpdateFont = NO; 113 | 114 | [[NSNotificationCenter defaultCenter] addObserver:self 115 | selector:@selector(updatePlaceholderTextView) 116 | name:UITextViewTextDidChangeNotification 117 | object:self]; 118 | 119 | for (NSString *key in self.class.observingKeys) { 120 | [self addObserver:self forKeyPath:key options:NSKeyValueObservingOptionNew context:nil]; 121 | } 122 | } 123 | return textView; 124 | } 125 | 126 | 127 | #pragma mark `placeholder` 128 | 129 | - (NSString *)placeholder { 130 | return self.placeholderTextView.text; 131 | } 132 | 133 | - (void)setPlaceholder:(NSString *)placeholder { 134 | self.placeholderTextView.text = placeholder; 135 | [self updatePlaceholderTextView]; 136 | } 137 | 138 | - (NSAttributedString *)attributedPlaceholder { 139 | return self.placeholderTextView.attributedText; 140 | } 141 | 142 | - (void)setAttributedPlaceholder:(NSAttributedString *)attributedPlaceholder { 143 | self.placeholderTextView.attributedText = attributedPlaceholder; 144 | [self updatePlaceholderTextView]; 145 | } 146 | 147 | #pragma mark `placeholderColor` 148 | 149 | - (UIColor *)placeholderColor { 150 | return self.placeholderTextView.textColor; 151 | } 152 | 153 | - (void)setPlaceholderColor:(UIColor *)placeholderColor { 154 | self.placeholderTextView.textColor = placeholderColor; 155 | } 156 | 157 | 158 | #pragma mark `needsUpdateFont` 159 | 160 | - (BOOL)needsUpdateFont { 161 | return [objc_getAssociatedObject(self, @selector(needsUpdateFont)) boolValue]; 162 | } 163 | 164 | - (void)setNeedsUpdateFont:(BOOL)needsUpdate { 165 | objc_setAssociatedObject(self, @selector(needsUpdateFont), @(needsUpdate), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 166 | } 167 | 168 | 169 | #pragma mark - KVO 170 | 171 | - (void)observeValueForKeyPath:(NSString *)keyPath 172 | ofObject:(id)object 173 | change:(NSDictionary *)change 174 | context:(void *)context { 175 | if ([keyPath isEqualToString:@"font"]) { 176 | self.needsUpdateFont = (change[NSKeyValueChangeNewKey] != nil); 177 | } 178 | [self updatePlaceholderTextView]; 179 | } 180 | 181 | 182 | #pragma mark - Update 183 | 184 | - (void)updatePlaceholderTextView { 185 | if (self.text.length) { 186 | [self.placeholderTextView removeFromSuperview]; 187 | self.accessibilityValue = self.text; 188 | } else { 189 | [self insertSubview:self.placeholderTextView atIndex:0]; 190 | self.accessibilityValue = self.placeholder; 191 | } 192 | 193 | if (self.needsUpdateFont) { 194 | self.placeholderTextView.font = self.font; 195 | self.needsUpdateFont = NO; 196 | } 197 | if (self.placeholderTextView.attributedText.length == 0) { 198 | self.placeholderTextView.textAlignment = self.textAlignment; 199 | } 200 | self.placeholderTextView.textContainer.exclusionPaths = self.textContainer.exclusionPaths; 201 | self.placeholderTextView.textContainerInset = self.textContainerInset; 202 | self.placeholderTextView.textContainer.lineFragmentPadding = self.textContainer.lineFragmentPadding; 203 | self.placeholderTextView.frame = self.bounds; 204 | } 205 | 206 | @end 207 | -------------------------------------------------------------------------------- /Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Supporting Files/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module UITextView_Placeholder { 2 | umbrella header "UITextView+Placeholder.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Tests.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | import XCTest 24 | @testable import UITextView_Placeholder 25 | 26 | class Tests: XCTestCase { 27 | 28 | var textView: UITextView! 29 | 30 | // MARK: Setup 31 | 32 | override func setUp() { 33 | super.setUp() 34 | self.textView = UITextView() 35 | } 36 | 37 | 38 | // MARK: Basic Tests 39 | 40 | func testPlaceholderText() { 41 | self.textView.placeholder = "Hello" 42 | XCTAssertEqual(self.textView.placeholderTextView.text, "Hello") 43 | self.textView.placeholder = nil 44 | XCTAssertEqual(self.textView.placeholderTextView.text.count, 0) 45 | } 46 | 47 | func testAttributedPlaceholder() { 48 | let attributedPlaceholder = attributedString("Hello", .bold(26)) 49 | self.textView.attributedPlaceholder = attributedPlaceholder 50 | XCTAssertEqual(self.textView.attributedPlaceholder, attributedPlaceholder) 51 | } 52 | 53 | func testplaceholderTextViewHasSuperviewWhileNotEditing() { 54 | self.textView.placeholder = "Placeholder" 55 | XCTAssertEqual(self.textView.placeholderTextView.superview, self.textView) 56 | } 57 | 58 | func testplaceholderTextViewHasNoSuperviewWhileEditing() { 59 | self.textView.text = "ABC" 60 | self.textView.placeholder = "Placeholder" 61 | XCTAssertNil(self.textView.placeholderTextView.superview) 62 | } 63 | 64 | 65 | // MARK: Fonts 66 | 67 | func testSetFont_beforePlaceholder() { 68 | self.textView.font = UIFont.systemFont(ofSize: 34) 69 | self.textView.placeholder = "Hello" 70 | XCTAssertEqual(self.textView.placeholderTextView.text, "Hello") 71 | XCTAssertEqual(self.textView.placeholderTextView.font, UIFont.systemFont(ofSize: 34)) 72 | } 73 | 74 | func testSetFont_afterPlaceholder() { 75 | self.textView.placeholder = "Hello" 76 | self.textView.font = UIFont.systemFont(ofSize: 34) 77 | XCTAssertEqual(self.textView.placeholderTextView.text, "Hello") 78 | XCTAssertEqual(self.textView.placeholderTextView.font, UIFont.systemFont(ofSize: 34)) 79 | } 80 | 81 | func testSetFont_beforeAttributedPlaceholder() { 82 | let attributedPlaceholder = attributedString("Hello", .bold(26)) 83 | self.textView.font = UIFont.systemFont(ofSize: 34) 84 | self.textView.attributedPlaceholder = attributedPlaceholder 85 | XCTAssertEqual(self.textView.attributedPlaceholder, attributedPlaceholder) 86 | } 87 | 88 | func testSetFont_afterAttributedPlaceholderFont() { 89 | let attributedPlaceholder = attributedString("Hello", .bold(26)) 90 | self.textView.attributedPlaceholder = attributedPlaceholder 91 | self.textView.font = UIFont.systemFont(ofSize: 34) 92 | XCTAssertEqual(self.textView.attributedPlaceholder, attributedString("Hello", .normal(34))) 93 | } 94 | 95 | 96 | // MARK: Text 97 | 98 | func testSetPlaceholderBeforeText() { 99 | self.textView.font = UIFont.systemFont(ofSize: 32) 100 | self.textView.placeholder = "Placeholder text..." 101 | self.textView.text = "Hello, world!" 102 | XCTAssertEqual(self.textView.placeholderTextView.font, UIFont.systemFont(ofSize: 32)) 103 | } 104 | 105 | func testSetPlaceholderAfterText() { 106 | self.textView.font = UIFont.boldSystemFont(ofSize: 30) 107 | self.textView.text = "Hello, world!" 108 | self.textView.placeholder = "Placeholder text..." 109 | XCTAssertEqual(self.textView.placeholderTextView.font, UIFont.boldSystemFont(ofSize: 30)) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Tests/Utils.swift: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2014 Suyeol Jeon (http:xoul.kr) 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 | 23 | import UIKit 24 | 25 | enum Font { 26 | case normal(CGFloat) 27 | case bold(CGFloat) 28 | 29 | var font: UIFont { 30 | switch self { 31 | case .normal(let size): return UIFont.systemFont(ofSize: size) 32 | case .bold(let size): return UIFont.boldSystemFont(ofSize: size) 33 | } 34 | } 35 | } 36 | 37 | func attributedString(_ string: String, _ font: Font) -> NSAttributedString { 38 | return NSAttributedString(string: string, attributes: [.font: font.font]) 39 | } 40 | -------------------------------------------------------------------------------- /UITextView+Placeholder.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "UITextView+Placeholder" 3 | s.version = "1.4.0" 4 | s.summary = "A missing placeholder for UITextView." 5 | s.homepage = "https://github.com/devxoul/UITextView-Placeholder" 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { "devxoul" => "devxoul@gmail.com" } 8 | s.source = { :git => "https://github.com/devxoul/UITextView-Placeholder.git", 9 | :tag => "#{s.version}" } 10 | s.platform = :ios, '6.0' 11 | s.requires_arc = true 12 | s.source_files = 'Sources/UITextView+Placeholder.{h,m}' 13 | s.frameworks = 'Foundation', 'UIKit' 14 | end 15 | -------------------------------------------------------------------------------- /UITextView+Placeholder.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0309F8BD1CBCC84400062D3B /* UITextView+Placeholder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0309F8BB1CBCC84400062D3B /* UITextView+Placeholder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 0309F8BE1CBCC84400062D3B /* UITextView+Placeholder.m in Sources */ = {isa = PBXBuildFile; fileRef = 0309F8BC1CBCC84400062D3B /* UITextView+Placeholder.m */; }; 12 | 0309F8CA1CBCC8A700062D3B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0309F8C91CBCC8A700062D3B /* main.m */; }; 13 | 0309F8CD1CBCC8A700062D3B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0309F8CC1CBCC8A700062D3B /* AppDelegate.m */; }; 14 | 0309F8D01CBCC8A700062D3B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0309F8CF1CBCC8A700062D3B /* ViewController.m */; }; 15 | 0309F8D31CBCC8A700062D3B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0309F8D11CBCC8A700062D3B /* Main.storyboard */; }; 16 | 0309F8D51CBCC8A700062D3B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0309F8D41CBCC8A700062D3B /* Assets.xcassets */; }; 17 | 0309F8D81CBCC8A700062D3B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0309F8D61CBCC8A700062D3B /* LaunchScreen.storyboard */; }; 18 | 0309F8DD1CBCC91300062D3B /* UITextView_Placeholder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0309F8AD1CBCC7FF00062D3B /* UITextView_Placeholder.framework */; }; 19 | 0309F8DE1CBCC91300062D3B /* UITextView_Placeholder.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0309F8AD1CBCC7FF00062D3B /* UITextView_Placeholder.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 20 | 0309F8F81CBCCD6500062D3B /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0309F8F71CBCCD6500062D3B /* Tests.swift */; }; 21 | 0309F9001CBCCD8D00062D3B /* UITextView_Placeholder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0309F8AD1CBCC7FF00062D3B /* UITextView_Placeholder.framework */; }; 22 | 0309F9041CBCEE4700062D3B /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0309F9031CBCEE4700062D3B /* Utils.swift */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 0309F8DF1CBCC91300062D3B /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 0309F8A41CBCC7FF00062D3B /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 0309F8AC1CBCC7FF00062D3B; 31 | remoteInfo = "UITextView+Placeholder"; 32 | }; 33 | 0309F8FB1CBCCD6500062D3B /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 0309F8A41CBCC7FF00062D3B /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 0309F8AC1CBCC7FF00062D3B; 38 | remoteInfo = "UITextView+Placeholder"; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXCopyFilesBuildPhase section */ 43 | 0309F8E11CBCC91300062D3B /* Embed Frameworks */ = { 44 | isa = PBXCopyFilesBuildPhase; 45 | buildActionMask = 2147483647; 46 | dstPath = ""; 47 | dstSubfolderSpec = 10; 48 | files = ( 49 | 0309F8DE1CBCC91300062D3B /* UITextView_Placeholder.framework in Embed Frameworks */, 50 | ); 51 | name = "Embed Frameworks"; 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXCopyFilesBuildPhase section */ 55 | 56 | /* Begin PBXFileReference section */ 57 | 0309F8AD1CBCC7FF00062D3B /* UITextView_Placeholder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UITextView_Placeholder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 0309F8BB1CBCC84400062D3B /* UITextView+Placeholder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITextView+Placeholder.h"; sourceTree = ""; }; 59 | 0309F8BC1CBCC84400062D3B /* UITextView+Placeholder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextView+Placeholder.m"; sourceTree = ""; }; 60 | 0309F8C01CBCC85900062D3B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 0309F8C61CBCC8A700062D3B /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 0309F8C91CBCC8A700062D3B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 63 | 0309F8CB1CBCC8A700062D3B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 64 | 0309F8CC1CBCC8A700062D3B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 65 | 0309F8CE1CBCC8A700062D3B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 66 | 0309F8CF1CBCC8A700062D3B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 67 | 0309F8D21CBCC8A700062D3B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 68 | 0309F8D41CBCC8A700062D3B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 69 | 0309F8D71CBCC8A700062D3B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 70 | 0309F8D91CBCC8A700062D3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 71 | 0309F8F51CBCCD6500062D3B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | 0309F8F71CBCCD6500062D3B /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; 73 | 0309F9031CBCEE4700062D3B /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | 0309F8A91CBCC7FF00062D3B /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 0309F8C31CBCC8A700062D3B /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | 0309F8DD1CBCC91300062D3B /* UITextView_Placeholder.framework in Frameworks */, 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | 0309F8F21CBCCD6500062D3B /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | 0309F9001CBCCD8D00062D3B /* UITextView_Placeholder.framework in Frameworks */, 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | /* End PBXFrameworksBuildPhase section */ 101 | 102 | /* Begin PBXGroup section */ 103 | 0309F8A31CBCC7FF00062D3B = { 104 | isa = PBXGroup; 105 | children = ( 106 | 0309F8BA1CBCC84400062D3B /* Sources */, 107 | 0309F8C71CBCC8A700062D3B /* Demo */, 108 | 0309F8BF1CBCC85900062D3B /* Supporting Files */, 109 | 0309F8F61CBCCD6500062D3B /* Tests */, 110 | 0309F8AE1CBCC7FF00062D3B /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | 0309F8AE1CBCC7FF00062D3B /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 0309F8AD1CBCC7FF00062D3B /* UITextView_Placeholder.framework */, 118 | 0309F8C61CBCC8A700062D3B /* Demo.app */, 119 | 0309F8F51CBCCD6500062D3B /* Tests.xctest */, 120 | ); 121 | name = Products; 122 | sourceTree = ""; 123 | }; 124 | 0309F8BA1CBCC84400062D3B /* Sources */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 0309F8BB1CBCC84400062D3B /* UITextView+Placeholder.h */, 128 | 0309F8BC1CBCC84400062D3B /* UITextView+Placeholder.m */, 129 | ); 130 | path = Sources; 131 | sourceTree = ""; 132 | }; 133 | 0309F8BF1CBCC85900062D3B /* Supporting Files */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 0309F8C01CBCC85900062D3B /* Info.plist */, 137 | ); 138 | path = "Supporting Files"; 139 | sourceTree = ""; 140 | }; 141 | 0309F8C71CBCC8A700062D3B /* Demo */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 0309F8CB1CBCC8A700062D3B /* AppDelegate.h */, 145 | 0309F8CC1CBCC8A700062D3B /* AppDelegate.m */, 146 | 0309F8CE1CBCC8A700062D3B /* ViewController.h */, 147 | 0309F8CF1CBCC8A700062D3B /* ViewController.m */, 148 | 0309F8D11CBCC8A700062D3B /* Main.storyboard */, 149 | 0309F8D41CBCC8A700062D3B /* Assets.xcassets */, 150 | 0309F8D61CBCC8A700062D3B /* LaunchScreen.storyboard */, 151 | 0309F8D91CBCC8A700062D3B /* Info.plist */, 152 | 0309F8C81CBCC8A700062D3B /* Supporting Files */, 153 | ); 154 | path = Demo; 155 | sourceTree = ""; 156 | }; 157 | 0309F8C81CBCC8A700062D3B /* Supporting Files */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 0309F8C91CBCC8A700062D3B /* main.m */, 161 | ); 162 | name = "Supporting Files"; 163 | sourceTree = ""; 164 | }; 165 | 0309F8F61CBCCD6500062D3B /* Tests */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 0309F8F71CBCCD6500062D3B /* Tests.swift */, 169 | 0309F9031CBCEE4700062D3B /* Utils.swift */, 170 | ); 171 | path = Tests; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXGroup section */ 175 | 176 | /* Begin PBXHeadersBuildPhase section */ 177 | 0309F8AA1CBCC7FF00062D3B /* Headers */ = { 178 | isa = PBXHeadersBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | 0309F8BD1CBCC84400062D3B /* UITextView+Placeholder.h in Headers */, 182 | ); 183 | runOnlyForDeploymentPostprocessing = 0; 184 | }; 185 | /* End PBXHeadersBuildPhase section */ 186 | 187 | /* Begin PBXNativeTarget section */ 188 | 0309F8AC1CBCC7FF00062D3B /* UITextView+Placeholder */ = { 189 | isa = PBXNativeTarget; 190 | buildConfigurationList = 0309F8B51CBCC7FF00062D3B /* Build configuration list for PBXNativeTarget "UITextView+Placeholder" */; 191 | buildPhases = ( 192 | 0309F8A81CBCC7FF00062D3B /* Sources */, 193 | 0309F8A91CBCC7FF00062D3B /* Frameworks */, 194 | 0309F8AA1CBCC7FF00062D3B /* Headers */, 195 | 0309F8AB1CBCC7FF00062D3B /* Resources */, 196 | ); 197 | buildRules = ( 198 | ); 199 | dependencies = ( 200 | ); 201 | name = "UITextView+Placeholder"; 202 | productName = "UITextView+Placeholder"; 203 | productReference = 0309F8AD1CBCC7FF00062D3B /* UITextView_Placeholder.framework */; 204 | productType = "com.apple.product-type.framework"; 205 | }; 206 | 0309F8C51CBCC8A700062D3B /* Demo */ = { 207 | isa = PBXNativeTarget; 208 | buildConfigurationList = 0309F8DA1CBCC8A700062D3B /* Build configuration list for PBXNativeTarget "Demo" */; 209 | buildPhases = ( 210 | 0309F8C21CBCC8A700062D3B /* Sources */, 211 | 0309F8C31CBCC8A700062D3B /* Frameworks */, 212 | 0309F8C41CBCC8A700062D3B /* Resources */, 213 | 0309F8E11CBCC91300062D3B /* Embed Frameworks */, 214 | ); 215 | buildRules = ( 216 | ); 217 | dependencies = ( 218 | 0309F8E01CBCC91300062D3B /* PBXTargetDependency */, 219 | ); 220 | name = Demo; 221 | productName = Demo; 222 | productReference = 0309F8C61CBCC8A700062D3B /* Demo.app */; 223 | productType = "com.apple.product-type.application"; 224 | }; 225 | 0309F8F41CBCCD6500062D3B /* Tests */ = { 226 | isa = PBXNativeTarget; 227 | buildConfigurationList = 0309F8FF1CBCCD6500062D3B /* Build configuration list for PBXNativeTarget "Tests" */; 228 | buildPhases = ( 229 | 0309F8F11CBCCD6500062D3B /* Sources */, 230 | 0309F8F21CBCCD6500062D3B /* Frameworks */, 231 | 0309F8F31CBCCD6500062D3B /* Resources */, 232 | ); 233 | buildRules = ( 234 | ); 235 | dependencies = ( 236 | 0309F8FC1CBCCD6500062D3B /* PBXTargetDependency */, 237 | ); 238 | name = Tests; 239 | productName = Tests; 240 | productReference = 0309F8F51CBCCD6500062D3B /* Tests.xctest */; 241 | productType = "com.apple.product-type.bundle.unit-test"; 242 | }; 243 | /* End PBXNativeTarget section */ 244 | 245 | /* Begin PBXProject section */ 246 | 0309F8A41CBCC7FF00062D3B /* Project object */ = { 247 | isa = PBXProject; 248 | attributes = { 249 | LastSwiftUpdateCheck = 0730; 250 | LastUpgradeCheck = 1020; 251 | ORGANIZATIONNAME = "Suyeol Jeon"; 252 | TargetAttributes = { 253 | 0309F8AC1CBCC7FF00062D3B = { 254 | CreatedOnToolsVersion = 7.3; 255 | }; 256 | 0309F8C51CBCC8A700062D3B = { 257 | CreatedOnToolsVersion = 7.3; 258 | }; 259 | 0309F8F41CBCCD6500062D3B = { 260 | CreatedOnToolsVersion = 7.3; 261 | }; 262 | }; 263 | }; 264 | buildConfigurationList = 0309F8A71CBCC7FF00062D3B /* Build configuration list for PBXProject "UITextView+Placeholder" */; 265 | compatibilityVersion = "Xcode 3.2"; 266 | developmentRegion = en; 267 | hasScannedForEncodings = 0; 268 | knownRegions = ( 269 | en, 270 | Base, 271 | ); 272 | mainGroup = 0309F8A31CBCC7FF00062D3B; 273 | productRefGroup = 0309F8AE1CBCC7FF00062D3B /* Products */; 274 | projectDirPath = ""; 275 | projectRoot = ""; 276 | targets = ( 277 | 0309F8AC1CBCC7FF00062D3B /* UITextView+Placeholder */, 278 | 0309F8C51CBCC8A700062D3B /* Demo */, 279 | 0309F8F41CBCCD6500062D3B /* Tests */, 280 | ); 281 | }; 282 | /* End PBXProject section */ 283 | 284 | /* Begin PBXResourcesBuildPhase section */ 285 | 0309F8AB1CBCC7FF00062D3B /* Resources */ = { 286 | isa = PBXResourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | 0309F8C41CBCC8A700062D3B /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 0309F8D81CBCC8A700062D3B /* LaunchScreen.storyboard in Resources */, 297 | 0309F8D51CBCC8A700062D3B /* Assets.xcassets in Resources */, 298 | 0309F8D31CBCC8A700062D3B /* Main.storyboard in Resources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | 0309F8F31CBCCD6500062D3B /* Resources */ = { 303 | isa = PBXResourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXResourcesBuildPhase section */ 310 | 311 | /* Begin PBXSourcesBuildPhase section */ 312 | 0309F8A81CBCC7FF00062D3B /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | 0309F8BE1CBCC84400062D3B /* UITextView+Placeholder.m in Sources */, 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | 0309F8C21CBCC8A700062D3B /* Sources */ = { 321 | isa = PBXSourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | 0309F8D01CBCC8A700062D3B /* ViewController.m in Sources */, 325 | 0309F8CD1CBCC8A700062D3B /* AppDelegate.m in Sources */, 326 | 0309F8CA1CBCC8A700062D3B /* main.m in Sources */, 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | 0309F8F11CBCCD6500062D3B /* Sources */ = { 331 | isa = PBXSourcesBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | 0309F8F81CBCCD6500062D3B /* Tests.swift in Sources */, 335 | 0309F9041CBCEE4700062D3B /* Utils.swift in Sources */, 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | }; 339 | /* End PBXSourcesBuildPhase section */ 340 | 341 | /* Begin PBXTargetDependency section */ 342 | 0309F8E01CBCC91300062D3B /* PBXTargetDependency */ = { 343 | isa = PBXTargetDependency; 344 | target = 0309F8AC1CBCC7FF00062D3B /* UITextView+Placeholder */; 345 | targetProxy = 0309F8DF1CBCC91300062D3B /* PBXContainerItemProxy */; 346 | }; 347 | 0309F8FC1CBCCD6500062D3B /* PBXTargetDependency */ = { 348 | isa = PBXTargetDependency; 349 | target = 0309F8AC1CBCC7FF00062D3B /* UITextView+Placeholder */; 350 | targetProxy = 0309F8FB1CBCCD6500062D3B /* PBXContainerItemProxy */; 351 | }; 352 | /* End PBXTargetDependency section */ 353 | 354 | /* Begin PBXVariantGroup section */ 355 | 0309F8D11CBCC8A700062D3B /* Main.storyboard */ = { 356 | isa = PBXVariantGroup; 357 | children = ( 358 | 0309F8D21CBCC8A700062D3B /* Base */, 359 | ); 360 | name = Main.storyboard; 361 | sourceTree = ""; 362 | }; 363 | 0309F8D61CBCC8A700062D3B /* LaunchScreen.storyboard */ = { 364 | isa = PBXVariantGroup; 365 | children = ( 366 | 0309F8D71CBCC8A700062D3B /* Base */, 367 | ); 368 | name = LaunchScreen.storyboard; 369 | sourceTree = ""; 370 | }; 371 | /* End PBXVariantGroup section */ 372 | 373 | /* Begin XCBuildConfiguration section */ 374 | 0309F8B31CBCC7FF00062D3B /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ALWAYS_SEARCH_USER_PATHS = NO; 378 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 379 | CLANG_ANALYZER_NONNULL = YES; 380 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 381 | CLANG_CXX_LIBRARY = "libc++"; 382 | CLANG_ENABLE_MODULES = YES; 383 | CLANG_ENABLE_OBJC_ARC = YES; 384 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 385 | CLANG_WARN_BOOL_CONVERSION = YES; 386 | CLANG_WARN_COMMA = YES; 387 | CLANG_WARN_CONSTANT_CONVERSION = YES; 388 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INFINITE_RECURSION = YES; 393 | CLANG_WARN_INT_CONVERSION = YES; 394 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 395 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 396 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 397 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 398 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 399 | CLANG_WARN_STRICT_PROTOTYPES = YES; 400 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 401 | CLANG_WARN_UNREACHABLE_CODE = YES; 402 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 403 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 404 | COPY_PHASE_STRIP = NO; 405 | CURRENT_PROJECT_VERSION = 1; 406 | DEBUG_INFORMATION_FORMAT = dwarf; 407 | ENABLE_STRICT_OBJC_MSGSEND = YES; 408 | ENABLE_TESTABILITY = YES; 409 | GCC_C_LANGUAGE_STANDARD = gnu99; 410 | GCC_DYNAMIC_NO_PIC = NO; 411 | GCC_NO_COMMON_BLOCKS = YES; 412 | GCC_OPTIMIZATION_LEVEL = 0; 413 | GCC_PREPROCESSOR_DEFINITIONS = ( 414 | "DEBUG=1", 415 | "$(inherited)", 416 | ); 417 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 418 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 419 | GCC_WARN_UNDECLARED_SELECTOR = YES; 420 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 421 | GCC_WARN_UNUSED_FUNCTION = YES; 422 | GCC_WARN_UNUSED_VARIABLE = YES; 423 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 424 | MTL_ENABLE_DEBUG_INFO = YES; 425 | ONLY_ACTIVE_ARCH = YES; 426 | SDKROOT = iphoneos; 427 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 428 | SWIFT_VERSION = 4.0; 429 | TARGETED_DEVICE_FAMILY = "1,2"; 430 | VERSIONING_SYSTEM = "apple-generic"; 431 | VERSION_INFO_PREFIX = ""; 432 | }; 433 | name = Debug; 434 | }; 435 | 0309F8B41CBCC7FF00062D3B /* Release */ = { 436 | isa = XCBuildConfiguration; 437 | buildSettings = { 438 | ALWAYS_SEARCH_USER_PATHS = NO; 439 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 440 | CLANG_ANALYZER_NONNULL = YES; 441 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 442 | CLANG_CXX_LIBRARY = "libc++"; 443 | CLANG_ENABLE_MODULES = YES; 444 | CLANG_ENABLE_OBJC_ARC = YES; 445 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 446 | CLANG_WARN_BOOL_CONVERSION = YES; 447 | CLANG_WARN_COMMA = YES; 448 | CLANG_WARN_CONSTANT_CONVERSION = YES; 449 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 450 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 451 | CLANG_WARN_EMPTY_BODY = YES; 452 | CLANG_WARN_ENUM_CONVERSION = YES; 453 | CLANG_WARN_INFINITE_RECURSION = YES; 454 | CLANG_WARN_INT_CONVERSION = YES; 455 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 456 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 457 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 458 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 459 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 460 | CLANG_WARN_STRICT_PROTOTYPES = YES; 461 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 462 | CLANG_WARN_UNREACHABLE_CODE = YES; 463 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 464 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 465 | COPY_PHASE_STRIP = NO; 466 | CURRENT_PROJECT_VERSION = 1; 467 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 468 | ENABLE_NS_ASSERTIONS = NO; 469 | ENABLE_STRICT_OBJC_MSGSEND = YES; 470 | GCC_C_LANGUAGE_STANDARD = gnu99; 471 | GCC_NO_COMMON_BLOCKS = YES; 472 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 473 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 474 | GCC_WARN_UNDECLARED_SELECTOR = YES; 475 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 476 | GCC_WARN_UNUSED_FUNCTION = YES; 477 | GCC_WARN_UNUSED_VARIABLE = YES; 478 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 479 | MTL_ENABLE_DEBUG_INFO = NO; 480 | SDKROOT = iphoneos; 481 | SWIFT_COMPILATION_MODE = wholemodule; 482 | SWIFT_VERSION = 4.0; 483 | TARGETED_DEVICE_FAMILY = "1,2"; 484 | VALIDATE_PRODUCT = YES; 485 | VERSIONING_SYSTEM = "apple-generic"; 486 | VERSION_INFO_PREFIX = ""; 487 | }; 488 | name = Release; 489 | }; 490 | 0309F8B61CBCC7FF00062D3B /* Debug */ = { 491 | isa = XCBuildConfiguration; 492 | buildSettings = { 493 | CODE_SIGN_IDENTITY = ""; 494 | DEFINES_MODULE = YES; 495 | DYLIB_COMPATIBILITY_VERSION = 1; 496 | DYLIB_CURRENT_VERSION = 1; 497 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 498 | INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; 499 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 500 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 502 | MODULEMAP_FILE = "Supporting Files/module.modulemap"; 503 | PRODUCT_BUNDLE_IDENTIFIER = "kr.xoul.UITextView-Placeholder"; 504 | PRODUCT_NAME = UITextView_Placeholder; 505 | SKIP_INSTALL = YES; 506 | }; 507 | name = Debug; 508 | }; 509 | 0309F8B71CBCC7FF00062D3B /* Release */ = { 510 | isa = XCBuildConfiguration; 511 | buildSettings = { 512 | CODE_SIGN_IDENTITY = ""; 513 | DEFINES_MODULE = YES; 514 | DYLIB_COMPATIBILITY_VERSION = 1; 515 | DYLIB_CURRENT_VERSION = 1; 516 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 517 | INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; 518 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 519 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 520 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 521 | MODULEMAP_FILE = "Supporting Files/module.modulemap"; 522 | PRODUCT_BUNDLE_IDENTIFIER = "kr.xoul.UITextView-Placeholder"; 523 | PRODUCT_NAME = UITextView_Placeholder; 524 | SKIP_INSTALL = YES; 525 | }; 526 | name = Release; 527 | }; 528 | 0309F8DB1CBCC8A700062D3B /* Debug */ = { 529 | isa = XCBuildConfiguration; 530 | buildSettings = { 531 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 532 | INFOPLIST_FILE = Demo/Info.plist; 533 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 534 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 535 | PRODUCT_BUNDLE_IDENTIFIER = kr.xoul.Demo; 536 | PRODUCT_NAME = "$(TARGET_NAME)"; 537 | }; 538 | name = Debug; 539 | }; 540 | 0309F8DC1CBCC8A700062D3B /* Release */ = { 541 | isa = XCBuildConfiguration; 542 | buildSettings = { 543 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 544 | INFOPLIST_FILE = Demo/Info.plist; 545 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 546 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 547 | PRODUCT_BUNDLE_IDENTIFIER = kr.xoul.Demo; 548 | PRODUCT_NAME = "$(TARGET_NAME)"; 549 | }; 550 | name = Release; 551 | }; 552 | 0309F8FD1CBCCD6500062D3B /* Debug */ = { 553 | isa = XCBuildConfiguration; 554 | buildSettings = { 555 | INFOPLIST_FILE = "Supporting Files/Info.plist"; 556 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 557 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 558 | PRODUCT_BUNDLE_IDENTIFIER = kr.xoul.Tests; 559 | PRODUCT_NAME = "$(TARGET_NAME)"; 560 | SWIFT_VERSION = 5.0; 561 | }; 562 | name = Debug; 563 | }; 564 | 0309F8FE1CBCCD6500062D3B /* Release */ = { 565 | isa = XCBuildConfiguration; 566 | buildSettings = { 567 | INFOPLIST_FILE = "Supporting Files/Info.plist"; 568 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 569 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 570 | PRODUCT_BUNDLE_IDENTIFIER = kr.xoul.Tests; 571 | PRODUCT_NAME = "$(TARGET_NAME)"; 572 | SWIFT_VERSION = 5.0; 573 | }; 574 | name = Release; 575 | }; 576 | /* End XCBuildConfiguration section */ 577 | 578 | /* Begin XCConfigurationList section */ 579 | 0309F8A71CBCC7FF00062D3B /* Build configuration list for PBXProject "UITextView+Placeholder" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 0309F8B31CBCC7FF00062D3B /* Debug */, 583 | 0309F8B41CBCC7FF00062D3B /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | 0309F8B51CBCC7FF00062D3B /* Build configuration list for PBXNativeTarget "UITextView+Placeholder" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | 0309F8B61CBCC7FF00062D3B /* Debug */, 592 | 0309F8B71CBCC7FF00062D3B /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | 0309F8DA1CBCC8A700062D3B /* Build configuration list for PBXNativeTarget "Demo" */ = { 598 | isa = XCConfigurationList; 599 | buildConfigurations = ( 600 | 0309F8DB1CBCC8A700062D3B /* Debug */, 601 | 0309F8DC1CBCC8A700062D3B /* Release */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | 0309F8FF1CBCCD6500062D3B /* Build configuration list for PBXNativeTarget "Tests" */ = { 607 | isa = XCConfigurationList; 608 | buildConfigurations = ( 609 | 0309F8FD1CBCCD6500062D3B /* Debug */, 610 | 0309F8FE1CBCCD6500062D3B /* Release */, 611 | ); 612 | defaultConfigurationIsVisible = 0; 613 | defaultConfigurationName = Release; 614 | }; 615 | /* End XCConfigurationList section */ 616 | }; 617 | rootObject = 0309F8A41CBCC7FF00062D3B /* Project object */; 618 | } 619 | -------------------------------------------------------------------------------- /UITextView+Placeholder.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UITextView+Placeholder.xcodeproj/xcshareddata/xcschemes/Demo.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 | -------------------------------------------------------------------------------- /UITextView+Placeholder.xcodeproj/xcshareddata/xcschemes/UITextView+Placeholder.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /UITextView+Placeholder.xcodeproj/xcuserdata/xoul.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Demo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | UITextView+Placeholder.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 0309F8AC1CBCC7FF00062D3B 21 | 22 | primary 23 | 24 | 25 | 0309F8C51CBCC8A700062D3B 26 | 27 | primary 28 | 29 | 30 | 0309F8E51CBCCB1F00062D3B 31 | 32 | primary 33 | 34 | 35 | 0309F8F41CBCCD6500062D3B 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | --------------------------------------------------------------------------------