日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Swift之深入解析构造过程和析构过程

發布時間:2024/5/28 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Swift之深入解析构造过程和析构过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、Swift 構造過程

  • 構造過程是為了使用某個類、結構體或枚舉類型的實例而進行的準備過程,這個過程包含了為實例中的每個屬性設置初始值和為其執行必要的準備和初始化任務。
  • Swift 構造函數使用 init() 方法。與 Objective-C 中的構造器不同,Swift 的構造器無需返回值,它們的主要任務是保證新實例在第一次使用前完成正確的初始化。
  • 類實例也可以通過定義析構器(deinitializer)在類實例釋放之前執行清理內存的工作。

二、存儲型屬性的初始賦值

  • 類和結構體在實例創建時,必須為所有存儲型屬性設置合適的初始值。
  • 存儲屬性在構造器中賦值時,它們的值是被直接設置的,不會觸發任何屬性觀測器。
  • 存儲屬性在構造器中賦值流程:
    • 創建初始值;
    • 在屬性定義中指定默認屬性值;
    • 初始化實例,并調用 init() 方法。

三、構造器

① 語法

  • 構造器在創建某特定類型的新實例時調用,它的最簡形式類似于一個不帶任何參數的實例方法,以關鍵字 init 命名。
init() {// 實例化后執行的代碼 }

② 實例

  • 以下結構體定義了一個不帶參數的構造器 init,并在里面將存儲型屬性 length 和 breadth 的值初始化為 6 和 12:
struct rectangle {var length: Doublevar breadth: Doubleinit() {length = 6breadth = 12} } var area = rectangle() print("矩形面積為 \(area.length*area.breadth)")
  • 以上程序執行輸出結果為:
矩形面積為 72.0

四、默認屬性值

  • 可以在構造器中為存儲型屬性設置初始值;同樣,也可以在屬性聲明時為其設置默認值。使用默認值能讓構造器更簡潔、更清晰,且能通過默認值自動推導出屬性的類型。
  • 以下實例在屬性聲明時為其設置默認值:
struct rectangle {// 設置默認值var length = 6var breadth = 12 } var area = rectangle() print("矩形的面積為 \(area.length*area.breadth)")
  • 以上程序執行輸出結果為:
矩形面積為 72

五、構造參數

  • 可以在定義構造器 init() 時提供構造參數,如下所示:
struct Rectangle {var length: Doublevar breadth: Doublevar area: Doubleinit(fromLength length: Double, fromBreadth breadth: Double) {self.length = lengthself.breadth = breadtharea = length * breadth}init(fromLeng leng: Double, fromBread bread: Double) {self.length = lengself.breadth = breadarea = leng * bread} }let ar = Rectangle(fromLength: 6, fromBreadth: 12) print("面積為: \(ar.area)")let are = Rectangle(fromLeng: 36, fromBread: 12) print("面積為: \(are.area)")
  • 以上程序執行輸出結果為:
面積為: 72.0 面積為: 432.0

六、內部和外部參數名

  • 跟函數和方法參數相同,構造參數也存在一個在構造器內部使用的參數名字和一個在調用構造器時使用的外部參數名字。
  • 然而,構造器并不像函數和方法那樣在括號前有一個可辨別的名字。所以在調用構造器時,主要通過構造器中的參數名和類型來確定需要調用的構造器。
  • 如果在定義構造器時沒有提供參數的外部名字,Swift 會為每個構造器的參數自動生成一個跟內部名字相同的外部名。
struct Color {let red, green, blue: Doubleinit(red: Double, green: Double, blue: Double) {self.red = redself.green = greenself.blue = blue}init(white: Double) {red = whitegreen = whiteblue = white} }// 創建一個新的Color實例,通過三種顏色的外部參數名來傳值,并調用構造器 let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)print("red 值為: \(magenta.red)") print("green 值為: \(magenta.green)") print("blue 值為: \(magenta.blue)")// 創建一個新的Color實例,通過三種顏色的外部參數名來傳值,并調用構造器 let halfGray = Color(white: 0.5) print("red 值為: \(halfGray.red)") print("green 值為: \(halfGray.green)") print("blue 值為: \(halfGray.blue)")
  • 以上程序執行輸出結果為:
red 值為: 1.0 green 值為: 0.0 blue 值為: 1.0 red 值為: 0.5 green 值為: 0.5 blue 值為: 0.5
  • 沒有外部名稱參數,如果不希望為構造器的某個參數提供外部名字,可以使用下劃線_來顯示描述它的外部名。
struct Rectangle {var length: Doubleinit(frombreadth breadth: Double) {length = breadth * 10}init(frombre bre: Double) {length = bre * 30}//不提供外部名字init(_ area: Double) {length = area} }// 調用不提供外部名字 let rectarea = Rectangle(180.0) print("面積為: \(rectarea.length)")// 調用不提供外部名字 let rearea = Rectangle(370.0) print("面積為: \(rearea.length)")// 調用不提供外部名字 let recarea = Rectangle(110.0) print("面積為: \(recarea.length)")
  • 以上程序執行輸出結果為:
面積為: 180.0 面積為: 370.0 面積為: 110.0

七、可選屬性類型

  • 如果定制的類型包含一個邏輯上允許取值為空的存儲型屬性,都需要將它定義為可選類型optional type(可選屬性類型)。
  • 當存儲屬性聲明為可選時,將自動初始化為空 nil。
struct Rectangle {var length: Double?init(frombreadth breadth: Double) {length = breadth * 10}init(frombre bre: Double) {length = bre * 30}init(_ area: Double) {length = area} }let rectarea = Rectangle(180.0) print("面積為:\(rectarea.length)")let rearea = Rectangle(370.0) print("面積為:\(rearea.length)")let recarea = Rectangle(110.0) print("面積為:\(recarea.length)")
  • 以上程序執行輸出結果為:
面積為:Optional(180.0) 面積為:Optional(370.0) 面積為:Optional(110.0)

八、構造過程中修改常量屬性

  • 只要在構造過程結束前常量的值能確定,可以在構造過程中的任意時間點修改常量屬性的值。
  • 對某個類實例來說,它的常量屬性只能在定義它的類的構造過程中修改;不能在子類中修改。
  • 盡管 length 屬性現在是常量,仍然可以在其類的構造器中設置它的值:
struct Rectangle {let length: Double?init(frombreadth breadth: Double) {length = breadth * 10}init(frombre bre: Double) {length = bre * 30}init(_ area: Double) {length = area} }let rectarea = Rectangle(180.0) print("面積為:\(rectarea.length)")let rearea = Rectangle(370.0) print("面積為:\(rearea.length)")let recarea = Rectangle(110.0) print("面積為:\(recarea.length)")
  • 以上程序執行輸出結果為:
面積為:Optional(180.0) 面積為:Optional(370.0) 面積為:Optional(110.0)

九、默認構造器

  • 默認構造器將簡單的創建一個所有屬性值都設置為默認值的實例。如下所示,ShoppingListItem 類中的所有屬性都有默認值,且它是沒有父類的基類,它將自動獲得一個可以為所有屬性設置默認值的默認構造器:
class ShoppingListItem {var name: String?var quantity = 1var purchased = false } var item = ShoppingListItem()print("名字為: \(item.name)") print("數理為: \(item.quantity)") print("是否付款: \(item.purchased)")
  • 以上程序執行輸出結果為:
名字為: nil 數理為: 1 是否付款: false
  • 結構體的逐一成員構造器,如果結構體對所有存儲型屬性提供了默認值且自身沒有提供定制的構造器,它們能自動獲得一個逐一成員構造器。
  • 在調用逐一成員構造器時,通過與成員屬性名相同的參數名進行傳值來完成對成員屬性的初始賦值。
  • 下面例子中定義了一個結構體 Rectangle,它包含兩個屬性 length 和 breadth。Swift 可以根據這兩個屬性的初始賦值100.0 、200.0自動推導出它們的類型 Double。
struct Rectangle {var length = 100.0, breadth = 200.0 } let area = Rectangle(length: 24.0, breadth: 32.0)print("矩形的面積: \(area.length)") print("矩形的面積: \(area.breadth)")
  • 由于這兩個存儲型屬性都有默認值,結構體 Rectangle 自動獲得了一個逐一成員構造器 init(width:height:),可以用它來為 Rectangle 創建新的實例。以上程序執行輸出結果為:
矩形的面積: 24.0 矩形的面積: 32.0

十、值類型的構造器代理

  • 構造器可以通過調用其它構造器來完成實例的部分構造過程,這一過程稱為構造器代理,它能減少多個構造器間的代碼重復。
  • 如下所示,Rect 結構體調用了 Size 和 Point 的構造過程:
struct Size {var width = 0.0, height = 0.0 } struct Point {var x = 0.0, y = 0.0 }struct Rect {var origin = Point()var size = Size()init() {}init(origin: Point, size: Size) {self.origin = originself.size = size}init(center: Point, size: Size) {let originX = center.x - (size.width / 2)let originY = center.y - (size.height / 2)self.init(origin: Point(x: originX, y: originY), size: size)} }// origin和size屬性都使用定義時的默認值Point(x: 0.0, y: 0.0)和Size(width: 0.0, height: 0.0): let basicRect = Rect() print("Size 結構體初始值: \(basicRect.size.width, basicRect.size.height) ") print("Rect 結構體初始值: \(basicRect.origin.x, basicRect.origin.y) ")// 將origin和size的參數值賦給對應的存儲型屬性 let originRect = Rect(origin: Point(x: 2.0, y: 2.0),size: Size(width: 5.0, height: 5.0))print("Size 結構體初始值: \(originRect.size.width, originRect.size.height) ") print("Rect 結構體初始值: \(originRect.origin.x, originRect.origin.y) ")//先通過center和size的值計算出origin的坐標。 //然后再調用(或代理給)init(origin:size:)構造器來將新的origin和size值賦值到對應的屬性中 let centerRect = Rect(center: Point(x: 4.0, y: 4.0),size: Size(width: 3.0, height: 3.0))print("Size 結構體初始值: \(centerRect.size.width, centerRect.size.height) ") print("Rect 結構體初始值: \(centerRect.origin.x, centerRect.origin.y) ")
  • 以上程序執行輸出結果為:
Size 結構體初始值: (0.0, 0.0) Rect 結構體初始值: (0.0, 0.0) Size 結構體初始值: (5.0, 5.0) Rect 結構體初始值: (2.0, 2.0) Size 結構體初始值: (3.0, 3.0) Rect 結構體初始值: (2.5, 2.5)
  • 構造器代理規則:
值類型類類型
不支持繼承,所以構造器代理的過程相對簡單,因為它們只能代理給本身提供的其它構造器,可以使用self.init在自定義的構造器中引用其它的屬于相同值類型的構造器它可以繼承自其它類,這意味著類有責任保證其所有繼承的存儲型屬性在構造時也能正確的初始化

十一、類的繼承和構造過程

  • Swift 提供了兩種類型的類構造器來確保所有類實例中存儲型屬性都能獲得初始值,它們分別是指定構造器和便利構造器。
指定構造器便利構造器
類中最主要的構造器類中比較次要的、輔助型的構造器
初始化類中提供的所有屬性,并根據父類鏈往上調用父類的構造器來實現父類的初始化可以定義便利構造器來調用同一個類中的指定構造器,并為其參數提供默認值。你也可以定義便利構造器來創建一個特殊用途或特定輸入的實例
每一個類都必須擁有至少一個指定構造器只在必要的時候為類提供便利構造器
Init(parameters) { statements }convenience init(parameters) { statements}
  • 指定構造器實例
class mainClass {var no1 : Int // 局部存儲變量init(no1 : Int) {self.no1 = no1 // 初始化} } class subClass : mainClass {var no2 : Int // 新的子類存儲變量init(no1 : Int, no2 : Int) {self.no2 = no2 // 初始化super.init(no1:no1) // 初始化超類} }let res = mainClass(no1: 10) let res2 = subClass(no1: 10, no2: 20)print("res 為: \(res.no1)") print("res2 為: \(res2.no1)") print("res2 為: \(res2.no2)")
  • 以上程序執行輸出結果為:
res 為: 10 res 為: 10 res 為: 20
  • 便利構造器實例
class mainClass {var no1 : Int // 局部存儲變量init(no1 : Int) {self.no1 = no1 // 初始化} }class subClass : mainClass {var no2 : Intinit(no1 : Int, no2 : Int) {self.no2 = no2super.init(no1:no1)}// 便利方法只需要一個參數override convenience init(no1: Int) {self.init(no1:no1, no2:0)} } let res = mainClass(no1: 20) let res2 = subClass(no1: 30, no2: 50)print("res 為: \(res.no1)") print("res2 為: \(res2.no1)") print("res2 為: \(res2.no2)")
  • 以上程序執行輸出結果為:
res 為: 20 res2 為: 30 res2 為: 50

十二、構造器的繼承和重載

  • Swift 中的子類不會默認繼承父類的構造器。
  • 父類的構造器僅在確定和安全的情況下被繼承。
  • 當重寫一個父類指定構造器時,需要寫 override 修飾符。
class SuperClass {var corners = 4var description: String {return "\(corners) 邊"} } let rectangle = SuperClass() print("矩形: \(rectangle.description)")class SubClass: SuperClass {override init() { //重載構造器super.init()corners = 5} }let subClass = SubClass() print("五角型: \(subClass.description)")
  • 以上程序執行輸出結果為:
矩形: 4 邊 五角型: 5
  • 如下所示,在操作中展示指定構造器、便利構造器和自動構造器的繼承,它定義了包含兩個個類 MainClass、SubClass 的類層次結構,并將演示它們的構造器是如何相互作用的:
class MainClass {var name: Stringinit(name: String) {self.name = name}convenience init() {self.init(name: "[匿名]")} } let main = MainClass(name: "Runoob") print("MainClass 名字為: \(main.name)")let main2 = MainClass() print("沒有對應名字: \(main2.name)")class SubClass: MainClass {var count: Intinit(name: String, count: Int) {self.count = countsuper.init(name: name)}override convenience init(name: String) {self.init(name: name, count: 1)} }let sub = SubClass(name: "Runoob") print("MainClass 名字為: \(sub.name)")let sub2 = SubClass(name: "Runoob", count: 3) print("count 變量: \(sub2.count)")
  • 以上程序執行輸出結果為:
MainClass 名字為: Runoob 沒有對應名字: [匿名] MainClass 名字為: Runoob count 變量: 3

十三、類的可失敗構造器

  • 如果一個類,結構體或枚舉類型的對象,在構造自身的過程中有可能失敗,則為其定義一個可失敗構造器。
  • 變量初始化失敗可能的原因有:
    • 傳入無效的參數值;
    • 缺少某種所需的外部資源;
    • 沒有滿足特定條件。
  • 為了妥善處理這種構造過程中可能會失敗的情況,可以在一個類,結構體或是枚舉類型的定義中,添加一個或多個可失敗構造器,其語法為在 init 關鍵字后面加添問號(init?)。
  • 如下,定義了一個名為 Animal 的結構體,其中有一個名為 species 的,String 類型的常量屬性,同時該結構體還定義了一個,帶一個 String 類型參數 species 的,可失敗構造器。這個可失敗構造器,被用來檢查傳入的參數是否為一個空字符串,如果為空字符串,則該可失敗構造器,構建對象失敗,否則成功。
struct Animal {let species: Stringinit?(species: String) {if species.isEmpty { return nil }self.species = species} }//通過該可失敗構造器來構建一個Animal的對象,并檢查其構建過程是否成功 // someCreature 的類型是 Animal? 而不是 Animal let someCreature = Animal(species: "長頸鹿")// 打印 "動物初始化為長頸鹿" if let giraffe = someCreature {print("動物初始化為\(giraffe.species)") }
  • 以上程序執行輸出結果為:
動物初始化為長頸鹿
  • 枚舉類型的可失敗構造器,可以通過構造一個帶一個或多個參數的可失敗構造器來獲取枚舉類型中特定的枚舉成員。
  • 如下所示,定義了一個名為 TemperatureUnit 的枚舉類型,其中包含了三個可能的枚舉成員(Kelvin,Celsius,和 Fahrenheit)和一個被用來找到 Character 值所對應的枚舉成員的可失敗構造器:
enum TemperatureUnit {// 開爾文,攝氏,華氏case Kelvin, Celsius, Fahrenheitinit?(symbol: Character) {switch symbol {case "K":self = .Kelvincase "C":self = .Celsiuscase "F":self = .Fahrenheitdefault:return nil}} }let fahrenheitUnit = TemperatureUnit(symbol: "F") if fahrenheitUnit != nil {print("這是一個已定義的溫度單位,所以初始化成功。") }let unknownUnit = TemperatureUnit(symbol: "X") if unknownUnit == nil {print("這不是一個已定義的溫度單位,所以初始化失敗。") }
  • 以上程序執行輸出結果為:
這是一個已定義的溫度單位,所以初始化成功。 這不是一個已定義的溫度單位,所以初始化失敗。
  • 值類型(如結構體或枚舉類型)的可失敗構造器,對何時何地觸發構造失敗這個行為沒有任何的限制。但是,類的可失敗構造器只能在所有的類屬性被初始化后和所有類之間的構造器之間的代理調用發生完后觸發失敗行為。
  • 如下,定義了一個名為 StudRecord 的類,因為 studname 屬性是一個常量,所以一旦 StudRecord 類構造成功,studname 屬性肯定有一個非 nil 的值。
class StudRecord {let studname: String!init?(studname: String) {self.studname = studnameif studname.isEmpty { return nil }} } if let stname = StudRecord(studname: "失敗構造器") {print("模塊為 \(stname.studname)") }
  • 以上程序執行輸出結果為:
模塊為 失敗構造器

十四、覆蓋一個可失敗構造器

  • 就如同其它構造器一樣,你也可以用子類的可失敗構造器覆蓋基類的可失敗構造器。也可以用子類的非可失敗構造器覆蓋一個基類的可失敗構造器。可以用一個非可失敗構造器覆蓋一個可失敗構造器,但反過來卻行不通。
  • 一個非可失敗的構造器永遠也不能代理調用一個可失敗構造器。
  • 以下實例描述了可失敗與非可失敗構造器:
class Planet {var name: Stringinit(name: String) {self.name = name}convenience init() {self.init(name: "[No Planets]")} } let plName = Planet(name: "Mercury") print("行星的名字是: \(plName.name)")let noplName = Planet() print("沒有這個名字的行星: \(noplName.name)")class planets: Planet {var count: Intinit(name: String, count: Int) {self.count = countsuper.init(name: name)}override convenience init(name: String) {self.init(name: name, count: 1)} }
  • 以上程序執行輸出結果為:
行星的名字是: Mercury 沒有這個名字的行星: [No Planets]

十五、可失敗構造器 init

  • 通常來說通過在 init 關鍵字后添加問號的方式(init?)來定義一個可失敗構造器,但也可以使用通過在 init 后面添加驚嘆號的方式來定義一個可失敗構造器(init!)。
  • 實例如下:
struct StudRecord {let stname: Stringinit!(stname: String) {if stname.isEmpty {return nil }self.stname = stname} }let stmark = StudRecord(stname: "Runoob") if let name = stmark {print("指定了學生名") }let blankname = StudRecord(stname: "") if blankname == nil {print("學生名為空") }
  • 以上程序執行輸出結果為:
指定了學生名 學生名為空

十六、析構過程

  • 在一個類的實例被釋放之前,析構函數被立即調用,用關鍵字 deinit 來標示析構函數,類似于初始化函數用 init 來標示,析構函數只適用于類類型。

① 析構過程原理

  • Swift 會自動釋放不再需要的實例以釋放資源。
  • Swift 通過自動引用計數(ARC)處理實例的內存管理。
  • 通常當實例被釋放時不需要手動地去清理。但是,當使用自己的資源時,可能需要進行一些額外的清理。例如,如果創建了一個自定義的類來打開一個文件,并寫入一些數據,可能需要在類實例被釋放之前關閉該文件。

② 語法

  • 在類的定義中,每個類最多只能有一個析構函數。析構函數不帶任何參數,在寫法上不帶括號:
deinit {// 執行析構過程 }

③ 實例

var counter = 0; // 引用計數器 class BaseClass {init() {counter += 1;}deinit {counter -= 1;} }var show: BaseClass? = BaseClass() print(counter) show = nil print(counter)
  • 以上程序執行輸出結果為:
1 0
  • 當 show = nil 語句執行后,計算器減去 1,show 占用的內存就會釋放:
var counter = 0; // 引用計數器class BaseClass {init() {counter += 1;}deinit {counter -= 1;} }var show: BaseClass? = BaseClass()print(counter) print(counter)
  • 以上程序執行輸出結果為:
1 1

總結

以上是生活随笔為你收集整理的Swift之深入解析构造过程和析构过程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。