###一、Swift的類class 作為一門物件導向語言,類也是Swift的非常重要的型別,我們先來看下一個簡單的類
//Swift中一個類可以不繼承於任何其他基類,那麼此類本身就是一個基類
class Person {
//定義屬性
var name:String
var height = 0.0
//構造器方法,注意如果不編寫構造方法預設會自動建立一個無參構造方法
init(name:String){
self.name = name
}
//析構器方法,在物件被釋放時呼叫,類似於ObjC的dealloc,注意這裡沒有括號和引數,無法直接呼叫
deinit{
print("deinit...")
}
//定義物件方法
func showMessage(){
print("name=\(name),height=\(height)")
}
}
//建立類的物件
var p = Person(name: "Liuting")
p.height = 170.0
p.showMessage() //結果:name=Liuting,height=170.0
//類是引用型別
var p2 = p
p2.name = "XiaoMing"
print(p.name) //結果:XiaoMing
//“===”表示等價於,這裡不能使用等於“==”,等於用於比較值相等,p和p2是不同的值,但是指向的物件相同
if p === p2 {
print("p===p2") //p等價於p2,表示二者指向同一個物件
}
複製程式碼
###二、屬性 Swift中淡化了成員屬性的概念,把屬性分為兩種:
- 儲存屬性: 無論從概念上還是定義方式上來看,儲存屬性更像其他語言中的成員變數,但是不同的是:
- 可以控制讀寫操作(
var
表示可讀可寫,let
表示只讀) - 通過屬性監視器來屬性的變化(
willSet
、didSet
) - 快速實現懶載入功能(
lazy
修飾)
- 計算屬性:
計算屬性並不直接儲存一個值,而是提供
getter
來獲取一個值,或者利用setter
來間接設定其他屬性。
######下面是物件屬性使用例項:
class Account {
//定義儲存屬性,設定預設值,新增屬性監聽器
var balance:Double = 0.0{
//即將賦值時呼叫
willSet{
//注意此時修改balance的值將作為最終結果
self.balance = 2.0
//newValue表示即將賦值的新值,並且在屬性監視器內部呼叫屬性不會引起監視器迴圈呼叫
print("Account.balance willSet,newValue=\(newValue),value=\(self.balance)")
}
//賦值完成後呼叫
didSet{
//注意此時修改balance的值將作為最終結果
self.balance = 3.0
//oldValue表示已經賦值的舊值,並且在屬性監視器內部呼叫屬性不會引起監視器迴圈呼叫
print("Account.balance didSet,oldValue=\(oldValue),value=\(self.balance)")
}
}
}
class Person {
//firstName、lastName、age是儲存屬性
var firstName:String //var定義表示該儲存屬性可讀可寫
var lastName:String
let age:Int //let定義表示該儲存屬性只讀
//屬性的懶載入,第一次訪問才會初始化
lazy var account = Account()//在Swift中懶載入的屬性不一定就是物件型別,也可以是基本型別
//fullName是一個計算屬性,在get、set方法中不能直接訪問計算屬性,否則會引起迴圈呼叫
var fullName:String{
//獲取該計算屬性時呼叫
get{
return firstName + "." + lastName
}
//設定該計算屬性時呼叫
set{
//set方法中的newValue表示即將賦值的新值,這裡是分割字串(Swift1的方法,Swift2以後改了)
let array = split(newValue, maxSplit: Int.max,
allowEmptySlices: false,
isSeparator: {$0=="."})
if array.count == 2 {
firstName = array[0]
lastName = array[1]
}
}
}
//構造器方法,注意如果不編寫構造方法預設會自動建立一個無參構造方法
init(firstName:String, lastName:String, age:Int){
self.firstName = firstName
self.lastName = lastName
self.age = age
}
//定義方法
func showMessage(){
print("name=\(self.fullName),age=\(self.age)")
}
}
//建立物件
var p = Person(firstName: "Liu", lastName: "Ting", age:22)
p.showMessage() //結果:name=Liu.Ting,age=22
p.fullName = "Liu.HAHA" //設定計算屬性
p.showMessage() //結果:name=Liu.HAHA,age=22
p.account.balance = 10
/* 下面是儲存屬性監聽器方法列印:
Account.balance willSet,newValue=10,value=2.0
Account.balance didSet,oldValue=0,value=3.0
*/
print("p.account.balance=\(p.account.balance)") //結果:p.account.balance=3.0
複製程式碼
- 計算屬性並不直接儲存一個值,而是提供
getter
來獲取一個值,或者利用setter
來間接設定其他屬性;
lazy
屬性必須有初始值,必須是變數不能是常量,因為常量在構造完成之前就已經確定了值;- 在構造物件方法之前儲存屬性必須有值(可選型別除外),無論是變數屬性還是常量屬性,這個值既可以在屬性建立時指定,也可以在構造方法內指定;
- 儲存屬性的預設值設定不會引起屬性監視器的呼叫(另外在構造方法中賦值也不會引起屬性監視器呼叫),只有在外部設定儲存屬性才會引起屬性監視器呼叫;
######除了上面的物件屬性外,我們還可以定義類的屬性:
class Student {
//定義類的屬性只需要在前面加static關鍵字即可,也是分為儲存屬性和計算屬性,這裡是計算屬性
static var skin:Array<String>{
//只定義了getter,表示該計算屬性是隻讀的
get{
return ["yellow", "white", "black"]
}
}
}
//讀取類的屬性
for color in Student.skin {
print(color)
}
複製程式碼
###三、方法 ######Swift的類中的方法可分為以下幾個類別:
- 構造器方法
- 預設構造器方法(當存在有引數的指定構造器方法,被覆蓋)
- 指定構造器方法
- 便利構造器方法
- 析構器方法
- 物件方法
- 類方法
######以下是方法使用例項:
class Person {
//定義屬性
var name:String
var height:Double
var age = 0
//1.2.指定構造器方法,注意如果不編寫構造方法,預設會自動建立一個無參構造方法
init(name:String, height:Double, age:Int){
self.name = name
self.height = height
self.age = age
}
//1.3.便利構造方法,通過呼叫指定構造方法、提供預設值來簡化構造方法實現
convenience init(name:String){
self.init(name:name, height:0.0, age:0)
}
//2.析構方法,在物件被釋放時呼叫,注意此方法沒有括號,沒有引數,無法直接呼叫
deinit{
print("deinit...")
}
//3.物件方法
func modifyInfoWithAge(age:Int, height:Double){
self.age = age
self.height = height
}
//4.類方法,使用class修飾的方法即是類方法
class func showClassName(){
print("Class name is Person")
}
}
//通過便利構造方法建立物件
var p = Person(name: "liuting")
//呼叫物件方法
p.modifyInfoWithAge(22,height: 170)
//呼叫類方法
Person.showClassName()
複製程式碼
- 除構造方法、析構方法外,其他方法的引數預設除了第一個引數是區域性引數,從第二個引數開始既是區域性引數又是外部引數。但是,對於函式,預設情況下只有預設引數既是區域性引數又是外部引數,其他引數都是區域性引數。
- 構造方法的所有引數預設情況下既是外部引數又是區域性引數
- 只有便利構造器方法才能呼叫當前類的指定構造方法
- 有引數的指定構造器方法會覆蓋呼叫預設的無參構造器方法
- 一個物件被釋放前,先自動呼叫自己的析構方法,然後一層一層往上呼叫父類的析構方法
###四、下標指令碼
下標指令碼是一種訪問集合的快捷方式,如果我們自定義的類具有集合型別的功能,我們可以定義下標指令碼來快捷訪問該類屬性,定義下標指令碼是通過關鍵字subscript
進行的。
class Record {
//定義屬性,store是Record內部的儲存結構,這裡是字典
var store:[String:String]
//指定構造方法
init(data:[String:String]){
self.store = data
}
//下標指令碼,下標索引為整形(注意也可以實現只有getter的只讀下標指令碼)
subscript(index:Int) -> String{
get{
//字典的key進行排序後根據Index整形索引獲取字典的值
var key = sorted(Array(self.store.keys))[index]
return self.store[key]!
}
set{
//字典的key進行排序後根據Index整形索引設定字典的值
var key = sorted(Array(self.store.keys))[index]
self.store[key] = newValue //newValue和屬性一樣使用
}
}
//下標指令碼,下標索引為字串
subscript(key:String) -> String{
get{
return store[key]!
}
set{
store[key] = newValue
}
}
}
//建立物件
var record = Record(data:["name":"liuting","sex":"male"])
print("r[0]=\(record[0])") //結果:r[0]=liuting
record["sex"] = "female"
print(record["sex"]) //結果:female
複製程式碼
###五、繼承 和ObjC一樣,Swift也是單繼承的(可以實現多個協議,此時協議放在後面),子類可以呼叫父類的屬性、方法,重寫父類的方法,新增屬性監視器,甚至可以將只讀屬性重寫成讀寫屬性。
//定義一個父類
class Person {
var firstName:String
var lastName:String
var age:Int = 0
var fullName:String{
get{
return firstName + " " + lastName
}
}
//指定構造方法
init(firstName:String,lastName:String){
self.firstName = firstName
self.lastName = lastName
}
//物件方法
func showMessage(){
print("name=\(self.fullName),age=\(self.age)")
}
//通過final宣告,子類無法重寫
final func sayHello(){
print("hello world.")
}
}
//定義子類
class Student: Person {
//重寫屬性,為屬性新增監視器,重寫都需要加override關鍵字
override var firstName:String{
willSet{
print("firstName willSet")
}
didSet{
print("firstName didSet")
}
}
//新增子類屬性
var score:Double
//子類指定構造方法一定要呼叫父類構造方法
//並且必須在子類儲存屬性初始化之後呼叫父類構造方法
init(firstName:String, lastName:String, score:Double){
self.score = score
super.init(firstName: firstName, lastName: lastName)
}
//便利構造方法
convenience init(){
self.init(firstName:"", lastName:"", score:0)
}
//將只讀屬性重寫成了可寫屬性
override var fullName:String{
get{
return super.fullName;
}
set{
let array = split(newValue, maxSplit: Int.max,
allowEmptySlices: false,
isSeparator: { $0 == "." })
if array.count == 2 {
firstName = array[0]
lastName = array[1]
}
}
}
//重寫物件方法
override func showMessage() {
print("name=\(self.fullName),age=\(self.age),score=\(self.score)")
}
}
//建立子類物件
var p = Student()
p.firstName = "liu"
p.showMessage() //結果:name=liu,age=0,score=0
p.fullName = "Liu.Ting"
p.showMessage() //結果:name=Liu.Ting,age=0,score=0
p.sayHello()
複製程式碼
- 只有指定構造方法才能呼叫父類的構造方法。
- 如果父類中存在有引數的指定構造方法,子類的指定構造方法不會自動呼叫父類無參的指定構造方法。
- 如果父類僅有一個無參構造方法(不管是否包含便利構造方法),子類的構造方法預設就會自動呼叫父類的無參構造方法(這種情況下可以不用手動呼叫)。
- 常量屬性只能在定義它的類的構造方法中初始化,不能在子類中初始化
- 一個物件被釋放前,先自動呼叫自己的析構方法,然後一層一層往上呼叫父類的析構方法。
- 便利構造方法必須呼叫同一個類中的其他指定構造方法(可以是指定構造方法或者便利構造方法),不能直接呼叫父類構造方法。
#####有什麼問題可在下方評論區中提出!O(∩_∩)O哈!