How to check validity of URL in Swift?

Swift 4 elegant solution using NSDataDetector:

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.utf16.count)) {
            // it is a link, if the match covers the whole string
            return match.range.length == self.utf16.count
        } else {
            return false
        }
    }
}

Usage:

let string = "https://www.fs.blog/2017/02/naval-ravikant-reading-decision-making/"
if string.isValidURL {
    // TODO
}

Reasoning behind using NSDataDetector instead of UIApplication.shared.canOpenURL:

I needed a method that would detect whether the user provided an input that is an URL to something. In many cases, users don't include the http:// nor https:// URL scheme in the URL they type in - e.g., instead of "http://www.google.com" they would type in "www.google.com". Without the URL scheme, the UIApplication.shared.canOpenURL will fail to recognize the URL and will return false. NSDataDetector is, compared to UIApplication.shared.canOpenURL, a rather forgiving tool (as @AmitaiB mentioned in comments) - and it can detect even URLs without the http:// scheme. This way I am able to detect a URL without having to try to add the scheme everytime when testing the string.

Sidenote - SFSafariViewController can open only URLs with http:///https://. Thus, if a detected URL does not have a URL scheme specified, and you want to open the link, you will have to prepend the scheme manually.


If your goal is to verify if your application can open a URL, here is what you can do. Although safari can open the URL, the website might not exist or it might be down.

// Swift 5
func verifyUrl (urlString: String?) -> Bool {
    if let urlString = urlString {
        if let url = NSURL(string: urlString) {
            return UIApplication.shared.canOpenURL(url as URL)
        }
    }
    return false
}

As a side note, this does not check whether or not a URL is valid or complete. For example, a call that passes "https://" returns true.


For a swift 3 version of the accepted answer:

func verifyUrl(urlString: String?) -> Bool {
    if let urlString = urlString {
        if let url = URL(string: urlString) {
            return UIApplication.shared.canOpenURL(url)
        }
    }
    return false
}

Or for a more Swifty solution:

func verifyUrl(urlString: String?) -> Bool {
    guard let urlString = urlString,
          let url = URL(string: urlString) else { 
        return false 
    }

    return UIApplication.shared.canOpenURL(url)
}

Using 'canOpenUrl' was too expensive for my use case, I found this approach to be quicker

func isStringLink(string: String) -> Bool {
    let types: NSTextCheckingResult.CheckingType = [.link]
    let detector = try? NSDataDetector(types: types.rawValue)
    guard (detector != nil && string.characters.count > 0) else { return false }
    if detector!.numberOfMatches(in: string, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, string.characters.count)) > 0 {
        return true
    }
    return false
}

Tags:

Url

Swift

Ios8