Trying to make an app launch the default browser to a URL, but only if the URL entered is valid, otherwise it displays a message saying the URL is invalid.
How would
Try this:
func isValid(urlString: String) -> Bool
{
if let urlComponents = URLComponents.init(string: urlString), urlComponents.host != nil, urlComponents.url != nil
{
return true
}
return false
}
This simply checks for valid URL components and if the host and url components are not nil. Also, you can just add this to an extensions file
My personal preference is to approach this with an extension, because I like to call the method directly on the string object.
extension String {
private func matches(pattern: String) -> Bool {
let regex = try! NSRegularExpression(
pattern: pattern,
options: [.caseInsensitive])
return regex.firstMatch(
in: self,
options: [],
range: NSRange(location: 0, length: utf16.count)) != nil
}
func isValidURL() -> Bool {
guard let url = URL(string: self) else { return false }
if !UIApplication.shared.canOpenURL(url) {
return false
}
let urlPattern = "^(http|https|ftp)\\://([a-zA-Z0-9\\.\\-]+(\\:[a-zA-Z0-9\\.&%\\$\\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\\-]+\\.)*[a-zA-Z0-9\\-]+\\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\\:[0-9]+)*(/($|[a-zA-Z0-9\\.\\,\\?\\'\\\\\\+&%\\$#\\=~_\\-]+))*$"
return self.matches(pattern: urlPattern)
}
}
This way it is also extensible with another use-cases, such as isValidEmail
, isValidName
or whatever your application requires.
You can use the NSURL
type (whose constructor returns an optional type) combined with an if-let statement to check the validity of a given URL. In other words, make use of the NSURL
failable initializer, a key feature of Swift:
let stringWithPossibleURL: String = self.textField.text // Or another source of text
if let validURL: NSURL = NSURL(string: stringWithPossibleURL) {
// Successfully constructed an NSURL; open it
UIApplication.sharedApplication().openURL(validURL)
} else {
// Initialization failed; alert the user
let controller: UIAlertController = UIAlertController(title: "Invalid URL", message: "Please try again.", preferredStyle: .Alert)
controller.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(controller, animated: true, completion: nil)
}
Version that works with Swift 4.2 and has reliable URL pattern matching ...
func matches(pattern: String) -> Bool
{
do
{
let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
return regex.firstMatch(in: self, options: [], range: NSRange(location: 0, length: utf16.count)) != nil
}
catch
{
return false
}
}
func isValidURL() -> Bool
{
guard let url = URL(string: self) else { return false }
if !UIApplication.shared.canOpenURL(url) { return false }
let urlPattern = "(http|ftp|https):\\/\\/([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?"
return self.matches(pattern: urlPattern)
}
Swift 5.1 Solution
extension String {
func canOpenUrl() -> Bool {
guard let url = URL(string: self), UIApplication.shared.canOpenURL(url) else { return false }
let regEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
let predicate = NSPredicate(format:"SELF MATCHES %@", argumentArray:[regEx])
return predicate.evaluate(with: self)
}
}
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.