DevB1
DevB1

Reputation: 1565

Swift - app crash when presenting popover as already presented

I have a textfield which, as user types in it, triggers a popover to be presented with a list of suggested values which the user can select from. Here is the textfield:

lazy var iata: CustomTextField = {
    let field = CustomTextField(
        title: Strings.originAiportCode.localized,
        placeholder: Strings.originAirportCodePlaceholder.localized,
        allowSpaceInput: false)
    
    field.configureField(with: TextInputKeyboardSettings(
        capitalization: .allCharacters,
        spellCheck: .no,
        returnKey: .done
    ))

    field.textDidChangeAction = { [weak self] in
        self?.search(field: field)
        self?.iataError.isHidden = true
    }
    
    field.shouldEndEditingAction = { [weak self] in
        self?.verifyTextfieldInput()
    }
    
    validator.registerField(field, rules: [RequiredRule(message: Strings.eHandshake.validation.iataRequired.localized)])
    
    return field
}()

didChangeAction is declared on the CustomTextField class as follows:

public var textDidChangeAction: (() -> Void)?

And this is passed in as a closure to the delegate method as follows:

public func textFieldDidChangeSelection(_ textField: UITextField) {
    textDidChangeAction?()
}

Here is the search method:

func search(field: CustomTextField) {
    if iata.text.isEmpty {
        popover.dismiss(animated: true, completion: nil)
    } else {
        
        let filterCompletion: (Int) -> () = { count in
            self.popover.sourceView = field
            
            // Present if needed
            let isPopoverPresented = self.popover.isVisiblyPresented
            if !isPopoverPresented && count > 0 {
                self.present(self.popover, animated: false, completion: nil)
            }
            
            if isPopoverPresented && count == 0 {
                self.popover.dismiss(animated: false, completion: nil)
            }
        }
        popover.filterToSearchTerm(field.text, objects: airportsList, completion:filterCompletion)
    }
}

Now this all works fine, excent if the user types too quickly into the textfield, in which case I get a crash and the following error:

Thread 1: "Application tried to present modally a view controller <project.ContainerPopover: 0x7fc736eabeb0> that is already being presented by <project.TabBarController: 0x7fc737838200>."

The list of data that this popover is receiving is pretty large, and clearly here the app is struggling as it is trying to present the vc when it is already there. However, I am stuck as to how to resolve this issue. Any help would be greatly appreciated.

Upvotes: 1

Views: 921

Answers (1)

DevB1
DevB1

Reputation: 1565

I appear to have solved this! I added a second check when presenting / dismissing:

(!self.popover.isBeingPresented && !self.popover.isVisiblyPresented)

It seems that this then ensures that the popover is neither being presented or is already visibly presented and this has resolved the issue

Upvotes: 2

Related Questions