本來打算一禮拜看完的哮针,后來一鼓作氣把最后3小節(jié)給看完了。
Memory Safety
這一小節(jié)主要講解的是Swift中的內(nèi)存安全埃篓,講的是內(nèi)存訪問時(shí)候遇到的沖突問題察净。
發(fā)生內(nèi)存訪問沖突的條件:
1.至少一個(gè)是寫訪問。
2.它們在內(nèi)存中訪問相同的位置锅必。
3.它們的持續(xù)時(shí)間重疊事格。
看一下沖突代碼先:
var stepSize = 1 //這里是全局變量
func incrementInPlace(_ number: inout Int) {
number += stepSize
}
incrementInPlace(&stepSize)
// Error: conflicting accesses to stepSize
其實(shí)后面的所講的本質(zhì)上也和這個(gè)大致一樣,就是當(dāng)你在對同一塊內(nèi)存同時(shí)進(jìn)行讀和寫的時(shí)候可能會(huì)出錯(cuò)搞隐,一般都是編譯時(shí)出錯(cuò)或者運(yùn)行時(shí)崩潰驹愚。后面講的是在結(jié)構(gòu)體中內(nèi)存訪問沖突的問題,本質(zhì)上和這個(gè)相差不多劣纲。附上一張圖:-
Conflicting Access to Properties
此外逢捺,像結(jié)元組、結(jié)構(gòu)體這些值類型癞季,對任何一個(gè)值進(jìn)行修改都會(huì)改變整個(gè)值劫瞳,這意味著讀取或修改其中的一個(gè)屬性需要對整個(gè)值進(jìn)行讀或?qū)懺L問,例如面對元組和結(jié)構(gòu)體重疊寫入會(huì)產(chǎn)生沖突:
struct Player {
var name: String
var health: Int
var energy: Int
static let maxHealth = 10
mutating func restoreHealth() {
health = Player.maxHealth
}
}
func balance(_ x: inout Int, _ y: inout Int) {
let sum = x + y
x = sum / 2
y = sum - x
}
var playerInformation = (health: 10, energy: 20) //這里是全局變量
var holly = Player(name: "Holly", health: 100, energy: 10)//這里是全局變量
balance(&playerInformation.health, &playerInformation.energy)
// Error: conflicting access to properties of playerInformation
balance(&holly.health, &holly.energy)
// Error
但是后面在局部變量中又是不會(huì)出錯(cuò)的:
func someFunction() {
var oscar = Player(name: "Oscar", health: 10, energy: 10)
balance(&oscar.health, &oscar.energy) // OK
}
以下三個(gè)條件可以確保結(jié)構(gòu)體的訪問是安全的:
1.你只訪問實(shí)例的存儲(chǔ)屬性绷柒,而不是計(jì)算的屬性或類屬性志于。
2.該結(jié)構(gòu)題是局部變量的值,而不是全局變量废睦。
3.該結(jié)構(gòu)題不是由任何閉包捕獲伺绽,或者僅由非逃逸閉包捕獲。
Access Control
這一小節(jié)主要講解的是Swift中的訪問控制嗜湃。
-
Access Control Syntax
訪問控制的語法:
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}
- public&open:開放訪問&公共訪問奈应,最開放的級(jí)別杖挣,等會(huì)兒有兩者的區(qū)別介紹
- internal:內(nèi)部訪問今瀑,使實(shí)體可以在其定義模塊的任何源文件中使用程梦,但不能在該模塊之外的任* * 何源文件中使用点把。定義應(yīng)用程序或框架的內(nèi)部結(jié)構(gòu)的時(shí)候使用屿附。
- fileprivate:文件私有訪問,就是只能在當(dāng)前文件中訪問
- private:私有訪問挺份,只能在實(shí)體內(nèi)部中訪問褒翰。
開放訪問時(shí)最高訪問級(jí)別,私有訪問時(shí)最低級(jí)別匀泊。開放訪問只使用于類和類成員各聘,它與公共訪問的區(qū)別如下: - 公共訪問權(quán)限的類或者小于它的只能在其定義的模塊中進(jìn)行子類化。
- 公共訪問權(quán)限的類或者小于它的只能由其定義的模塊內(nèi)的子類重寫早敬。
- 開放訪問權(quán)限的類可以在其定義的模塊以及在任何導(dǎo)入該模塊的模塊中進(jìn)行子類化大脉。
- 開放訪問權(quán)限的類可以被其定義的模塊以及在任何導(dǎo)入該模塊的模塊中的子類重寫。
-
Custom Types
看下面一段代碼:
public class SomePublicClass { // explicitly public class
public var somePublicProperty = 0 // explicitly public class member
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
class SomeInternalClass { // implicitly internal class
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
fileprivate class SomeFilePrivateClass { // explicitly file-private class
func someFilePrivateMethod() {} // implicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
private class SomePrivateClass { // explicitly private class
func somePrivateMethod() {} // implicitly private class member
}
類型的訪問控制級(jí)別也影響該類型的成員(其屬性、方法秤标、初始化器和下標(biāo))的默認(rèn)訪問級(jí)別抛杨。如果將類型的訪問級(jí)別定義為私有或文件私有,則其成員的默認(rèn)訪問級(jí)別也將是私有的或文件私有的茁帽。如果將類型的訪問級(jí)別定義為內(nèi)部或公共(或者使用內(nèi)部的默認(rèn)訪問級(jí)別而不顯式指定訪問級(jí)別)屈嗤,則類型成員的默認(rèn)訪問級(jí)別將是內(nèi)部的饶号。
Ps:公共類型默認(rèn)為具有內(nèi)部成員,而不是公共成員琅束。如果要將類型成員公開,則必須顯式標(biāo)記該類型成員料滥。也就是說如果類型時(shí)public的艾船,那么類型內(nèi)部的成員(其屬性、方法践宴、初始化器和下標(biāo))默認(rèn)是internal而不是public的爷怀。
-
Function Types
如下一段代碼:
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}
SomeInternalClass是internal, SomePrivateClass是private霉撵,所以所返回的元組取低級(jí)別的private,因?yàn)楹瘮?shù)的返回類型是私有的,所以你必須用private來修飾函數(shù)喇完,應(yīng)該如下代碼寫才對:
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}
-
Constants, Variables, Properties, and Subscripts
將一個(gè)值賦值給常量剥啤、變量、屬性和下標(biāo)時(shí)刻诊,這個(gè)值的訪問級(jí)別必須是高于或者等于常量则涯、變量冲簿、屬性和下標(biāo)的訪問級(jí)別。如下代碼:
class Person: NSObject {
private var book1 = Book()
private class Book {
}
}
Book在這里是私有的档礁,所以這里book1必須聲明成私有以下的吝沫,如果大于私有則編譯時(shí)出錯(cuò)。
-
Getters and Setters
也可以給常量宰衙、變量睹欲、屬性和下標(biāo)的setter和getter定義訪問級(jí)別,但是setter和getter的訪問級(jí)別不能高于其常量袋哼、變量闸衫、屬性或下標(biāo)的訪問級(jí)別蔚出,如下代碼:
struct TrackedString {
internal(set) var numberOfEdits = 0
var value: String = "" {
didSet {
numberOfEdits += 1
}
}
}
var stringToEdit = TrackedString()
stringToEdit.value = "This string will be tracked."
stringToEdit.numberOfEdits = 2
如結(jié)構(gòu)體TrackedString中的numberOfEdits沒有顯示聲明訪問級(jí)別,所以它是internal稀余,他的setter和getter不能高于internal睛琳。(PS: internal(set)是將numberOfEdits的setter訪問級(jí)別設(shè)置成internal)
如果又想設(shè)置setter和getter的訪問級(jí)別踏烙,又要設(shè)置常量、變量辟癌、屬性和下標(biāo)的訪問級(jí)別可以這樣寫:
public struct TrackedString {
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
這樣子TrackedString結(jié)構(gòu)體中的numberOfEdits是公共訪問級(jí)別黍少,numberOfEdits的setter是私有訪問級(jí)別靴患。
-
Subclassing
Swift子類可以通過重寫父類的屬性或者方法達(dá)到超過其父類屬性或者方法的訪問級(jí)別鸳君,但是子類本身的訪問級(jí)別不能大于父類訪問級(jí)別:
public class A {
fileprivate func someMethod() {}
}
internal class B: A {
override internal func someMethod() {}
}
Advanced Operators
這一小節(jié)主要講解的是Swift中的高級(jí)運(yùn)算符。
-
itwise Operators
Bitwise NOT Operator:按位取反,將一個(gè)操作數(shù)的每一位都取反砸紊,使用如下:
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // equals 11110000
運(yùn)算過程如圖:Bitwise AND Operator:按位與醉顽,兩個(gè)操作數(shù)同一位都位1時(shí)為1,使用如下:
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits // equals 00111100
運(yùn)算過程如圖:Bitwise OR Operator:按位或游添,兩個(gè)操作數(shù)同一位有一個(gè)為1時(shí)為1,使用如下:
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits // equals 11111110
運(yùn)算過程如圖:Bitwise XOR Operator:按位異或找都,兩個(gè)操作數(shù)的同一位不同的時(shí)候?yàn)?能耻,使用如下:
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // equals 00010001
運(yùn)算過程如圖:Bitwise Left and Right Shift Operators:按位左移/右移,使用如下:
let shiftBits: UInt8 = 4 // 00000100 in binary
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
shiftBits >> 2 // 00000001
-
Overflow Operators
溢出操作符晓猛,如果嘗試將數(shù)字插入到不能保存該值的整數(shù)常量或變量中凡辱,則默認(rèn)情況下,Swift報(bào)告錯(cuò)誤而不是允許創(chuàng)建無效值帕涌。如下代碼會(huì)得到一個(gè)編譯時(shí)的錯(cuò)誤:
var potentialOverflow = Int16.max
// potentialOverflow equals 32767, which is the maximum value an Int16 can hold
potentialOverflow += 1
// this causes an error
當(dāng)然,swift也提供一組溢出操作符來允許這一行為的發(fā)生亲澡。
-
正方向溢出: &+
var unsignedOverflow = UInt8.max
// unsignedOverflow equals 255, which is the maximum value a UInt8 can hold
unsignedOverflow = unsignedOverflow &+ 1
// unsignedOverflow is now equal to 0
運(yùn)算過程如圖:-
負(fù)方向溢出: &-
var unsignedOverflow = UInt8.min
// unsignedOverflow equals 0, which is the minimum value a UInt8 can hold
unsignedOverflow = unsignedOverflow &- 1
// unsignedOverflow is now equal to 255
運(yùn)算過程如圖:帶符號(hào)操作的溢出時(shí)符號(hào)位也會(huì)參與運(yùn)算客情,如下:
var signedOverflow = Int8.min
// signedOverflow equals -128, which is the minimum value an Int8 can hold
signedOverflow = signedOverflow &- 1
// signedOverflow is now equal to 127
運(yùn)算過程如圖:-
Operator Methods
可以給類和結(jié)構(gòu)體定義操作符膀斋,如下給一個(gè)結(jié)構(gòu)定義一個(gè)+操作符:
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)
-
Prefix and Postfix Operators
前綴和后綴運(yùn)算符痹雅,定義如下:
extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
}
let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative is a Vector2D instance with values of (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive is a Vector2D instance with values of (3.0, 4.0)
-
Compound Assignment Operators
復(fù)合賦值操作符
extension Vector2D {
static func += (left: inout Vector2D, right: Vector2D) {
left = left + right
}
}
var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original now has values of (4.0, 6.0)
-
Equivalence Operators
相等操作符
extension Vector2D: Equatable {
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
}
let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
print("These two vectors are equivalent.")
}
// Prints "These two vectors are equivalent."
-
Custom Operators
自定義運(yùn)算符摔蓝,swift中可以自定義運(yùn)算符,需要用前綴、中綴或后綴修飾符標(biāo)記:
prefix operator +++ // 聲明成全局的
extension Vector2D {
static prefix func +++ (vector: inout Vector2D) -> Vector2D {
vector += vector
return vector
}
}
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)
-
Precedence for Custom Infix Operators
自定義中綴運(yùn)算符的優(yōu)先級(jí)
infix operator +-: AdditionPrecedence
extension Vector2D {
static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y - right.y)
}
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector is a Vector2D instance with values of (4.0, -2.0)
這里的AdditionPrecedence是一個(gè)優(yōu)先級(jí)組(與加法同一級(jí)別)拌滋。未顯式放置到優(yōu)先組中的自定義中綴運(yùn)算符被賦予默認(rèn)優(yōu)先級(jí)組败砂,其優(yōu)先級(jí)高于三目運(yùn)算符的優(yōu)先級(jí)魏铅。
總算是看完了,官方文檔中剩下貌似不需要去特別關(guān)注祭隔÷凡伲看完之后發(fā)現(xiàn)之前去大公司面試的時(shí)候被問的好多答不上來的東西,看過官方文檔之后算是有了點(diǎn)逼數(shù)了搞坝。不過這并沒有結(jié)束魁袜,看完官方文檔又得進(jìn)入下一個(gè)學(xué)習(xí)環(huán)節(jié)啦~