Swift5 基礎(chǔ)(三)屬性冷蚂、方法缭保、下標(biāo)

Swift5 基礎(chǔ)教程與進(jìn)階合集

一. 屬性

Swift中跟實(shí)例相關(guān)的屬性可以分為兩大類:
存儲(chǔ)屬性(Stored Property)

  • 類似于成員變量這個(gè)概念
  • 存儲(chǔ)在實(shí)例的內(nèi)存中
  • 結(jié)構(gòu)體、類可以定義存儲(chǔ)屬性
  • 枚舉不可以定義存儲(chǔ)屬性

計(jì)算屬性(Computed Property):

  • 本質(zhì)就是方法(函數(shù))
  • 不占用實(shí)例的內(nèi)存
  • 枚舉蝙茶、結(jié)構(gòu)體艺骂、類都可以定義計(jì)算屬性
struct Circle{
    //存儲(chǔ)屬性
    var radius: Double
    //計(jì)算屬性
    var diameter: Double{
        set {
            radius = newValue/2
        }get{
            radius * 2
        }
    }
}

存儲(chǔ)屬性

關(guān)于存儲(chǔ)屬性,Swift有個(gè)明確的規(guī)定
在創(chuàng)建類或結(jié)構(gòu)體的實(shí)例時(shí)隆夯,必須為所有的存儲(chǔ)屬性設(shè)置一個(gè)合適的初始值

  • 可以在初始化器里為存儲(chǔ)屬性設(shè)置一個(gè)初始值
  • 可以分配一個(gè)默認(rèn)的屬性值作為屬性定義的一部分

計(jì)算屬性

  • set傳入的新值默認(rèn)叫做newValue钳恕,也可以自定義
struct Circle{
    var radius: Double
    var diameter: Double{
        set (newDiamater){
            radius = newDiamater/2
        }get{
            radius * 2
        }
    }
}
  • 定義計(jì)算屬性只能用var,不能用let

??let代表常量:值是一成不變的
??計(jì)算屬性的值是可能發(fā)生變化的(即使是只讀計(jì)算屬性)

  • 只讀計(jì)算屬性:只有g(shù)et蹄衷,沒有set
struct Circle{
    var radius: Double
    var diameter: Double{
        get{
            radius * 2
        }
    }
}

//只有g(shù)et的話可以省略get關(guān)鍵字
struct Circle{
    var radius: Double
    var diameter: Double{
        radius * 2
    }
}

枚舉rawValue的原理

枚舉原始值rawValue的本質(zhì)是:只讀計(jì)算屬性

enum TestEnum : Int {
    case test1 = 1,test2,test3
    //這里對(duì)rawValue進(jìn)行了重寫
    var rawValue: Int{
        switch self {
        case .test1:
            return 10
        case .test2:
            return 11
        case .test3:
            return 12
        }
    }
}
print(TestEnum.test3.rawValue)//12

延遲存儲(chǔ)屬性(Lazy Stored Property)

使用lazy可以定義一個(gè)延遲存儲(chǔ)屬性忧额,在第一次用到屬性的時(shí)候才會(huì)進(jìn)行初始化

  • lazy屬性必須是var,不能是let愧口,因?yàn)閘et必須在實(shí)例的初始化方法完成之前就擁有值
  • 如果多條線程同時(shí)第一次訪問lazy屬性睦番,無法保證屬性只被初始化一次
class Car{
    init() {
        print("Car init")
    }
    func run() {
        print("Car is running")
    }
}

class Person{
    lazy var car = Car()
    init() {
        print("Person init")
    }
    func goOut() {
        car.run()
    }
}

let p = Person()
p.goOut()
//打印結(jié)果
//Person init
//Car init
//Car is running

當(dāng)結(jié)構(gòu)體包含一個(gè)延遲存儲(chǔ)屬性時(shí),只有var才能訪問延遲存儲(chǔ)屬性耍属。因?yàn)檠舆t屬性初始化時(shí)需要改變結(jié)構(gòu)體的內(nèi)存

struct Point{
    var x = 0
    var y = 0
    lazy var z = 0
}
//let的p無法訪問到延遲存儲(chǔ)屬性
//let p = Point()
//print(p.z)
var p = Point()
print(p.z)//0

屬性觀察器

可以為非lazyvar存儲(chǔ)屬性設(shè)置屬性觀察器

struct Circle{
    var radius: Double{
        willSet{
            print("willSet",newValue)
        }
        didSet{
            print("didSet",oldValue)
        }
    }
    init() {
        radius = 1.0
        print("Circle init")
    }
}
var circle = Circle()
circle.radius = 2.5
print(circle.radius)
//打印結(jié)果
//Circle init
//willSet 2.5
//didSet 1.0
//2.5
  • willSet會(huì)傳遞新值抡砂,默認(rèn)叫newValue大咱,也可以自定義
  • didSet會(huì)傳遞舊值,默認(rèn)叫oldValue注益,也可以自定義
  • 初始化器中設(shè)置屬性值不會(huì)觸發(fā)willSet和didSet
  • 屬性定義時(shí)設(shè)置初始值也不會(huì)觸發(fā)willSet和didSet

全局變量碴巾、局部變量

屬性觀察期、計(jì)算屬性的功能丑搔,同樣可以應(yīng)用在全局變量厦瓢、局部變量上

//全局計(jì)算屬性
var num: Int{
    get{
        10
    }
    set{
        print("setNum",newValue)
    }
}
num = 22//setNum 22
print(num)//10 由于計(jì)算屬性不具有存儲(chǔ)功能,之前設(shè)置的值沒有保存啤月,所以還是直接拿的get返回的值

func test(){
    var age = 10{
        willSet{
            print("willSet",newValue)
        } didSet{
            print("didSet",oldValue)
        }
    }
    age = 11
}
test()
//willSet 11
//didSet 10

inout的再次研究

struct Shape{
    var width: Int
    var side: Int{
        willSet{
            print("willSetSide",newValue)
        }didSet{
            print("didSetSide",oldValue,side)
        }
    }
    var girth: Int{
        set {
            width = newValue/side
            print("setGirth",newValue)
        }
        get{
            print("getGirth")
            return width*side
        }
    }
    func show() {
        print("width=\(width),side=\(side),girth=\(girth)")
    }
}

func test(_ num: inout Int){
    num = 20
}

var s = Shape(width: 10, side: 4)
test(&s.width)
s.show()
print("-----------")
test(&s.side)
s.show()
print("-----------")
test(&s.girth)
s.show()
//打印結(jié)果
//getGirth
//width=20,side=4,girth=80
//-----------
//willSetSide 20
//didSetSide 4 20
//getGirth
//width=20,side=20,girth=400
//-----------
//getGirth
//setGirth 20
//getGirth
//width=1,side=20,girth=20

inout的本質(zhì)總結(jié):

  • 如果實(shí)參有物理內(nèi)存地址煮仇,且沒有設(shè)置屬性觀察值,直接將實(shí)參的內(nèi)存地址傳入函數(shù)(實(shí)參進(jìn)行引用傳遞)
  • 如果實(shí)參是計(jì)算屬性或者設(shè)置了屬性觀察值谎仲,采用了Copy In Copy Out的做法浙垫,即:

??1.調(diào)用該函數(shù)時(shí),先復(fù)制實(shí)參的值郑诺,產(chǎn)生副本(get)
??2.將副本的內(nèi)存地址傳入函數(shù)(副本進(jìn)行引用傳遞)夹姥,在函數(shù)內(nèi)部可以修改副本的值
??3.函數(shù)返回后,再將副本的值覆蓋實(shí)參的值(set)

總結(jié):inout的本質(zhì)就是引用傳遞(地址傳遞)

類型屬性(Type Property)

嚴(yán)格來說辙诞,屬性可以分為:

  • 實(shí)例屬性(Instance Property):只能通過實(shí)例去訪問
    ??存儲(chǔ)實(shí)例屬性(Stored Instance Property):存儲(chǔ)在實(shí)例的內(nèi)存中辙售,每個(gè)實(shí)例都有1份
    ??計(jì)算實(shí)例屬性(Computed Instance Property)

  • 類型屬性(Type Property):只能通過類型去訪問
    ??存儲(chǔ)類型屬性(Stored Type Property):整個(gè)程序運(yùn)行過程中,就只有1份內(nèi)存(類似于全局變量)
    ??計(jì)算類型屬性(Computed Type Property)

可以通過static定義類型屬性飞涂,如果是類旦部,也可以用關(guān)鍵字class

struct Car{
    static var count: Int = 0
    init() {
        Car.count += 1
    }
}
let c1 = Car()
let c2 = Car()
let c3 = Car()
print(Car.count)//3

類型屬性細(xì)節(jié):

  1. 不同于存儲(chǔ)實(shí)例屬性,必須給存儲(chǔ)類型屬性設(shè)置初始值较店,因?yàn)轭愋蜎]有像實(shí)例那樣的init初始化器來初始化存儲(chǔ)屬性
  2. 存儲(chǔ)類型屬性默認(rèn)就是lazy士八,會(huì)在第一次使用的時(shí)候才初始化,就算被多個(gè)線程同時(shí)訪問梁呈,保證只會(huì)初始化一次婚度;存儲(chǔ)類型屬性可以是let
  3. 枚舉類型也可以定義類型屬性(存儲(chǔ)類型屬性、計(jì)算類型屬性)

單例模式

public class FileManager{
    public static let shared = FileManager()
    private init(){}
}
public class FileManager{
    public static let shared = {
        FileManager()
    }()
    private init(){}
}

二.方法

方法(Method)

  • 枚舉捧杉、結(jié)構(gòu)體、類都可以定義實(shí)例方法秘血、類型方法
  • 實(shí)例方法(Instance Method):通過實(shí)例對(duì)象調(diào)用
  • 類型方法(Type Method):通過類型調(diào)用味抖,用static或者class關(guān)鍵字定義
struct Car{
    static var count: Int = 0
    init() {
        Car.count += 1
    }
    //大括號(hào)中的count等價(jià)于self.count,Car.self.count,Car.count
    static func getCount() -> Int { count }
}
let c1 = Car()
let c2 = Car()
let c3 = Car()
print(Car.getCount())//3

self:

  • 在實(shí)例方法中代表實(shí)例對(duì)象
  • 在類型方法中代表類型

mutating

結(jié)構(gòu)體和枚舉是值類型,默認(rèn)情況下灰粮,值類型的屬性不能被自身的實(shí)例方法修改
在func關(guān)鍵字前面加mutating可以允許這種修改行為

struct Point{
    var x = 0.0
    var y = 0.0
    mutating func moveBy(deltaX: Double,deletaY: Double){
        x += deltaX
        y += deletaY
    }
}

enum StateSwitch{
    case low,middle,high
    mutating func next(){
        switch self {
        case .low:
            self = .middle
        case .middle:
            self = .high
        case .high:
            self = .low
        }
    }
}

@discardableResult

在func前面加個(gè)@discardableResult仔涩,可以消除:函數(shù)調(diào)用后返回值未被使用的警告

struct Point{
    var x = 0.0
    var y = 0.0
    @discardableResult mutating func moveBy(deltaX: Double,deletaY: Double) -> Point{
        x += deltaX
        y += deletaY
        return self
    }
}

var p = Point()
p.moveBy(deltaX: 0.4, deletaY: 0.7)


@discardableResult func get() -> Int{
    return 10
}
get()

三. 下標(biāo)

下標(biāo)(subscript)

使用subscript可以給任意類型(枚舉、結(jié)構(gòu)體粘舟、類)增加下標(biāo)功能熔脂,有些地方也翻譯為:下標(biāo)腳本
subscript的語法類似于實(shí)例方法佩研、計(jì)算屬性,本質(zhì)就是方法(函數(shù))

class Point{
    var x = 0.0
    var y = 0.0
    subscript(index: Int) -> Double{
        set {
            if index == 0 {
                x = newValue
            } else if index == 1 {
                y = newValue
            }
        }
        get{
            if index == 0 {
                return x
            } else if index == 1 {
                return y
            }
            return 0
        }
    }
}

var p = Point()
p[0] = 1.1
p[1] = 2.2
print("p.x=\(p.x),p.y=\(p.y),p[0]=\(p[0]),p[1]=\(p[1])")
//打印結(jié)果
//p.x=1.1,p.y=2.2,p[0]=1.1,p[1]=2.2
  • subscript中定義的返回值類型決定了

??get方法的返回值類型
??set方法中newValue的類型

  • subscript可以接受多個(gè)參數(shù)霞揉,并且類型任意

  • subscript可以沒有set方法旬薯,但必須有g(shù)et方法,如果只有g(shù)et方法适秩,可以省略get

class Point{
    var x = 0.0
    var y = 0.0
    subscript(index: Int) -> Double{
        if index == 0 {
            return x
        } else if index == 1 {
            return y
        }
        return 0
    }
}
  • 可以設(shè)置參數(shù)標(biāo)簽
class Point{
    var x = 0.0
    var y = 0.0
    subscript(index i: Int) -> Double{
        if i == 0 {
            return x
        } else if i == 1 {
            return y
        }
        return 0
    }
}
var p = Point()
p.y = 2.2
print(p[index: 1])//2.2
  • 下標(biāo)可以是類型方法
class Sum{
    static subscript(v1: Int,v2: Int) -> Int{
        v1 + v2
    }
}
print(Sum[10,20])//30

結(jié)構(gòu)體绊序、類作為返回值

class Point{
    var x = 0.0
    var y = 0.0
    
}
class PointManager {
    var point = Point()
    subscript(index: Int) -> Point{
        point
    }
}
var pm = PointManager()
pm[0].x = 11
pm[0].y = 22
print(pm[0])//__lldb_expr_26.Point
print(pm.point)//__lldb_expr_26.Point
struct Point{
    var x = 0.0
    var y = 0.0
    
}
class PointManager {
    var point = Point()
    subscript(index: Int) -> Point{
        set { point = newValue }
        get { point }
    }
}
var pm = PointManager()
pm[0].x = 11
pm[0].y = 22
print(pm[0])//Point(x: 11.0, y: 22.0)
print(pm.point)//Point(x: 11.0, y: 22.0)

接收多個(gè)參數(shù)的下標(biāo)

class Grid{
    var data = [
        [0,1,2],
        [3,4,5],
        [6,7,8]
    ]
    subscript(row: Int, column: Int) -> Int{
        set{
            guard row >= 0 && row < 3 && column >= 0 && column < 3 else {
                return
            }
            data[row][column] = newValue
        } get {
            guard row >= 0 && row < 3 && column >= 0 && column < 3 else {
                return 0
            }
            return data[row][column]
        }
    }
}
var grid = Grid()
grid[0,1] = 77
grid[1,2] = 88
grid[2,0] = 99
print(grid.data)//[[0, 77, 2], [3, 4, 88], [99, 7, 8]]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市秽荞,隨后出現(xiàn)的幾起案子骤公,更是在濱河造成了極大的恐慌,老刑警劉巖扬跋,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阶捆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡钦听,警方通過查閱死者的電腦和手機(jī)洒试,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來彪见,“玉大人儡司,你說我怎么就攤上這事∮嘀福” “怎么了捕犬?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)酵镜。 經(jīng)常有香客問我碉碉,道長(zhǎng),這世上最難降的妖魔是什么淮韭? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任垢粮,我火速辦了婚禮,結(jié)果婚禮上靠粪,老公的妹妹穿的比我還像新娘蜡吧。我一直安慰自己,他們只是感情好占键,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布昔善。 她就那樣靜靜地躺著,像睡著了一般畔乙。 火紅的嫁衣襯著肌膚如雪君仆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音返咱,去河邊找鬼钥庇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛咖摹,可吹牛的內(nèi)容都是我干的评姨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼楞艾,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼参咙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起硫眯,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤蕴侧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后两入,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體净宵,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年裹纳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了择葡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剃氧,死狀恐怖敏储,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情朋鞍,我是刑警寧澤已添,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站滥酥,受9級(jí)特大地震影響更舞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坎吻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一缆蝉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘦真,春花似錦刊头、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至弦讽,卻和暖如春污尉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背往产。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工被碗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仿村。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓锐朴,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蔼囊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焚志,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353