// // TextFieldDelegateProxy.swift // KeymanEngine // // Created by Gabriel Wong on 2017-10-06. // Copyright © 2017 SIL International. All rights reserved. // // Proxies delegate messages for a TextField. // This allows the TextField to hook into these calls while allowing a developer to still // use the delegate as normal (albeit with a different name: 'keymanDelegate') // // This class is required because at the time of writing, setting a UITextField as it's // own delegate caused an infinite loop in Apple's code, repeatedly calling the selectionDidChange callback // See: http://lists.apple.com/archives/cocoa-dev/2010/Feb/msg01391.html import UIKit public protocol TextFieldDelegate: UITextFieldDelegate { } class TextFieldDelegateProxy: NSObject, UITextFieldDelegate { weak var keymanDelegate: TextFieldDelegate? private unowned let textField: UITextFieldDelegate init(_ textField: TextField) { self.textField = textField super.init() } // MARK: - UITextFieldDelegate // NOTE: Return values from the TextField hooks are ignored func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { _ = self.textField.textFieldShouldBeginEditing?(textField) return keymanDelegate?.textFieldShouldBeginEditing?(textField) ?? true } func textFieldDidBeginEditing(_ textField: UITextField) { self.textField.textFieldDidBeginEditing?(textField) keymanDelegate?.textFieldDidBeginEditing?(textField) } func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { _ = self.textField.textFieldShouldEndEditing?(textField) return keymanDelegate?.textFieldShouldEndEditing?(textField) ?? true } func textFieldDidEndEditing(_ textField: UITextField) { self.textField.textFieldDidEndEditing?(textField) keymanDelegate?.textFieldDidEndEditing?(textField) } @available(iOS 10.0, *) func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) { self.textField.textFieldDidEndEditing?(textField, reason: reason) keymanDelegate?.textFieldDidEndEditing?(textField, reason: reason) } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { _ = self.textField.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) return keymanDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true } func textFieldShouldClear(_ textField: UITextField) -> Bool { _ = self.textField.textFieldShouldClear?(textField) return keymanDelegate?.textFieldShouldClear?(textField) ?? true } func textFieldShouldReturn(_ textField: UITextField) -> Bool { _ = self.textField.textFieldShouldReturn?(textField) return keymanDelegate?.textFieldShouldReturn?(textField) ?? true } }