我正在编写一本关于Swift的书,我理解了函数中范围的概念,所以我接下来想要理解的是为什么我们在类中使用可选类型设置全局变量。老实说,看起来我们没有按照说法设置这些变量,只是让类知道整个代码库中某个特定类型的变量:var sut: ItemManager!
。
根据我的理解,变量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)
}
}
答案 0 :(得分:3)
sut
不是全局变量。
sut
是ItemManagerTests
的实例变量。每次实例化ItemManagerTests
的新实例(即对象)时,都会为sut
分配内存。
ItemManager!
类型。这是一个隐式解包的可选项。它类似于ItemManager?
(也就是可选),区别在于它在任何地方被直接强行打开,就像使用了强制解包操作符(!
)一样
其值初始化为nil
,但在Xcode的测试框架调用ItemManager
时设置为新的setUp
对象。
答案 1 :(得分:3)
首先,sut
不是全球性的。 Swift中的全局变量在任何封闭范围之外声明(因此,在class
语句之前)。 sut
是一个实例属性;您的ItemManagerTests
课程的每个实例都有一个sut
属性。
在Swift中,必须在初始化程序完成时初始化所有非可选属性。在某些情况下,这可以通过初始化程序内的代码实现,在其他情况下可以通过分配默认值来实现。
在某些情况下,您无法指定或不想指定默认值,也不能(或不想)覆盖初始化程序。
如果您使用了普通的可选项,那么编译器会认为默认情况下或初始化程序中没有初始化该属性,但每次引用该属性时都必须将其解包(例如sut?.donecount
)。
由于您的测试用例是在sut
中为setup
分配值,您知道它将具有值并且您可以使用强制解包(例如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)
}
}
答案 2 :(得分:1)
我们用感叹号或问号设置它的原因是 因为这个类中没有初始化器
因为当初始化类的每个实例时,它必须为其属性/实例var分配内存。因此,使用var sut: ItemManager!
时,sut
的值nil
为init
。如果没有!
,?
,编译器就无法分配init,因此您必须在初始化程序中手动初始化。这就是编译器告诉你的。
使用!
或?
。
!
。在第一次分配后,它不能晚于?