1. 将表达式赋值给具有相同名称的变量

Swift 5.4新增功能:现在可以创建一个局部变量,并将其赋值给具有相同名称的表达式,而无需手动用self消除歧义。

例如,下面的ItemListViewController有一个方法可以让我们检索给定IndexPath的Item,我们选择了简单地调用item(at:):

class ItemListViewController: UIViewController {
    ...

    private func item(at indexPath: IndexPath) -> Item {
        ...
    }
}

在使用Swift 5.3或更早的版本时,如果我们想调用上面的方法,并将其结果赋给一个也叫做item的本地let或var变量,然后,我们必须在方法调用的前面加上self,以便编译器能够将这两者分开——就像这样:

class ItemListViewController: UIViewController {
    ...

    private func showDetailViewForItem(at indexPath: IndexPath) {
        let item = self.item(at: indexPath)
        ...
    }
}

然而,从Swift 5.4开始,这就不再需要了,编译器现在会自动理解右项符号指向对我们方法的调用,而不管我们是否使用self引用它:

class ItemListViewController: UIViewController {
    ...

    private func showDetailViewForItem(at indexPath: IndexPath) {
        let item = item(at: indexPath)
        ...
    }
}

也许我最喜欢的使用这种新语法特性的方式是在为异步代码编写单元测试时,这通常涉及使用内置的expectation API创建xctestexpect实例。 因为这种期望的最自然的名称通常是简单的expectation,现在能够做以下事情真的很好:

class ItemLoaderTests: XCTestCase {
    ...

    func testLoadingItem() {
        let expectation = expectation(description: "Loading item")
        ...
    }
}

上述特性可以派上用场的另一种情况是,当我们想要创建属性的局部可变副本时。现在,当引用我们要复制的属性时,也可以不使用self来完成——例如:

struct Item {
    var title: String
    var prefix: String?
    var suffix: String?
    
    func fullTitle() -> String {
        var title = title

        if let prefix = prefix {
            title = prefix + title
        }

        if let suffix = suffix {
            title += suffix
        }

        return title
    }
}

当然,这可能不是一个革命性的新语法特性,不会完全改变我们编写Swift代码的方式——但是,嘿,不是每个特性或改变都需要如此。我个人认为这种“生活质量”的改进是非常受欢迎的,并且可以使某些类型的代码感觉更轻量级。