45

Before Xcode-11-Beta (ios13) below code for custom searchbar value for key to get textField working fine. Now getting below crash log.

'NSGenericException', reason: 'Access to UISearchBar's _searchField ivar is prohibited. This is an application bug'

- (UITextField *)textField
{
 return [self valueForKey:@"_searchField"];
}

Any help appreciated.

Pratik Sodha
  • 3,679
  • 2
  • 19
  • 38
  • 1
    Never use `valueForKey:` to dig into the private subview structure of standard components. It was never valid and it always ends up breaking after a while. Work with the provide public API to do what you need. – rmaddy Jun 19 '19 at 15:19
  • 2
    @rmaddy Thanks for valuable feedback. But for customize UISearchBar already did it. So, now what's solutions. – Pratik Sodha Jun 20 '19 at 04:06
  • How i am understanding we don't have no one solution? – Genevios Sep 24 '19 at 06:33
  • @PratikSodha - check this [UISearchBarSearchField BackgroundView color](https://stackoverflow.com/questions/58127704/uisearchbarsearchfield-backgroundview-color) – Anbu.Karthik Oct 01 '19 at 07:26

12 Answers12

74

The SDK now provides UISearchBar.searchTextField so you can simply replace your private API implementation with the public API.

searchBar.searchTextField.backgroundColor = [UIColor blueColor];
Jordan H
  • 52,571
  • 37
  • 201
  • 351
  • but now the code doesn't compile on the previous xcode... any suggestions? – tomeron11 Jul 01 '19 at 08:47
  • And if you need to support iOS 12 and below but you're compiling with Xcode 11? – trusk Sep 19 '19 at 12:35
  • 14
    Wrap it in `if #available(iOS 13.0, *) {}` if you need to support earlier iOS versions. You won’t be able to use an older version of Xcode when building for iOS 13. – Jordan H Sep 19 '19 at 14:48
  • 1
    @JordanH you answer is ok , but i need to support xCode10 also anyone can help me – guru Nov 12 '19 at 12:34
24

If we want to support iOS 12 and earlier also while compiling with Xcode 11, then we can make an extension of UISearchBar where we can grab the textfield

extension UISearchBar {

    var textField : UITextField? {
        if #available(iOS 13.0, *) {
            return self.searchTextField
        } else { // Fallback on earlier versions
            for subview in subviews.first?.subviews ?? [] {
                if let textField = subview as? UITextField {
                    return textField
                }
            }
        }
        return nil
    }
}

USAGE

searchBar.textField?.font = UIFont.systemFont(ofSize: 15.0)

Here we can access all textField's properties and modify as per our needs in UISearchBar

There is a change in the view hierarchy. So by printing self.subviews[0]).subviews where self in UISearchBar


For iOS 12 and earlier

enter image description here

For iOS 13+

enter image description here

Along with UISearchBarBackground, now we have UISearchBarSearchContainerView and UISearchBarScopeContainerView whereas UISearchBarTextField is missing which is replaced by an extension provided by Apple in UISearchTextField class

extension UISearchBar {

    
    open var searchTextField: UISearchTextField { get }
}

So we can directly access searchBar.searchTextField in iOS 13 and above devices whereas it will lead to a crash if we try to access this property in iOS 12 and below OS devices.

The crash will be like this:

[UISearchBar searchTextField]: unrecognized selector sent to instance

enter image description here

Here is the Apple doc for this

mike vorisis
  • 2,786
  • 6
  • 40
  • 74
Rajan Maheshwari
  • 14,465
  • 6
  • 64
  • 98
  • 4
    Why does Xcode compiler not throw a warning when the iOS deployment target is set to < 13.0? Doesn't that happen usually when using an API that is not available on the deployment target version? And isn't that an essential job of a pre-compiler? – Manuel Oct 15 '19 at 15:32
  • Yes, and UISearchTextField IS marked in (e.g. typing "UISearchTextField * textfield" does give me a warning), but unfortunately, the property "searchBar.searchTextField" isn't marked as iOS13 only in the SDK. – mackworth Dec 06 '19 at 04:37
  • Crash on iOS 12 when I call becomeFirstResponder. – BSK-Team Jan 07 '20 at 15:12
  • 1
    Last time I checked (on Xcode 11.6) this property finally flagged as iOS 13+. It was about time... – gcharita Aug 11 '20 at 16:19
22

I had the same crash, with IOS 13 you don't need anymore the .value(forKey:)

Here is the line that caused the crash:

if let searchField = searchController.searchBar.value(forKey: "_searchField") as? UITextField {

And this was the fix:

let searchField = searchController.searchBar.searchTextField
AaoIi
  • 8,288
  • 6
  • 45
  • 87
9

Do this:

 var searchTextField: UITextField?
    if #available(iOS 13.0, *) {
        searchTextField = searchBar.searchTextField
    } else {
        if let searchField = searchBar.value(forKey: "searchField") as? UITextField {
            searchTextField = searchField
        }
    }

This will give you search bar's text field appropriately based on version check.

Tejas
  • 1,050
  • 12
  • 23
7

It still works for me with key "searchField" without underscore. Swift 5

guard let searchField = searchBar.value(forKey: "searchField") as? UITextField else { return }
Syrota Roman
  • 81
  • 1
  • 3
  • You have to do it this way if you are still using Xcode 10 since there is no "searchTextField" of SDK 10 UISearchBar. But when running under iOS 13 if will work. ` if #available(iOS 13.0, *) { return value(forKey: "searchField") as? UITextField } else { return value(forKey: "_searchField") as? UITextField ` – GilroyKilroy Oct 04 '19 at 01:15
  • is it a private API? will Apple reject the app to app store? – HamasN Feb 26 '21 at 07:50
4

If u want check iOS Version!

 if #available(iOS 13.0, *) {
    searchBar.searchTextField.clearButtonMode = .never
 } else {
    searchBar.textField.clearButtonMode = .never
 }

Dont Forget the extension:

extension UISearchBar {

 var textField : UITextField{
    return self.value(forKey: "_searchField") as! UITextField
 }
}
irvinstone
  • 593
  • 4
  • 10
  • Day saving answer! Hint: For me, it just worked without the underscore (`self.value(forKey: "searchField") as! UITextField`) – chocolate cake Nov 01 '19 at 10:07
3

Removed the "_" Underscore (while trying to access property) everywhere and it worked for all iOS versions.

mohsin
  • 530
  • 5
  • 24
2
extension UISearchBar {

    var textField : UITextField? {
        if #available(iOS 13.0, *) {
            return self.searchTextField
        } else {
            // Fallback on earlier versions
            return value(forKey: "_searchField") as? UITextField
        }
        return nil
    }
}
midhun p
  • 1,987
  • 18
  • 24
0

You can make check like this for iOS 11 and the earlier versions:

if #available(iOS 11, *){
            self.searchBar.placeholder = "Search by Name"
            self.searchBar.setSerchFont(textFont: UIFont(name:AppFontLato.Regular, size:14.0 * DeviceInfo.aspectRatio()))
            self.searchBar.setSerchTextcolor(color: Colors.black51)
        }
        else{
            if let searchTextField = self.searchBar.value(forKey: "_searchField") as? UITextField, let clearButton = searchTextField.value(forKey: "_clearButton") as? UIButton {
                searchTextField.placeholder = "Search by Name"
                searchTextField.font = UIFont(name:AppFontLato.Regular, size:14.0 * DeviceInfo.aspectRatio())
                searchTextField.textColor = Colors.black51
            }
        }

Hope this helps

Sarabjit Singh
  • 1,814
  • 1
  • 17
  • 28
0

I'm getting crash on cancel button value forkey. Is it possible to customize cancel button in iOS 13.enter image description here

Jiffin
  • 405
  • 5
  • 8
0

You can use this answer, working fine in iOS 13:-

https://stackoverflow.com/a/60503506/9863222

Vipul Kumar
  • 893
  • 9
  • 19
0
if #available(iOS 13.0, *) {
        self.searchBar.searchTextField.clearButtonMode = .never
    } else {
        // Fallback on earlier versions
        if let searchField = searchBar.value(forKey: "searchField") as? UITextField {
            searchField.clearButtonMode = .never
        }
    }
Anil Kumar
  • 1,830
  • 15
  • 24