iOS 13 - UITextField with Placeholder getting app crash
Asked Answered
M

15

27

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"

Messinger answered 10/6, 2019 at 13:2 Comment(6)
This issue exists in Xcode 11 GM seed too.Egmont
@SunilTarge check answers - https://mcmap.net/q/495835/-ios-13-uitextfield-with-placeholder-getting-app-crashMessinger
This isn't an "issue". Poking at internal implementation details is not allowed. You are violating App Store guidelines. Any "workaround" you attempt will be broken again soon. Stop.Law
@Messinger this freeze is only for simulator right ? as long as in the real device is not freezing then it is not an issue ? I am a beginner. I am confused because I don't have this freezing on real device but only in simulator. so if I don't care about simulator, I don't need to add the answers below right ? please really need your infoValadez
@Alexa289 Crash happens on the device - when you build an app with Xcode11 and iOS 13 Device. Crash not happens when app builds prior to Xcode11 and install in iOS 13 device.Messinger
@Messinger I have not tried on iOS 13, but I just tried on iOS 13.1.3 and I have not found a problem on my real device. just freezing on simulator. thats why I have a doubt either to add the code below (answer) or notValadez
F
28

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)

Fard answered 26/6, 2019 at 15:42 Comment(7)
Thanks. This 'bug' still exists in Beta 6. Wrote this in Swift and works there too.Retired
Why in the world would you recommend people do something that is obviously not allowed by posting another workaround? This is not OK, stop doing it. Your apps will be broken in the future.Law
@Law any solution how to change it then? ThanksAnuran
@Law Thank you for reminding me. I have updated my answer.Fard
@Fard it's clearly written in docs "If set, the placeholder string is drawn using system-defined color and the remaining style information (except the text color)". So you didn't answer the question in your updateDelenadeleon
Changing the placeholder text color is not supported by UIKit, but feedback requests for that are appreciated. You can use attributedPlaceholderString to change other style attributes of the placeholder text.Law
@Mikhail Maslo,Thank you for your remind,But When I build in Xcode 11 and launch in iOS 12.2 and iOS 13 Simulator, This worked for me.How strange this is!Fard
I
14

I think it's a bug from the XCode side and hopefully, they will fix this one on the next release. You can quickly fix this by Erase all Contents and Settings on the Simulator device.

enter image description here

Illinois answered 29/10, 2019 at 12:17 Comment(0)
M
12

Yes this problem is related with the Xcode version. I have Xcode 11.2.1 and i am facing same issue.

_placeholderLabel.textColor

if you are using it from storyboard as runtime var and getting issue so just remove "_"

like that enter image description here

after removing the "_" runtime Var start working

Mastoid answered 7/12, 2019 at 13:39 Comment(0)
D
11

Remove Underscore "_" and try this.

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

It should work for all versions!

Doncaster answered 18/11, 2019 at 6:1 Comment(1)
This worked for me in simulator and Xcode 11.2.1. ThanksIntangible
G
8

I did it this way :

Objc

NSMutableAttributedString *placeholderAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:searchField.attributedPlaceholder];
[placeholderAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, [placeholderAttributedString length])];
searchField.attributedPlaceholder = placeholderAttributedString;

Swift 5

var placeholderAttributedString = NSMutableAttributedString(attributedString: searchField.attributedPlaceholder)
    placeholderAttributedString.addAttribute(.foregroundColor, value: UIColor.red, range: NSRange(location: 0, length: placeholderAttributedString.length))
    searchField.attributedPlaceholder = placeholderAttributedString

It's a bit long but I have nothing better for the moment.

Graptolite answered 10/9, 2019 at 11:45 Comment(2)
Only acceptable answer for now, I am using Xcode 11.0Kg
Try to Erase all contents and settings on simulator :)Illinois
E
3

if you are using UITextView+Placeholder.h class please change below method Clean and build if issue persists

Objective C

+(UIColor *)defaultPlaceholderColor {

    static UIColor *color = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        UITextField *textField = [[UITextField alloc] init];
        textField.placeholder = @" ";
        //        color = [textField valueForKeyPath:@"_placeholderLabel.textColor"];
        Ivar ivar =  class_getInstanceVariable([UITextField class], "_placeholderLabel");
        UILabel *placeholderLabel = object_getIvar(textField, ivar);
        color =  placeholderLabel.textColor;

    });
    return color;

}
Entresol answered 9/10, 2019 at 4:25 Comment(0)
C
2

You can set UITextField placeholder text color, font using attributedPlaceholder method as follows :

NSString *text = [textField text];
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:text attributes:@{NSForegroundColorAttributeName: [UIColor redColor], NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Medium" size:14.0f]}];
Calamint answered 21/8, 2019 at 7:21 Comment(0)
S
2

"Erase all contents and settings"

This worked for me.

Snowslide answered 25/9, 2019 at 17:46 Comment(0)
T
2

I removed the var "_placeholderLabel" in the section "User Defined Runtime Attributes" enter image description here

Tenor answered 14/11, 2019 at 14:21 Comment(0)
P
2

Just replace _placeholderLabel with placeholderLabel

Pinson answered 16/1, 2020 at 15:17 Comment(0)
C
1

For IOS 13 you can set UITextField placeholder color by one line code.

Objective C

[textField setAttributedPlaceholder:[[NSAttributedString alloc] initWithString:@"PlaceHolder Text" attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}]];

In Swift 5

txtTitle.attributedPlaceholder = NSAttributedString(string:"PlaceHolder Text", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
Complacency answered 15/10, 2019 at 15:13 Comment(0)
B
0

- Swift Version

Add the following code to the bottom of placeholder setting:

    let iVar = class_getInstanceVariable(UITextField.self, "_placeholderLabel")!
    let placeholderLabel = object_getIvar(textField, iVar) as! UILabel

    placeholderLabel.textColor = .white

For example:

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .gray

    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 = .white
}
Behind answered 16/9, 2019 at 10:8 Comment(0)
P
0

Swift 5

Here is a correct Swift replacement of that property. Note that if you also change alignment of other properties for the text field, then you need to set these properties to placeholder's attributed text too. Usually only color and font are changed:

/// Set placeholder text color
/// - Parameter color: the color
func setPlaceholderColor(_ color: UIColor) {
    // Color
    var attributes: [NSAttributedString.Key: Any] = [.foregroundColor: color]
    var range = NSRange(location: 0, length: 1)

    // Font
    if let text = attributedText, text.length > 0, let attrs = attributedText?.attributes(at: 0, effectiveRange: &range), let font = attrs[.font] {
        attributes[.font] = font
    }
    else if let font = font {
        attributes[.font] = font
    }
    self.attributedPlaceholder = NSAttributedString(string: self.placeholder ?? "", attributes: attributes)
}
Pamplona answered 28/9, 2019 at 9:12 Comment(0)
F
0

FOR UISEARCHBAR PLACEHOLDER COLOR

Xcode 11.1

From iOS 13 onwards the SDK provides UISearchBar.searchTextField so we can use public API instead of private API. In the subclass of UISearchBar i have used this code to change the placeholder color

UITextField *textField = [self findSubviewOfClass:[UITextField class]];
textField.textColor = [UIColor whiteColor];
//textField.font = [UIFont fontWithName:@"HelveticaNeue-Regular" size:14.0f];

if (@available(iOS 13.0, *)) {
    self.searchTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName: [UIColor colorWithRed:0.8 green:0.82 blue:0.81 alpha:1]}];

}else {
    [textField setValue:[UIColor colorWithRed:0.8 green:0.82 blue:0.81 alpha:1] forKeyPath:@"_placeholderLabel.textColor"];

}
Francyne answered 15/10, 2019 at 6:42 Comment(0)
D
0

Remove "_" form "_placeholderLabel.textColor" try with "placeholderLabel.textColor".

Draughty answered 21/5, 2021 at 16:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.