2015-01-21 2 views
25

Попытка заставить приложение запускать браузер по умолчанию для URL-адреса, но только если введенный URL-адрес действителен, в противном случае отображается сообщение о том, что URL-адрес недействителен.Как проверить правильность URL-адреса в Swift?

Как я могу проверить правильность использования Swift?

+0

отправить NSURLRequest и проверить возвращение? – chris

+0

Используйте строку, чтобы сформировать NSURL, и посмотрите, нет ли этого? – matt

ответ

49

Если ваша цель состоит в том, чтобы проверить, если ваше приложение может открыть URL здесь является то, что вы можете сделать. Хотя сафари может открыть Url, веб-сайт может не существовать или он может быть недоступен.

func verifyUrl (urlString: String?) -> Bool { 
    //Check for nil 
    if let urlString = urlString { 
     // create NSURL instance 
     if let url = NSURL(string: urlString) { 
      // check if your application can open the NSURL instance 
      return UIApplication.sharedApplication().canOpenURL(url) 
     } 
    } 
    return false 
} 
+1

Все оставшиеся 'else' являются избыточными. – royhowie

+2

если пусть urlString = urlString, URL = NSURL (строка: urlString) где UIApplication.sharedApplication() canOpenURL (URL) { возвращающие } –

+0

не работает, когда я тест на swift2.0 ', если позволить URL = NSURL. (строка: urlString) {' –

2

Вы можете использовать тип NSURL (конструктор которого возвращает необязательный тип) в сочетании с if-let statement, чтобы проверить правильность заданного URL-адреса. Другими словами, использовать в NSURLfailable initializer, ключевой особенностью 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) 
} 
5
var url:NSURL = NSURL(string: "tel://000000000000")! 
if UIApplication.sharedApplication().canOpenURL(url) { 
    UIApplication.sharedApplication().openURL(url) 
} else { 
    // Put your error handler code... 
} 
9

Я нашел это один чистый (в Swift):

func canOpenURL(string: String?) -> Bool { 
    guard let urlString = string else {return false} 
    guard let url = NSURL(string: urlString) else {return false} 
    if !UIApplication.sharedApplication().canOpenURL(url) {return false} 

    // 
    let regEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+" 
    let predicate = NSPredicate(format:"SELF MATCHES %@", argumentArray:[regEx]) 
    return predicate.evaluateWithObject(string) 
} 

Использование:

if canOpenURL("abc") { 
    print("valid url.") 
} else { 
    print("invalid url.") 
} 
+0

не принимается 127.0.0.1:5433 – Vahid

17

Для быстрой 3 версии принятого ответа:

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

Или для более решения Swifty:

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

    return UIApplication.shared.canOpenURL(url) 
} 
+0

В то время как он верен предыдущей версии, вы можете объединить 'if let..'s 'в одну проверку, а затем также перевернуть' if' в 'guard ... else {return false} ', чтобы уточнить, что' return false' является состоянием сбоя и 'return UIApplication ... 'является (возможным) состоянием успеха. – ReactiveRaven

+1

@ReactiveRaven Да, я согласен. Я добавил версию, как предложено –

3

Мое личное предпочтение, чтобы подойти к этому с расширением, потому что я хотел бы вызвать метод непосредственно на объекте строки.

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) 
    } 
} 

Таким образом, это также расширяемой с другими потребительных случаях, например isValidEmail, isValidName или независимо от вашего приложения требуется.

+0

Это, похоже, не работает на google.com. Для этого требуется только что-то вроде http://google.com – lwdthe1

+0

@ lwdthe1 да, регулярное выражение имеет некоторые отверстия. Тем не менее, речь идет о архитектуре решения (приближаясь к нему с расширением). Не стесняйтесь заменять регулярное выражение вашим собственным в приложении. Или если у вас есть лучший - улучшите мой ответ! :) – Michal

1

Это не регулярное выражение подход, но это наивное один, который хорошо работает для убедившись, что есть хозяин и расширение, если вы хотите, простой и недорогой подход:

extension String { 
    var isValidUrlNaive: Bool { 
     var domain = self 
     guard domain.count > 2 else {return false} 
     guard domain.trim().split(" ").count == 1 else {return false} 
     if self.containsString("?") { 
      var parts = self.splitWithMax("?", maxSplit: 1) 
      domain = parts[0] 
     } 
     return domain.split(".").count > 1 
    } 
} 

Используйте это только если вам нужен быстрый способ проверить на стороне клиента, и у вас есть логика сервера, которая проведет более строгую проверку перед сохранением данных.

8

Использование «canOpenUrl» было слишком дорого для моего случая использования, я нашел этот подход, чтобы быть быстрее

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 
} 
+0

Это было идеально для меня использовать в расширении, где UIApplication.shared недоступен. Благодаря! – Simon

+1

Для Swift 4: 'string.characters.count' становится' string.count' –

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

//Usage 
let testURL: String = "http://www.google.com" 
if testURL.isStringLink() { 
    //Valid! 
} else { 
    //Not valid. 
} 

Советуют использовать эту проверку только один раз, а затем повторно использовать.

P.S. Кредиты на Shachar для этой функции.

0

Попробуйте это:

func isValid(urlString: String) -> Bool 
{ 
    if let urlComponents = URLComponents.init(string: urlString), urlComponents.host != nil, urlComponents.url != nil 
    { 
     return true 
    } 
    return false 
} 

Это просто проверяет наличие действительных компонентов URL и, если хост и URL компоненты не равны нулю. Кроме того, вы можете просто добавить это в файл расширений

0

В некоторых случаях этого может быть достаточно, чтобы проверить соответствие URL-адреса RFC 1808. Существует несколько способов сделать это. Один из примеров:

if let url = URL(string: urlString), url.host != nil { 
    // This is a correct url 
} 

Это потому, что .host, а также .path, .fragment и несколько других методов будет возвращать ноль, если URL не соответствует RFC 1808.

Если вы не» проверка т, вы могли бы иметь такого рода сообщений в журнале консоли:

Task <DF46917D-1A04-4E76-B54E-876423224DF7>.<72> finished with error - code: -1002 
0

Для быстрой 4 вы можете использовать:

class func verifyUrl (urlString: String?) -> Bool { 
    //Check for nil 
    if let urlString = urlString { 
     // create NSURL instance 
     if let url = URL(string: urlString) { 
      // check if your application can open the NSURL instance 
      return UIApplication.shared.canOpenURL(url) 
     } 
    } 
    return false 
} 
0

Swift 4 элегантное решение с использованием 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.endIndex.encodedOffset)) { 
      // it is a link, if the match covers the whole string 
      return match.range.length == self.endIndex.encodedOffset 
     } else { 
      return false 
     } 
    } 
} 

Использование:

let string = "https://www.fs.blog/2017/02/naval-ravikant-reading-decision-making/" 
if string.isValidURL { 
    // TODO 
} 
Смежные вопросы