Custom Swift Formatter для телефонных номеров - PullRequest
0 голосов
/ 11 октября 2019

Мне требуется простое средство форматирования телефонных номеров в Swift для добавления в NSTextField.

У меня проблемы с пониманием документации и примеров, особенно для getObjectValue (_ :, for :, errorDescription) -> Boolиспользование функции объекта .pointee. Концепция AutoreleasingUnsafeMutablePointer? было трудно из документации, и я не могу найти много о пользовательских форматерах Swift в Интернете. Я посмотрел на PhoneNumberKit Мармела Роя, но он кажется слишком сложным для моих нужд, и не описал, как добавить его в средство форматирования напрямую.

override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {

      obj?.pointee = someConversionToInternalString(typedString)
        return true
    }

Вышеприведенное не сработало, постоянно просто сохраняя пустую строку.

1 Ответ

0 голосов
/ 11 октября 2019

После некоторой работы я решил, как это сделать. Я надеюсь, что это сэкономит время других на этом. Ключ в моем решении состоял в том, чтобы сохранить «объект» как объект Какао (то есть объективный тип C);здесь как строка NSString, а не строка. Вот некоторый полный пример кода, который выполняет (простое) форматирование телефонных номеров, подходящих для моих условий.

import Foundation

class PhoneFormatter: Formatter {

    override init() {
        super.init()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    func reduceToPhoneCharacters(string: String) -> String {
        let plusSign = string.prefix(1) == "+"

        // remove any non-digit characters
        let str = string.digits
        return "\(plusSign ? "+" : "")\(str)"
    }

    func displayString(string: String) -> String? {

        // take a string of symbols and convert into a formatted phone number (US, Aust, Europe)
        if string.isBlank || !string.isPhoneCharacters { return string } // will see if it improves

        let plusSign = string.prefix(1) == "+"

        // remove any non-digit characters
        let str = string.digits

        // international, + at start, recognise only US, Australian, NZ or European
        if plusSign {
            // USA
            if str.prefix(1) == "1" {
                return "+" + str.substring(start: 0, length: 1) + " (" + str.substring(start: 1, length: 3) + ") " + str.substring(start: 4, length: 3) + "-" + str.substring(start: 7, length: 4)
            }
            // Australia
            if str.prefix(2) == "61" || str.prefix(2) == "64" {
                return "+" + str.substring(start: 0, length: 3) + "-" + str.substring(start: 3, length: 4) + "-" + str.substring(start: 7, length: 4)
            }
            // Others? eg +44-123-456789
            return "+" + str.substring(start: 0, length: 2) + "-" + str.substring(start: 3, length: 4) + "-" + str.substring(start: 7, length: 10)
        }
        // mobile if begins with 04
        if str.prefix(2) == "04" {
            return str.substring(start: 0, length: 4) + "-" + str.substring(start: 4, length: 3) + "-" + str.substring(start: 7, length: 3)
        }
        // interstate
        if str.prefix(1) == "0" {
            return str.substring(start: 0, length: 2) + "-" + str.substring(start: 2, length: 4) + "-" + str.substring(start: 6, length: 4)
        }
        // 1800 or 1300 numbers
        if str.prefix(4) == "1800" || str.prefix(4) == "1300" {
            return str.substring(start: 0, length: 1) + "-" + str.substring(start: 1, length: 3) + "-" + str.substring(start: 4, length: 3) + "-" + str.substring(start: 7, length: 4)
        }
        // else Victoria substring
        return str.substring(start: 0, length: 4) + "-" + str.substring(start: 4, length: 4)
    }

    override func string(for obj: Any?) -> String? {
        // take a string of symbols and convert into a formatted phone number (US, Aust, Europe)
        guard let str = obj as? NSString else { return nil }
        return displayString(string: str as String)
    }

    override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {

        obj?.pointee = reduceToPhoneCharacters(string: string) as NSString
        return true
    }

    override func editingString(for obj: Any) -> String? {
        if let str = obj as? NSString {
            return str as String
        }
        return nil
    }

    override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
        return partialString.isPhoneCharacters || partialString == ""
    }
}

// separate +String.swift file for extensions
import Foundation

extension String {}

    var digits: String {
        return components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
    }

    var isPhoneCharacters: Bool {
        return !isEmpty && range(of: "[^+\\d]", options: .regularExpression) == nil
    }    

    func substring(start: Int, length : Int) -> String {
        if (count > start + length) {
            let startAtIndex = index(startIndex, offsetBy: start)
            return String(self[startAtIndex...index(startAtIndex, offsetBy: length - 1)])
        }
        if count > start {
            let startAtIndex = index(startIndex, offsetBy: start)
            return String(self[startAtIndex...])
        }
        return ""
    }

}

И использовать его программно, например:

        @IBOutlet weak var phoneTextField: NSTextField!
        phoneTextField.formatter = PhoneFormatter()

Я редактировалэто для удаления избыточного кода и использования функции editString (для :).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...