Переменная, определенная в Guard, по-прежнему требует распаковки сразу после использования. - PullRequest
0 голосов
/ 08 февраля 2019

if (stringToURL? .IsValidURL)! <- Не уверен, почему компилятору требуется необязательное сцепление для <em>stringToURL , когда оно безопасно объявлено в операторе Guard.Кроме того, расширение строки для isValidURL: Bool всегда возвращает Bool, но компилятор все еще хочет развернуть его.

В этом примере annotation.subtitle уже должна быть строкой в ​​формате URL, ноЯ хотел подтвердить.

Попытка использовать переменные, определенные в guard, становится более запутанной, чем ожидалось, потому что требуется дальнейшее развертывание.Теперь я чувствую, что я делаю несколько строк кода слишком сложными, чтобы их можно было читать / читать в моих реализациях.

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    let backupURL = URL(string: "https://www.google.com")!
    guard let currentAnnotation = view.annotation, var stringToURL = currentAnnotation.subtitle else {
        // currentAnnotation has blank subtitle.  Handle by opening up any website.
        UIApplication.shared.open(backupURL, options: [:])
        return
    }
    if (stringToURL?.isValidURL)!{
        stringToURL = stringToURL?.prependHTTPifNeeded()
        if let url = URL(string: stringToURL!){
            UIApplication.shared.open(url, options: [:])
        } else {
            UIApplication.shared.open(backupURL, options: [:])
        }
    }
}

extension String {
var isValidURL: Bool {
    let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
    if let match = detector.firstMatch(in: self, options: [], range: NSRange(location: 0, length: self.endIndex.encodedOffset)) {
        // it is a link, if the match covers the whole string
        return match.range.length == self.endIndex.encodedOffset
    } else {
        return false
    }
}

func prependHTTPifNeeded()-> String{
    let first4 = self.prefix(4)
    if first4 != "http" {
        return "http://" + self
    } else {
        return self
    }
}

}

Блок кода выполняется правильно.
аннотация.subtitle = "https://www.yahoo.com" <--- Yahoo открывает </p>

annotation.subtitle =" www.yahoo.com "<--- Yahoo открывает </p>

annotation.subtitle =" Yahoo"<--- google.com открывается, потому что у нас не было правильной строки URL </p>

1 Ответ

0 голосов
/ 08 февраля 2019

Проблема в том, что currentAnnotation.subtitle - это String??, поскольку subtitle - это не только само по себе String?, но и необязательное свойство протокола MKAnnotation.Таким образом, простая развертка только подтверждает, что был реализован необязательный протокол subtitle, но не то, что полученный String? не был nil.Вы должны развернуть это тоже.

Но вы можете сделать guard var stringToURL = view.annotation?.subtitle as? String else { ... }, и он будет правильно развернут в String:

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    let backupURL = URL(string: "https://www.google.com”)!

    guard var stringToURL = view.annotation?.subtitle as? String else {
        UIApplication.shared.open(backupURL)
        return
    }

    if stringToURL.isValidURL {
        stringToURL = stringToURL.prependHTTPifNeeded()
        let url = URL(string: stringToURL) ?? backupURL
        UIApplication.shared.open(url)
    }
}

Примечание, которое откроет backupURL, если строка не указана,но если строка была указана и не была действительным URL, она ничего не сделает.Поэтому, возможно, вы имели в виду следующее, которое откроет backupURL, если не может открыть stringToURL:

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    let backupURL = URL(string: "https://www.google.com")!

    guard var stringToURL = view.annotation?.subtitle as? String,
        stringToURL.isValidURL else {
            UIApplication.shared.open(backupURL)
            return
    }

    stringToURL = stringToURL.prependHTTPifNeeded()
    let url = URL(string: stringToURL) ?? backupURL
    UIApplication.shared.open(url)
}

Где:

extension String {
    var isValidURL: Bool {
        let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
        let range = NSRange(startIndex..., in: self)
        return detector.firstMatch(in: self, range: range)?.range == range
    }

    func prependHTTPifNeeded() -> String{
        if prefix(4) != "http" {
            return "http://" + self
        } else {
            return self
        }
    }
}
...