0

特定の API が呼び出されると設定される配列があります。ただし、後でこの配列にアクセスしようとすると、再び空になります。

問題のクラスは次のようになります。

class SearchableLoginFormField: LoginFormField {
    
    weak var delegate: PopoverPresentableDelegate?
    var selectedObject: Selectable?
    let popoverType: PopoverType
    var sourceList = [Selectable]() {
        didSet {
            // Field set
        }
    }
    
    private lazy var selectionPopover: ContainerPopover = {
        let popover = LoginFormPopover(objectSelected: { object in
            self.selectedObject = object
            self.text = object.selectionName
            self.selectionPopover.dismiss(animated: true)
        }, popoverType: self.popoverType)
        return popover
    }()
    
    
    init(popoverType: PopoverType, fieldTitle: String, fieldIcon: UIImage?,
         colorScheme: UIColor?, returnAction: (() -> Void)?) {
        self.popoverType = popoverType
        
        super.init(fieldTitle: fieldTitle, fieldIcon: fieldIcon, colorScheme: colorScheme, returnAction: returnAction)
        configureFormField()
    }
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configureFormField() {
        textDidChangeAction = { [weak self] in
            /// We clear the selectedAirport each time user searches in field so that we know whether we need to trigger shouldEndEditingAction or not
            /// (which we only trigger if user ends action and selectedAirport is nil)
            self?.selectedObject = nil
            
            self?.configureField(with: I6TextInputKeyboardSettings(
                capitalization: .allCharacters,
                spellCheck: .no
            ))
            
            guard let self = self else { return }
            
            self.searchObjects(
                field: self,
                popover: self.selectionPopover,
                sourceList: self.sourceList,
                dataPopover: self.selectionPopover)
        }
        
        self.shouldEndEditingAction = { [weak self] in
            if self?.selectedObject == nil {
                let filteredText = self?.text.replacingOccurrences(of: "-", with: "") // We remove the "-" if user has entered it so that reg can still be validated
                self?.text = filteredText ?? ""
                self?.verifyFieldInput()
            }
        }
    }
    
    private func searchObjects<T>(field: I6TextField, popover: ContainerPopover, sourceList: [T], dataPopover: ContainerPopover) {
        if field.text.isEmpty {
            dataPopover.dismiss(animated: true, completion: nil)
        } else {
            
            let filterCompletion: (Int) -> () = { count in
                dataPopover.sourceView = field
                
                // Present if needed
                let isPopoverPresented = dataPopover.isVisiblyPresented
                if (!dataPopover.isBeingPresented && !isPopoverPresented && count > 0) {
                    self.delegate?.presentPopover(popover: dataPopover)
                }
                
                if (isPopoverPresented || dataPopover.isBeingPresented) && count == 0 {
                    dataPopover.dismiss(animated: false, completion: nil)
                }
            }
            
            dataPopover.filterToSearchTerm(field.text.replacingOccurrences(of: "-", with: ""), objects: sourceList, completion:filterCompletion)
        }
    }
    
    private func verifyFieldInput() {
        let matchingList = sourceList.filter {
            $0.selectionName.lowercased() == self.text.lowercased()
        }
        if matchingList.count == 1 {
            self.text = matchingList[0].selectionName
            self.selectedObject = matchingList[0]
            self.hasError = false
        } else if matchingList.count > 1 {
            self.errorAlert(errorText: Strings.EHandshake.FlightLookupCustomisable.mulitpleMatches.localizedFormat(""))
        } else if matchingList.isEmpty {
            self.errorAlert(errorText: Strings.EHandshake.FlightLookupCustomisable.noSelectionMatches.localizedFormat(""))
        }
        delegate?.textInputValidated(popover: selectionPopover)
    }
}

私が注目している変数は、sourceList 変数です。

ここで、このオブジェクトが作成されるクラスで、次のように SearchableLoginFormField を宣言します。

lazy var iata: SearchableLoginFormField = {
    let field = SearchableLoginFormField(
        popoverType: .airport,
        fieldTitle: FlightLookupStrings.originAiportCode.localized,
        fieldIcon: UIImage.Login.origin,
        colorScheme: fieldColor,
        returnAction: nil)
    
    field.delegate = self
    
    validator.registerField(field, rules: [RequiredRule(message: ValidationStrings.aircraftRegistrationRequired.localized)])
    return field
}()

次に、次のデリゲート メソッドを使用して sourceList を設定します。

func airportsSet() {
        iata.sourceList = CoreDataObjectsManager.shared.airportsList
    }

これは、空港リストが API 呼び出しから取得されるときに呼び出されます。

ブレーク ポイントは、sourceList が正しく設定されていることを証明します。

  • airportsSet() デリゲート メソッドがヒットし、正しい空港リストが含まれている
  • SearchableLoginFormField の didSet メソッドが起動され、sourceList が Airports リストに正常に設定されます
  • フィールドの編集時に textField デリゲート メソッドをヒットすると、sourceList が空です。configureFormField() メソッドを sourceList の didSet に移動しようとしましたが、同じ結果になりました。

これがどのように設定されているように見えるが、再び空になるのか、私は本当に混乱しています。私は didSet にブレークポイントを保持していますが、他のものによって空に設定されることはありません。

スーパークラスには次の変数が含まれています。

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

および次の textFieldDelegate メソッド:

 open func textFieldDidChangeSelection(_ textField: UITextField) {
        didChangeSelectionAction?()
    }

したがって、configureFormField メソッドでは、トリガーされるこのデリゲート メソッドのアクションを適宜設定しています。この時点で、sourceList は空です。

フィールド自体は、次のようにメイン ディスプレイ viewController の viewDidLoad に追加されます。

stackView.add(arrangedSubviews: [number, reg, iata, submitButton, errorLabel])
4

0 に答える 0