Search code examples
uitextfieldios13placeholder

iOS 13 - UITextField with Placeholder getting app crash


In iOS 13, I'm getting a crash when accessing the UITextField _placeholderLabel.textColor label key.

The key used to apply placeholder text color.

[textfield setValue:[UIColor whiteColor] forKeyPath:@"_placeholderLabel.textColor"];

"NSGenericException" - reason: "Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug"


Solution

  • You can do it by using runtime:

    add the following code to the bottom of placeholder setting

    Ivar ivar =  class_getInstanceVariable([UITextField class], "_placeholderLabel");
    UILabel *placeholderLabel = object_getIvar(textField, ivar);
    placeholderLabel.textColor = [UIColor whiteColor];
    

    At Xcode 11 beta2 ,this code is work ,but I don't know about GM version or official version.

    The complete code:

    • Objective-C Version
    
    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor grayColor];
        self.title = @"UITextField Demo";
    
        UITextField *textField = [UITextField new];
        textField.frame = CGRectMake(0, 100, 300, 50);
        textField.placeholder = @"UITextField Demo";
        [self.view addSubview:textField];
    
        Ivar ivar =  class_getInstanceVariable([UITextField class], "_placeholderLabel");
        UILabel *placeholderLabel = object_getIvar(textField, ivar);
    
        placeholderLabel.textColor = [UIColor whiteColor];
    }
    
    @end
    
    • Swift Version:
    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            let textField = UITextField()
            textField.frame = CGRect(x: 0, y: 100, width: 300, height: 50)
            textField.placeholder = "UITextField Demo"
            view.addSubview(textField)
    
            let iVar = class_getInstanceVariable(UITextField.self, "_placeholderLabel")!
            let placeholderLabel = object_getIvar(textField, iVar) as! UILabel
            placeholderLabel.textColor = .red
        }
    }
    

    2019/09/25 Update

    The above implementation can solve the problem ,but it not be advocated.

    The apps that use the private api maybe broken in the future.

    Please use new api :

    var attributedPlaceholder: NSAttributedString? { get set }
    

    Discussion

    This property is nil by default. If set, the placeholder string is drawn using system-defined color and the remaining style information (except the text color) of the attributed string. Assigning a new value to this property also replaces the value of the placeholder property with the same string data, albeit without any formatting information. Assigning a new value to this property does not affect any other style-related properties of the text field.

    The complete code:

    let textField = UITextField()
    textField.frame = CGRect(x: 0, y: 100, width: 300, height: 50)
    let placeholderString = NSAttributedString.init(string: "UITextField Demo", attributes: [NSAttributedString.Key.foregroundColor : UIColor.red])
    textField.attributedPlaceholder = placeholderString
    view.addSubview(textField)