如何理解 if let 与guard

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何理解 if let 与guard相关的知识,希望对你有一定的参考价值。

参考技术A if let 和 guard 只是语法糖,没有也可以,但有了可以使得代码更简洁方便。要理解 if let 和 guard,不妨设想假如没有这两者,代码会怎么写。------------------------------------

if let
func doSomething(str: String?)

let v: String! = str
if v != nil

// use v to do something



Swift 中因为有optional, 经常需要判断是否为空。假如没有if let,大致写成上面的样子,有了if let, 可以改写成
func doSomething(str: String?)

if let v = str

// use v to do something



上面两段代码的控制流是一样的。对照着,可以看出if let的写法更加简洁方便。
------------------------------------
guard
假如if中出现的代码很长,我们写代码时可以将错误情况先返回。比如:
func doSomething(str: String?)

let v: String! = str
if v == nil

return


// use v to do something


这样做可以避免过多的嵌套。上面代码实在太常见了,swift也提供一个guard这个语法糖,用guard可以改写成:
func doSomething(str: String?)

guard let v = str else return

// use v to do something


上面两段代码的控制流是一样的。也可以看出guard的写法更加简洁方便。
------------------------------------

至于if let 和 guard 语法中出现的where,只是附加一些条件。相当于逻辑运算 && 和 ||。SQL中的条件语法也是用where这个关键字。

假如还不理解,动手将一段代码,不用if let 和 guard 进行改写。试多几次,就会发觉很自然了。

Swift 1.2 中 UIImage 的 If Let vs Guard Let

【中文标题】Swift 1.2 中 UIImage 的 If Let vs Guard Let【英文标题】:If Let vs Guard Let for UIImage in Swift 1.2 【发布时间】:2017-06-04 19:35:32 【问题描述】:

我正在学习 iOS Apple 开发人员教程,但我遇到了一些问题,因为我的计算机的 Swift 版本是 1.2,Xcode 是 6.4 而不是 Swift 3.0。我已经能够根据需要同时降级代码,但是在下面的 Swift 2.0 中引入的“guard let”中遇到了错误:

// The info dictionary may contain multiple representations of the image. 
// You want to use the original.

guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else 
    fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")

我将其转换为以下内容:

if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage 
     return selectedImage
 else 
     fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")


//Set photoImageView to display the image.
photoImageView.image = selectedImage

但我收到以下错误:“使用未解决的已识别 'selectedImage'”

任何帮助将不胜感激!

编辑:下面是完整代码

import UIKit

class ViewController: UIViewController, UITextFieldDelegate,
UIImagePickerControllerDelegate, UINavigationControllerDelegate 

//MARK: Properties
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var mealNameLabel: UILabel!
@IBOutlet weak var photoImageView: UIImageView!

override func viewDidLoad() 
    super.viewDidLoad()

    //Handle the text field's user input through the delegate callbacks
    nameTextField.delegate = self



//MARK: UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool 
    //Hide the keyboard
    textField.resignFirstResponder()
    return true

func textFieldDidEndEditing(textField: UITextField) 
    //Set the lablel name as what the used typed
    mealNameLabel.text = textField.text


//MARK: UIImagePickerControllerDelegate
func imagePickerControllerDidCancel(picker: UIImagePickerController) 
    //Dismiss the picker if the user canceled
    dismissViewControllerAnimated(true, completion:nil)

func imagePickerController(picker: UIImagePickerController,
    didFinishPickingMediaWithInfo info: [String : Any]) 
        //The info dictionary may contain multiple representations of the image. You want to use the original.
        if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage 
            //Set photoImageView to display the image
            photoImageView.image = selectedImage
         else 
            fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
        

        //Set photoImageView to display the image
        //photoImageView.image = selectedImage

        //Dismiss the picker
        dismissViewControllerAnimated(true, completion: nil)



//MARK: Actions
@IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) 
    //Hide the keyboard
    nameTextField.resignFirstResponder()

    //UIImagePickerController is a view controller that lets a user pick media from their photo library.
    let imagePickerController = UIImagePickerController()


    //Only allow photos to be picked, not taken.
    imagePickerController.sourceType = .PhotoLibrary

    //Make sure ViewController is notified when the user picks and image.
    imagePickerController.delegate = self
    presentViewController(imagePickerController, animated: true, completion: nil)


@IBAction func setDefaultLabelText(_: UIButton) 
    mealNameLabel.text = "Default Text"


【问题讨论】:

你的错误在这一行 photoImageView.image = selectedImage ?,这是因为你的变量 selectedImage 只在你的 if let 范围内定义,顺便说一句,你返回你的 selectedImage 之后你是将其分配给 .image? 正确,错误就在那一行。如果我在 if let 中添加return selectedImage,会解决它吗?更新:刚试过这个。现在return selectedImage 返回错误:'UIImage' is not convertible to '()' 检查我的答案 【参考方案1】:

if let 可选绑定语句创建一个新变量,该变量仅存在于后面的大括号内:

if let foo = optionalFoo 
  //foo is only defined here


//foo has gone out of scope.

guard let 创建一个新变量,该变量在当前作用域结束后的代码中存在:

func bar(optionalFoo: FooThing) 
  guard let foo = optionalFoo else return

  //foo exists from here until the end of the 
  //current scope (the end of the func)

由于 Swift 1 没有保护语句,您需要将 guard let 之后的代码移动到 if let 的大括号内:

看起来@ReinierMelian 用他的回答打败了我。在 Swift 1.x 中查看他的正确代码形式的答案。

请注意,Swift 1.0 已经过时了,使用它对你自己不利。您应该升级到 Xcode 8.3 和 Swift 3.1。从 Swift 1 到 Swift 2 的变化是显着的,而从 Swift 2 到 Swift 3 的变化是。 Swift 1 代码无法在 Xcode 8 中编译,您可能无法通过自动转换运行它。 (Xcode 8 将提供通过自动转换为 Swift 3 来运行 Swift 2.x,但我不确定它是否会将 Swift 1 转换为 Swift 3。

【讨论】:

现在 Swift 1.x 已经过时了 4 个主要版本,所以你绝对应该继续前进。 (我们使用的是 Swift 5.2)【参考方案2】:

发生这种情况是因为您的变量 selectedImage 仅在您的 if let 范围内定义

您必须改用此代码

if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
     //Set photoImageView to display the image.
     photoImageView.image = selectedImage
     return selectedImage
 else 
     fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")

希望对你有帮助

【讨论】:

嗨 Reinier,感谢您的帮助。代码现在可以编译,但是当我在模拟器中单击并选择一个图像时,它会加载到应用程序中。这可能是因为它包含在if let 范围内吗? @user282041 你是想说不要在应用程序中加载?还是不要在模拟器中加载?不要在你的 photoImageView UIImageView 中加载? 它不会在模拟器中加载。我单击图像,从库中选择一张照片,但一旦我选择它,照片就不会加载。 @user282041 你能分享你的完整代码看看有什么问题吗? @user282041 我认为你的问题又是范围,你在一个方法中定义你的UIImagePickerController,将你的选择器视图作为 viewController 属性并尝试,必须工作,让我知道

以上是关于如何理解 if let 与guard的主要内容,如果未能解决你的问题,请参考以下文章

Swift 基本语法03-"if let"和"guard let"

Swift 1.2 中 UIImage 的 If Let vs Guard Let

[PHP] 浅谈 Laravel Authentication 的 guards 与 providers

关于var和ES6中的let,const的理解

即使值为 nil,Guard Let 语句也不会触发

laravel Contracts 的理解与分析