Swift之旅_Language Guide2

刚做完一个项目,有点时间,就把Swift官方文档的部分小节阅读了一下,照例记录一些知识盲点和重点。


Enumerations

这一小节主要讲解的是Swift中枚举的相关用法。Swift中的枚举不像C中的枚举的case关联的值只能是数值,Swift中枚举case的关联值可以是各种各样的值,并且可以直接通过枚举的rawValue属性获取它。

enum kStatusEnum: Int {
    case success = 200
    case failed = 404
}
print(kStatusEnum.success.rawValue)
print(kStatusEnum.failed.rawValue)
// print 200, 404
  • Recursive Enumerations

此外还有一个比较高端的用法(个人感觉= =),可以在枚举中使用递归。在枚举前加上indirect修饰符可以让枚举中的每个case都是可递归的,或者单独在某个case里加上这个修饰符,表示该case是可递归的。

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case let .number(value):
        return value
    case let .addition(left, right):
        return evaluate(left) + evaluate(right)
    case let .multiplication(left, right):
        return evaluate(left) * evaluate(right)
    }
}
 
print(evaluate(product))
// Prints "18"

Classes and Structures

这一小节主要讲解的是Swift中类和结构体的用法,Swift不用像其他编程语言需要在头文件中声明属性和方法,你可以在单个文件中定义类或结构,并且该类或结构的外部接口可以自动供其他代码使用。此外,Swift中结构体与类有许多共同之处。

  • Memberwise Initializers for Structure Types

All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name:

Swift中所有结构体都会有自动生成一个初始化方法为每个属性分配值,你可以使用它初始化新结构实例的成员属性,如下代码只声明了结构体的属性,但是也会自动生成一个初始化方法,改方法可以为结构体中的每个属性分配一个值。

struct Person {
    var name: String?
    var age: String?
}
var p = Person(name: <#T##String?#>, age: <#T##String?#>)
  • Structures and Enumerations Are Value Types

All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code.

在Swift中所有的结构体和枚举都是值类型。这意味着你创建的所有的结构体和枚举(以及任何作为他们属性的值类型)在你的代码中传递时总是是copy的。

override func viewDidLoad() {
    super.viewDidLoad()
    let objInstance = testClass()
    var structInstance1 = testStruct(age: 25, obj: objInstance)
    var structInstance2 = structInstance1
    structInstance2.age = 30
}
struct testStruct {
    var age: Int?
    var obj: testClass?
}
class testClass: NSObject {
}

如上代码,自定义了一个结构体有一个Int类型的属性,和一个testClass对象属性,代码中初始化了一个objInstance实例对象objInstance,并用objInstance去初始化了一个testStruct类型的结构体structInstance1,然后又把structInstance1赋值给了另外一个结构体structInstance2,最后修改了structInstance1的age属性,调试得出以下结果:

可以看到structInstance2 的age修改之后structInstance1的age并没有改变,说明结构体在Swift中确实是值类型。此外关于"(以及任何作为他们属性的值类型)"在图中也有体现,obj是一个引用类型,所以在copy过程中并没有分配新的存储空间,而是引用了objInstance。

  • Classes Are Reference Types

类是引用类型的。

let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0

let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Prints "The frameRate property of tenEighty is now 30.0"
  • Identity Operators

Identical to (===)
Not identical to (!==)
使用这些运算符检查两个常量或变量是否引用同一个实例:

let view1 = UIView()
let view2 = UIView()
let view3 = view1       
print(view1 === view2)
print(view1 === view3)
//false     true

至于==和===有什么区别,官方文档上有这么一句话.

Note that “identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==):
“Identical to” means that two constants or variables of class type refer to exactly the same class instance.
“Equal to” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer.

“相同”表示两个常量或类类型的变量引用完全相同的类实例。
“相等”意味着两个实例在价值上被认为是“相等的”或“等价的”,这是由“类型”设计者定义的“相等”的适当含义。
还是不太理解二者的区别,不过后面会有讲解,如果有懂的大神希望可以指点一下.

  • Pointers

If you have experience with C, C++, or Objective-C, you may know that these languages use pointers to refer to addresses in memory. A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but is not a direct pointer to an address in memory, and does not require you to write an asterisk (*) to indicate that you are creating a reference. Instead, these references are defined like any other constant or variable in Swift.

对于指针这一块,文档上暂时只有这么一段话描述,Swift中引用某些引用类型的实例常量或实例变量类似于C中的指针,但不是指向内存中地址的直接指针。

最后有段话也值得记录一下:

Assignment and Copy Behavior for Strings, Arrays, and Dictionaries
In Swift, many basic data types such as String, Array, and Dictionary are implemented as structures. This means that data such as strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.

This behavior is different from Foundation: NSString, NSArray, and NSDictionary are implemented as classes, not structures. Strings, arrays, and dictionaries in Foundation are always assigned and passed around as a reference to an existing instance, rather than as a copy.

在SWIFT中,许多基本数据类型(如字符串、数组和字典)被实现为结构体。这意味着当字符串、数组和字典被分配给一个新的常量或变量时,或者当它们被传递给函数或方法时,他们都是被copy的。
不同于Foundation框架中的NSString,NSArray,和NSDictionary,他们都是类,不是结构体。所以Foundation中的 字符串,数组,和字典在分配和传递时通常是引用的形式而不是copy。


Properties

这一小节主要讲解的是Swift中的属性。这一小节的知识点不多,主要是属性的get set willSet 和 didSet的使用。
值得注意的是一个static和class的区别。我平时开发中都有过用static和class去定义一个类方法,之前也不太了解两者的区别,看到官方文档中有提及,但是限于英文水平有限去查阅了一些资料发现,class定义的方法可以被子类重写,而static的不能(感觉相当于calss final)。

class ClassA {
    class func func1() -> String {
        return "func1"
    }
    static func func2() -> String {
        return "func2"
    }
    class final func func3() -> String {
        return "func3"
    }
} 
class ClassB : ClassA {
    override class func func1() -> String {
        return "func1 in ClassB"
    }
    // ERROR: Cannot override static method
    override static func func2() -> String {
        return "func2 in ClassB"
    }
    // ERROR: Class method overrides a 'final` class method
    override class func func3() -> String {
        return "func3 in ClassB"
    }
} 

Methods

这一小节主要讲解的是Swift中方法的相关用法。
和oc不同的是,Swift中结构体和枚举也可以定义方法。

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"

enum TriStateSwitch {
    case off, low, high
    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight is now equal to .high
ovenLight.next()
// ovenLight is now equal to .off

关于mutating(变异方法)在第一篇文章Swift之旅_Welcome to Swift有提到过中有提及过,可以参考一下。


Subscripts

这一小节主要讲解了Swift中下标的语法,不看还真不知道Swift中下标可以这样用。
以前只知道数组和字典可以用下标语法,但是在Swift中,类、结构体和枚举都可以定义自己的下标。

  • Subscript Syntax

为结构体定义下标,这样用起来感觉像是数组= =。在结构体、枚举和类中的方法都如下:

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// Prints "six times three is 18"

也可以在subscript中传入多个参数

struct Matrix {
    let rows: Int, sections: Int
    subscript(section: Int, row: Int) -> Int {
        return section * rows + row
    }
}
let threeTimesTable = Matrix(rows: 10, sections: 5)
print(threeTimesTable[2,5])
// 25

Inheritance

这一小节主要讲解的是Swift中的继承。基本没啥难度,大部分是在讲重写属性、方法、下标。不过最后倒是有一个修饰符以前没注意过。

  • Preventing Overrides

You can prevent a method, property, or subscript from being overridden by marking it as final. Do this by writing the final modifier before the method, property, or subscript’s introducer keyword (such as final var, final func, final class func, and final subscript).
Any attempt to override a final method, property, or subscript in a subclass is reported as a compile-time error. Methods, properties, or subscripts that you add to a class in an extension can also be marked as final within the extension’s definition.
You can mark an entire class as final by writing the final modifier before the class keyword in its class definition (final class). Any attempt to subclass a final class is reported as a compile-time error.

final修饰符加载属性、方法或者下标前面可以防止它被重写。尝试去重写被final修饰的属性、方法或者下标会得到一个编译时的错误。在extension中被final标记的也是一样。你也可以在一个类前面加上这个修饰符,这样其他类就不能继承此类。

推荐阅读更多精彩内容