Swift之旅_Language Guide5

本來打算一禮拜看完的哮针,后來一鼓作氣把最后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)算過程如圖:
負(fù)方向溢出

帶符號(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)算過程如圖:
帶符號(hào)負(fù)方向溢出
  • 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é)啦~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末峰弹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子融师,更是在濱河造成了極大的恐慌蚁吝,老刑警劉巖窘茁,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異房待,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)张抄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門署惯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镣隶,“玉大人,你說我怎么就攤上這事轻猖∮蚰牵” “怎么了次员?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長市殷。 經(jīng)常有香客問我刹衫,道長带迟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任黄选,我火速辦了婚禮婶肩,結(jié)果婚禮上律歼,老公的妹妹穿的比我還像新娘啡专。我一直安慰自己,他們只是感情好畔况,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布跷跪。 她就那樣靜靜地躺著,像睡著了一般葛菇。 火紅的嫁衣襯著肌膚如雪橡羞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天莺债,我揣著相機(jī)與錄音齐邦,去河邊找鬼覆致。 笑死,一個(gè)胖子當(dāng)著我的面吹牛儡羔,可吹牛的內(nèi)容都是我干的璧诵。 我是一名探鬼主播之宿,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼色难!你這毒婦竟也來了等缀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對情侶失蹤冒掌,失蹤者是張志新(化名)和其女友劉穎蹲盘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铃诬,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氧急,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年吩坝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哑蔫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嵌纲,死狀恐怖逮走,靈堂內(nèi)的尸體忽然破棺而出今阳,到底是詐尸還是另有隱情,我是刑警寧澤墓臭,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布窿锉,位于F島的核電站膝舅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鼻疮。R本人自食惡果不足惜琳轿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一崭篡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧迹炼,春花似錦颠毙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霎奢。三九已至,卻和暖如春帝美,著一層夾襖步出監(jiān)牢的瞬間晤硕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工女责, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抵知,地道東北人软族。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓立砸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浊闪。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 本章將會(huì)介紹 模塊和源文件訪問級(jí)別訪問控制語法自定義類型子類常量翩腐、變量、屬性何什、下標(biāo)構(gòu)造器協(xié)議擴(kuò)展泛型類型別名位運(yùn)算...
    寒橋閱讀 877評(píng)論 0 2
  • 擴(kuò)展 擴(kuò)展就是向一個(gè)已有的類富俄、結(jié)構(gòu)體而咆、枚舉類型或者協(xié)議類型添加新功能。這包括在沒有權(quán)限獲取原始源代碼的情況下擴(kuò)展類...
    cht005288閱讀 460評(píng)論 0 0
  • 136.泛型 泛型代碼讓你可以寫出靈活,可重用的函數(shù)和類型,它們可以使用任何類型,受你定義的需求的約束悠瞬。你可以寫出...
    無灃閱讀 1,454評(píng)論 0 4
  • Hello Word 在屏幕上打印“Hello, world”浅妆,可以用一行代碼實(shí)現(xiàn): 你不需要為了輸入輸出或者字符...
    restkuan閱讀 3,169評(píng)論 0 6
  • 訪問控制 可以限定其它源文件或模塊中的代碼對你的代碼的訪問級(jí)別凌外。這個(gè)特性可以讓我們隱藏代碼的一些實(shí)現(xiàn)細(xì)節(jié)涛浙,并且可以...
    答案MK閱讀 271評(píng)論 0 0