理解swift中的可选全局变量

理解swift中的可选全局变量,swift,optional,Swift,Optional,我正在阅读一本关于Swift的书,我了解函数中作用域的概念,所以我接下来想了解的是为什么我们在类中使用可选类型设置全局变量。老实说,看起来我们并没有设置这些变量,只是让类知道在整个代码库的某个地方会有一个特定类型的变量:var sut:itemmager 据我所知,变量sut是ItemManger类型的未包装可选变量,它肯定有一个有效值,而不是nil。我们之所以用感叹号或问号来设置它,是因为这个类中没有初始值设定项。不清楚的是,既然这个类没有初始值设定项,那么在决定是否使用问号将这个全局变量设置

我正在阅读一本关于Swift的书,我了解函数中作用域的概念,所以我接下来想了解的是为什么我们在类中使用可选类型设置全局变量。老实说,看起来我们并没有设置这些变量,只是让类知道在整个代码库的某个地方会有一个特定类型的变量:
var sut:itemmager

据我所知,变量sut是ItemManger类型的未包装可选变量,它肯定有一个有效值,而不是nil。我们之所以用感叹号或问号来设置它,是因为这个类中没有初始值设定项。不清楚的是,既然这个类没有初始值设定项,那么在决定是否使用问号将这个全局变量设置为可选变量或使用感叹号隐式展开时,哪些因素起作用

import XCTest
    @testable import ToDo

    class ItemManagerTests: XCTestCase {

        var sut: ItemManager!

        override func setUp() {
            super.setUp()
            // Put setup code here. This method is called before the invocation of each test method in the class.

            sut = ItemManager.init()
        }

        override func tearDown() {
            // Put teardown code here. This method is called after the invocation of each test method in the class.
            super.tearDown()
        }


        func test_ToDoCount_InitiallySetAtZero(){

            let sut = ItemManager.init()

            XCTAssertEqual(sut.toDoCount, 0)
        }

        func test_DoneCount_InitiallySetAtZero(){

            let sut = ItemManager.init()

            XCTAssertEqual(sut.doneCount, 0)
        }
    }

sut
不是全局变量

sut
ItemManagerTests
的一个实例变量。每次实例化
ItemManagerTests
的新实例(即对象)时,都会为
sut
分配内存

它的类型是
itemmager。这是一个隐式展开的可选项。它类似于
项目管理器?
(又称为可选),区别在于它在直接使用的任何地方都隐式强制展开,就像使用了强制展开操作符(

它的值被初始化为
nil
,但是当Xcode的测试框架调用
setUp
时,它被设置为一个新的
ItemManager
对象

我们将其设置为感叹号或问号的原因是 因为这个类中没有初始值设定项

因为当初始化类的每个实例时,它必须为其属性/实例变量分配内存
,当
init
时,
sut
的值为
nil
。没有
编译器无法分配init,因此您必须在初始值设定项中手动初始化。这就是编译器告诉你的

用于使用

  • 。在第一次分配之后,它不可能是零
  • 用于pro/var是否有值的情况

首先,
sut
不是全局的。Swift中的全局变量在任何封闭范围之外声明(因此,在
语句之前)
sut
是一个实例属性;
ItemManagerTests
类的每个实例都有一个
sut
属性

在Swift中,所有非可选属性必须在初始化程序完成时初始化。在某些情况下,这可以通过初始化器内部的代码来实现,在其他情况下,可以通过指定默认值来实现

在某些情况下,不能指定或不想指定默认值,并且不能(或不想)重写初始化器

如果您使用了一个普通的可选选项,那么编译器将确信该属性在默认情况下或在初始化器中没有初始化,但每次引用该属性时,您都必须将其展开(例如
sut?.donecount

由于您的测试用例正在
setup
中为
sut
分配一个值,因此您知道它将有一个值,您可以使用强制展开(例如
sut!.donecount
),或者进一步使用隐式展开的可选项。这允许您在不进行任何展开的情况下引用属性,但它仍然是可选的,如果
nil
,则仍然会导致崩溃

请注意,您当前的代码甚至没有使用该属性,因为您正在测试用例中分配一个局部变量。您可以使用:

class ItemManagerTests: XCTestCase {

    var sut: ItemManager!

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.

        sut = ItemManager.init()
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func test_ToDoCount_InitiallySetAtZero() {

        XCTAssertEqual(sut.toDoCount, 0)
    }

    func test_DoneCount_InitiallySetAtZero() {

        XCTAssertEqual(sut.doneCount, 0)
    }
}

您列表中第一项中的索赔都不正确。IUO没有值是完全可以的——只要确保没有值就不会访问它们。