Pratik Sodha
Pratik Sodha

Reputation: 3727

ios 13 - Custom SearchBar with UISearchBar _searchField not working

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.

Upvotes: 45

Views: 26968

Answers (12)

Rajan Maheshwari
Rajan Maheshwari

Reputation: 14571

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

Upvotes: 24

Anil Kumar
Anil Kumar

Reputation: 1984

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
        }
    }

Upvotes: 0

Tejas
Tejas

Reputation: 1048

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.

Upvotes: 9

Vipul Kumar
Vipul Kumar

Reputation: 961

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

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

Upvotes: 0

mohsin
mohsin

Reputation: 540

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

Upvotes: 3

inam
inam

Reputation: 533

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

Upvotes: 0

Sarabjit Singh
Sarabjit Singh

Reputation: 1824

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

Upvotes: 0

Syrota Roman
Syrota Roman

Reputation: 81

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

guard let searchField = searchBar.value(forKey: "searchField") as? UITextField else { return }

Upvotes: 7

Midhun
Midhun

Reputation: 2197

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
    }
}

Upvotes: 2

irvinstone
irvinstone

Reputation: 623

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
 }
}

Upvotes: 4

Daniel Ardeleanu
Daniel Ardeleanu

Reputation: 255

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

Upvotes: 22

Jordan H
Jordan H

Reputation: 55825

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

searchBar.searchTextField.backgroundColor = [UIColor blueColor];

Upvotes: 74

Related Questions