Guard 中定义的变量在使用时仍然需要立即解包
Variable defined in Guard still require unwrapping immediately afterwards when used
if (stringToURL?.isValidURL)! <-- 不确定为什么编译器需要在 上进行可选链接stringToURL 在 Guard 语句中安全声明时。此外,isValidURL 的字符串扩展名:Bool 始终 returns Bool 但编译器仍需要解包。
在此示例中,annotation.subtitle 应该已经是 URL 格式的字符串,但我想确认一下。
尝试使用在 guard 中定义的变量变得比预期的更复杂,因为需要进一步解包。现在我觉得我的实现让几行代码变得过于复杂 follow/read。
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
}
}
}
代码块正确执行。
annotation.subtitle = "https://www.yahoo.com" <--- 雅虎打开
annotation.subtitle = "www.yahoo.com" <--- 雅虎打开
annotation.subtitle = "yahoo" <--- google.com 打开,因为我们没有有效的 URL 字符串
问题是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
}
}
}
if (stringToURL?.isValidURL)! <-- 不确定为什么编译器需要在 上进行可选链接stringToURL 在 Guard 语句中安全声明时。此外,isValidURL 的字符串扩展名:Bool 始终 returns Bool 但编译器仍需要解包。
在此示例中,annotation.subtitle 应该已经是 URL 格式的字符串,但我想确认一下。
尝试使用在 guard 中定义的变量变得比预期的更复杂,因为需要进一步解包。现在我觉得我的实现让几行代码变得过于复杂 follow/read。
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
}
}
}
代码块正确执行。
annotation.subtitle = "https://www.yahoo.com" <--- 雅虎打开
annotation.subtitle = "www.yahoo.com" <--- 雅虎打开
annotation.subtitle = "yahoo" <--- google.com 打开,因为我们没有有效的 URL 字符串
问题是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
}
}
}