文章目錄
1.print(str)
- print函數能夠將表達式的結果輸出到控制檯,類似C的printf函數和OC的NSLog函數。
- print函數定義:
public func print(_ items: Any..., //任意個數,任何類型的參數它們將輸出到控制檯
separator: String = default,//輸出多個參數之間的分隔符
terminator: String = default)//輸出字符串之後的結束符號
參數separator
、terminator
都可以省略,separator
只有字輸出數據大於1時纔有意義。
- 示例:
print("a","b","c","d","e", separator: "|", terminator: "-")
打印結果爲a|b|c|d|e-
,用|
將打印的字母分開,用-
來結束打印。
- 自定義打印日誌:
//自定義log p28
func hjLog(mes:Any){
print("file:\(#file) column:\(#column) line:\(#line) \(mes)")
}
由於Swift中不能定義宏,只能定義一個打印日誌的方法,上面方法打印文件路徑,行數,及要打印的內容,可以方便的定位到打印的位置。
2.浮點型取餘
- Swift中允許浮點型取餘,但是在Swift3之後取餘運算符
%
不能應用於浮點數運算,需要使用public func truncatingRemainder(dividingBy other: Double) -> Double
方法來計算浮點型取餘。
var c = 19.22
//浮點型取餘
let d = c.truncatingRemainder(dividingBy: 6.1)
3.Swift中的數據類型
- 根據這些類型在賦值或給函數傳遞時的方式,可分爲
值類型
和引用類型
。值類型
就是創建一個副本,把副本賦值或傳遞過去,這樣在函數的調用過程中不會影響原始數據;引用類型
就是把數據本身的引用(即指針)賦值或傳遞過去在函數的調用過程中會影響原始數據。 - Swift中整型、浮點型、布爾型、字符型、字符串、元組、集合、枚舉。結構體值類型,而類屬於引用類型。如Swift中
String
是值類型、NSString
是引用類型。 - 整型、浮點型、布爾型、字符型、字符串、元組、集合等類型本質上都是結構體類型,結構體有構造函數,通過構造函數創建並初始化實例。
- 用於判斷的幾種方式:
==
比較基本類型的值是否相等===
比較對象類型,是不是同一個對象is
判斷某個實例是否爲某種類型as
強制類型轉換
4.Swift中的for循環
- Swift3之後C語言風格的for語句不再使用, Swift3之後for語句只能與in關鍵字結合使用。
- 示例1:只需要知道連續區間的值(只需要循環變量)
//打印1到9平方的值
for i in 1..<10{
print("\(i)x\(i)=\(i*i)")
}
- 示例2:只需要連續獲取集合元素的值(不需要循環變量)
//打印集合元素
let nums = [1,2,3,4,5,6,7,8,9]
for item in nums {
print(item)
}
- 示例3:既需要集合元素的值,又需要腳標(需要循環變量),可以使用結合的
enumerated()
方法
let nums = [1,2,3,4,5,6,7,8,9]
for(index,item) in nums.enumerated(){
print("\(index):\(item)")
}
- Swift中的區間分爲兩種,全閉合區間
...
和左閉右開區間..<
。
5. break語句
- break語句可用於循環語句結構,(Swift中的循環語句有while、repeat-while、for ),作用是強制退出循環結構,不執行循環結構中的剩餘語句。由於Swift的選擇switch默認會添加break,所以一般不需要收到添加break,但添加上也不會出問題。
for i in 1...10{
print("\(i)x\(i)=\(i*i)")
if i == 5{
break;
}
}
- break可以配合標籤使用
label1: for x in 0..<5 {
label2: for y in (1...5).reversed(){
if x == y {
break label1
}
print("(x,y)=(\(x),\(y))")
}
}
默認情況下break只會跳出最近的內循環,而示例中條件成立時直接跳出循環,給外循環添加了一個標籤label1,然後break後面指定這個標籤,當條件成立就跳出該標籤的外循環。reversed()
是反向變量區間。
6.Set集合
- Swift集合有
數組、字典、Set集合
。數組
是一組有序的由相同類型元素構成的集合;字典
由兩部分組成,一個鍵集合,一個值集合,鍵集合不能有重複元素,而值集合可以重複,鍵值成對出現;Set集合
是由一串無序的,不能重複的相同類型元素構成的集合。 - 與OC任何對象類型不同,三種集合都強調是元素的類型一致,但這裏的類型指的是泛型。如果想包含任何類型可指定爲
Any
。
//正規聲明
var arr : Array<Any> = [1,2,"3",1.22]
print(arr[1])
//簡寫聲明
let dic:[AnyHashable : Any] = [1:2,2:3,"3":4,4:"5"]
//字典的key和value都爲任何類型,有可能是可選類型,獲取元素值時要解包
print(dic[1]!)
let set:Set<String> = ["1","12","123"]
print(set.first!)
- Array和Dictionary有簡寫的聲明,而Set集合沒有簡寫的聲明。因爲Set和Array唯一的區別是無序且不重複(當不考慮敘述而且沒有重複的元素時,二者可互相替換),如果簡寫了就無法區分是Set還是Array了。
- 三種集合強調的點不同, Array強調有序;Set強調不重複(無序);字典強調key唯一(不能重複),通過key取值,也是無序的。
- Set的一般操作:
let set:Set<String> = ["1","123","12","12","1234"]
print("第一個元素\(set.first!)")
print("元素個數\(set.count)")
var set2:Set<String> = ["1234","1","123","12"]
if set == set2{
print("set等於set2")
}
//插入一個元素
set2.insert("插入")
//刪除某個元素
let item = "1"
set2.remove(item)
print(set2)
//刪除一個元素,這裏並不是第一個元素,而是隨機的
set2.removeFirst()
print(set2)
//判斷是否包含某個元素
if set.contains("1234"){
print("set有該元素")
}
結果可以看出Set的first方法獲取的並不一定是第一個元素,而是隨機的。多個重複的元素在Set中只算一個,從count可以看出。
- Set集合遍歷
for item in set{
print(item)
}
for (index,item) in set.enumerated(){
print("\(index+1):\(item)")
}
注意:Set的enumerated()
方法可以取出Set的索引和元素, (index,item)是元組類型。這裏的index是循環遍量,可以表示循環次數,而不是元素的序號腳標。
- Set集合間的運算,首先了解一下幾個概念(A,B是兩個Set集合):
- 交集:屬於A且屬於B的元素集合
- 並集:屬於A或屬於B的元素集合
- 異或集合:A與B的並集元素集合去掉A與B的交集集合中的元素後剩下元素的集合
- 差集:屬於A而不屬於B的元素集合稱A與B的差集。(A與B的並集去掉B中所有元素後的集合)
- 子集:B中所有元素都A的元素,那麼久稱B是A的子集。但是Set集合運算過程中不涉及Set子集概念。
let A:Set<String> = ["a","b","c","d"]
let B:Set<String> = ["c","d","e","f"]
print("A與B的交集 = \(A.intersection(B))")
print("A與B的並集 = \(A.union(B))")
print("A與B異或集合 = \(A.symmetricDifference(B))")
let C = A.subtracting(B)
print("A與B差集 = \(C)")
if C.isSubset(of: A){
print("C是A的子集")
}
7.函數
7.1 .Swift 函數參數
- Swift中的函數參數很靈活,具體體現在傳遞參數有多種形式。
- 我們可以爲每個參數提供標籤,爲調用者說明參數的含義,這些變遷命名應該唯一,並且有意義:
func rectangleArea(W width:Double,H height:Double) ->Double{
return width*height
}
print(rectangleArea(W: 10.0, H: 10.0))
W,H就是參數標籤,外部調用時會提示使用。
- 如果定義函數沒有聲明標籤,原則上也是可以的
func rectangleArea2(width:Double,height:Double) ->Double{
return width*height
}
print(rectangleArea2(width: 10.0, height: 10.0))
- 省略參數標籤,在Swift3以後,調用函數時要求指定所有參數的標籤,除非函數定義是使用下劃線
_
關鍵字聲明的標籤。
func rectangleArea3(_ width:Double,_ height:Double) ->Double{
return width*height
}
print(rectangleArea3(10,10))
- 給參數設默認值,當調用時可以忽略該參數,調用時如果沒傳值就取默認值,如果賦值了就會覆蓋掉默認值
func test(a:Int = 10,b:Int) -> Int{
return a+b
}
print(test(b: 20)) //30
print(test(a: 1, b: 2)) //3
- 可變參數:參數個數可以變化,調用時可以接受不確定數量的參數,這些參數具有相同的類型,有點像傳入了一個數組
func sum(nums:Int...)->Int{
var total = 0
for num in nums{
total += num
}
return total
}
print(sum(nums: 1,2,3))
print(sum(nums: 1,2,3,4,5,6,8))
sum函數是用來求多個整型的函數,參數nums:Int…是Int類型的可變參數,在函數體重nums被認爲是一個Double類型的數組
- 類型參數的引用傳遞:除了類是引用類型,其他如整型…都是值類型,但有時候我們想在函數內部改變函數外面參數的值,這樣就需要將值類型參數以引用類型方式傳遞。
func increment(value: inout Double,auto:Double = 1.0){
value += auto
}
var value:Double = 10.0
print(value)
increment(value: &value)
print(value) //11.0
參數value是需要增長的數值,它被設計爲inout
類型,inout
修飾的參數稱爲輸入輸出參數,value必須是變量不能是let修飾的常量。
7.2. Swift函數返回值
- 函數返回值分爲無返回值和有返回值,無返回值其類型是void,可以省略不寫;有返回值又分爲單個返回值,和多個返回值,單個返回值就是返回一種類型,多個返回值可以返回多個類型,將這些不同類型的返回值放到元組中返回就可以了。
7.3. Swift函數類型
- 每個函數都有一個類型,使用函數類型與使用其他數據類型一樣,可以聲明變量或常量,也可以作爲其他函數參數或返回值使用。
- 用函數類型聲明常量或變量
func rectangleArea(width: Double,height:Double) -> Double {
return width * height
}
let rectangleArea1: (Double,Double)->Double = rectangleArea(width:height:)
print(rectangleArea1(10,10)) //100.0
var rectangleArea2: (Double,Double)->Double = rectangleArea(width:height:)
rectangleArea2(20,20)
rectangleArea2 = rectangleArea(width:height:)
print(rectangleArea2(30,30)) //900.0
- 用函數類型作爲函數返回類型使用
//計算矩形面積
func rectangleArea(width: Double,height:Double) -> Double {
return width * height
}
//計算三角形面積
func triangleArea(width: Double,height:Double) -> Double {
return width * height/2.0
}
//作爲函數返回類型使用
func getArea(type:String) -> (Double,Double)->Double {
var returnFunc: (Double,Double)->Double
switch type {
case "矩形":
returnFunc = rectangleArea
default://三角形
returnFunc = triangleArea
}
return returnFunc
}
let rectangleFunc = getArea(type: "矩形")
print("矩形面積:\(rectangleFunc(20,20))") //矩形面積:400.0
let triangleFunc = getArea(type: "三角形")
print("三角形面積:\(triangleFunc(20,20))") //三角形面積:200.0
getArea
返回值類型爲函數類型,常量rectangleFunc
和triangleFunc
只是接收了getArea
函數的返回值,是將計算矩形面積和三角形面積的函數真正聲明瞭,rectangleFunc(20,20)和triangleFunc(20,20)纔是對計算面積的函數的真正調用。總之就是getArea
函數調用是爲了聲明rectangleArea
和triangleArea
,返回的函數常量或變量的調用纔是真正用於計算面積的,
- 用函數類型做爲函數參數類型使用
//計算矩形面積
func rectangleArea(width: Double,height:Double) -> Double {
return width * height
}
//計算三角形面積
func triangleArea(width: Double,height:Double) -> Double {
return width * height/2.0
}
//作爲參數類型使用
func getAreabByFunc(funcName:(Double,Double)->Double,a:Double,b:Double)->Double {
let area = funcName(a,b) //對傳進來函數參數的真正調用
return area;
}
print("矩形面積:\(getAreabByFunc(funcName: rectangleArea, a: 10, b: 10))") //矩形面積:100.0
print("三角形面積:\(getAreabByFunc(funcName: triangleFunc, a: 10, b: 10))") //三角形面積:50.0
getAreabByFunc
調用值只需要將函數名傳進來就可以,傳進來的函數參數直接在裏面調用。
7.4. Swift嵌套函數
- 將函數定義在另外的函數體重,稱爲
嵌套函數
。
//嵌套函數
func calculate(opr:String) -> (Int,Int) -> Int {
//定義加函數
func add(a:Int,b:Int) -> Int{
return a + b
}
//定義減函數
func sub(a:Int,b:Int) -> Int{
return a - b
}
var result: (Int,Int) -> Int
switch opr {
case "+":
result = add
case "-":
result = sub
default:
result = add
}
return result
}
let addfunc = calculate(opr: "+") // 聲明加函數
print("5+5 = \(addfunc(5,5))") //5+5 = 10
let subfunc = calculate(opr: "-")// 聲明減函數
print("5-5 = \(subfunc(5,5))")//5-5 = 0
嵌套函數的作用域在外函數體內,但我們可以定義外函數的返回值類型爲嵌套函數類型,從而將嵌套函數出啊遞給外函數,被其調用者調用。
8.運算符重載
- Swift中除了class類型是引用類型,其他整型,浮點型,數組,結構體等都是值類型,對於引用類型通常用
===
和!===
來判斷是不是同一個對象;對於值類型通常用==
和!=
來判斷兩個值是否相等。 - 示例:自定義一個機構體,判斷兩個實例是否相等。
struct Student {
var name = ""
var no = 0
var age = 0
}
var stu1 = Student()
stu1.name = "張三"
stu1.no = 1
stu1.age = 18
var stu2 = Student()
stu2.name = "張三"
stu2.no = 1
stu2.age = 18
if stu1 == stu2{
print("是同一個學生")
}else{
print("不是同一個學生")
}
可以發現在運行時報錯了,報錯說明爲==
不能用於兩個Student
結構體實例操作。說了stu1和stu2不能用於比較。我們需要在這些類型中重載
==和
!=運算符號。即定義相等規則。
struct Student {
var name = ""
var no = 0
var age = 0
}
//定義重載==號運算符符
func == (lsh:Student,rhs:Student) -> Bool {
return lsh.name == rhs.name && lsh.no == rhs.no && lsh.age == rhs.age
}
//定義重載!=號運算符符
func != (lsh:Student,rhs:Student) -> Bool {
return (lsh.name != rhs.name || lsh.no != rhs.no || lsh.age != rhs.age)
}
var stu1 = Student()
stu1.name = "張三"
stu1.no = 1
stu1.age = 18
var stu2 = Student()
stu2.name = "張三"
stu2.no = 1
stu2.age = 18
if stu1 == stu2{
print("是同一個學生")
}else{
print("不是同一個學生")
}
9.類型嵌套
- Swift中的類、結構體和枚舉可以進行嵌套。優點是支持訪問它外部的成員(包括方法、屬性和其他嵌套類型),嵌套可以有多個層次。
class Employee {
var name = ""
var no = 0
var job = ""
var day = WeekDays.Friday
var dept = Department()
struct Department {
var no = 10
var name = "Sales"
}
enum WeekDays{
case Monday,Tuesday,Wednesday,Thursday,Friday
struct Day {
static var mes = "Today is ..."
}
}
}
let emplo = Employee()
print(emplo.day)
print(emplo.dept.name)
print(Employee.WeekDays.Day.mes)
10.類和結構體的異同。
- 相同點:
- 定義存儲屬性;
- 定義方法;
- 定義下標;
- 定義構造函數;
- 定義擴展;
- 實現協議
- 不同點:(只有類纔有的功能)
- 能夠繼承另外一個類;
- 能夠覈對運行時對象的類型;
- 析構對象釋放資源;
- 引用計數允許一個實例有多個引用。
- 選擇的原則:結構體是值類型,每一個實例沒有獨一無二的標識,而類是引用類型,每一個實例都是獨一無二的標識。
class Employee{ //員工類
var no = ""
var name = ""
var dept: Department?
}
struct Department{//部門結構體
var no = ""
var name = ""
}
上面示例可以看出,由於員工的編號都是獨一無二,每個員工是獨立的個體,所以員工可以聲明成類Employee;如果具有相同部門標號和部門名稱,我們就認爲是它們是相同的部門,所以就可以把部門設計爲機構體Department。
11.屬性與下標。
- Swift中的屬性分爲
存儲屬性
和計算屬性
。存儲屬性就是oc中的數據成員,計算屬性不存儲數據,但可以通過計算其他屬性返回數據。
class Employee{
let no = 0
var firstName = "Tony"
var lastName = "Guan"
lazy var dept: Department = Department() //延遲存儲屬性
var fullName: String{ //計算屬性
get{
return firstName + "." + lastName
}
set(newFullName){
let names = newFullName.components(separatedBy: ".")
firstName = names.first!
lastName = names.last!
}
// set{
// let names = newValue.components(separatedBy: ".")
// firstName = names.first!
// lastName = names.last!
// }
}
}
struct Department{
var no = ""
var name = ""
}
let emp = Employee()
//emp.no = 10;編譯會報錯 ,常量屬性不允許被修改。
print(emp.fullName)
emp.fullName = "Jack.Ma"
print(emp.fullName)
let dept = Department()
上面類Employee中的no、firstName、lastName、dept都是存儲屬性,fullName是計算屬性,其中dept是延遲存儲屬性。
- 延遲存儲屬性:存儲屬性前面加上lazy關鍵字聲明,就是延遲存儲屬性,只在第一次訪問時加載,如果不訪問就不會創建,這樣可以減少內存佔用,注意存儲屬性沒有延遲加載一說,添加到存儲屬性前面會報錯的。
- 計算屬性:計算屬性本身不存儲數據,而是從其他屬性計算得到數據。計算屬性提供一個Getter(取值訪問器)來獲取值,以及一個
可選的(可以不實現set方法)
Settter(設置訪問器)來間接設置其他屬性或變量的值,語法如下。
面向對象的類型(class、struct、enum) 類型名{
存儲屬性
var 計算屬性名: 屬性數據類型{
get{
return 計算後的語句值
}
set(新屬性值){
語句組
}
}
}
其中新屬性值
是要賦值給屬性值的,當然也可以不寫,Swift提供了一個默認的變量newValue
去接收新傳入的值。上面set(newFullName)
可以省略如下:
set{
let names = newValue.components(separatedBy: ".")
firstName = names.first!
lastName = names.last!
}
- 只讀計算屬性:計算屬性只有Getter訪問器,沒有Setter訪問器,只能取值而不能賦值。(只讀存儲屬性就是let修飾的存儲屬性)
class Employee{
let no = 0
var firstName = "Tony"
var lastName = "Guan"
lazy var dept: Department = Department()
var fullName: String{
get{
return firstName + "." + lastName
}
}
}
let emp = Employee()
//emp.no = 10;
print(emp.fullName)
// emp.fullName = "Jack.Ma" //不能賦值
fullName就是隻讀計算屬性,不能給其賦值,結構體,枚舉的計算屬性也是類似,這裏不再贅述。只讀屬性可以簡化去掉get關鍵字和括號,上面只讀屬性可以簡化爲:
var fullName: String {
return firstName + "." + lastName
}
- 存儲屬性觀察者:Swift的屬性觀察者有兩個,willSet:觀察者在修改之前調用,didSet觀察者在修改之後調用 語法格式如下。
面向對象類型(class/struct) 類型名{
...
var 存儲屬性值: 屬性數據類型 = 初始值{
willSet(新值){
...
}
didSet(舊值){
...
}
}
}
示例
class Employee1{
let no = 0
var name = "Tony"{
willSet(newName){
print("員工新名字:\(newName)")
}
didSet(oldName){
print("員工舊名字:\(oldName)")
}
}
}
struct Department1{
var no = 1{
willSet{
print("部門新編號:\(newValue)")
}
didSet{
print("部門舊編號:\(oldValue)")
}
}
var name = "移動開發部"
}
let emp1 = Employee1()
emp1.name = "Jack"
//結構體是值類型,必須用聲明爲變量才能修改其屬性
var dept1 = Department1()
dept1.no = 10
Employee1類中給name存儲屬性添加了觀察者, willSet(newName)中的newName是要傳進來的新值,didSet(oldName)中的oldName是新值傳進來之前的舊值;參數的聲明可以省略。Department1結構體中的no就省略了觀察者參數,Swift提供了對應默認參數,新值默認是newValue
,舊值默認是oldValue
。這裏需要說明下枚舉只有計算屬性沒有存儲屬性,所以枚舉不支持屬性觀察者
。
- 靜態屬性:在屬性前面加static關鍵字,類中也可以加class關鍵字,這樣的屬性稱爲靜態屬性。類,結構體,枚舉都可以定義靜態屬性(也包括靜態存儲屬性和靜態計算屬性)。這裏需要注意的是
枚舉中沒有實例存儲屬性但是可以有靜態存儲屬性
。
struct Account {
var amount = 0.0 //賬戶金額
var ower = "" //賬戶名
static let monthRate = 0.00688 //月利率
static var yearRate : Double{ //計算存儲屬性不能用let修飾,及不能是常量
return monthRate * 12
}
var owerInterest:Double{ //年利息
return Account.yearRate * amount
}
}
//訪問靜態屬性
print(Account.yearRate)
var account = Account()
//訪問實例屬性
account.amount = 100000.0
print(account.owerInterest)
class Account {
var amount = 0.0 //賬戶金額
var ower = "" //賬戶名
static let monthRate = 0.00688 //月利率
class var yearRate : Double{ //class換成static子類就不能重寫該屬性
return monthRate * 12
}
var owerInterest:Double{ //年利息
return Account.yearRate * amount
}
static var test:Int = 10{ //靜態屬性也支持添加屬性監聽者
willSet{
print(newValue)
}
didSet{
print(oldValue)
}
}
}
//訪問靜態屬性
print(Account.yearRate)
var account = Account()
//訪問實例屬性
account.amount = 100000.0
print(account.owerInterest)
class Account2:Account{
override class var yearRate : Double{ //class換成static子類就不能重寫該屬性
return monthRate * 12 * 1.1
}
}
這裏枚舉與結構體類似不再舉例,類中static修飾的屬性爲類的靜態屬性,class修飾的屬性稱爲類的類屬性,區別是類的類屬性可以被子類重寫,但是class不能修飾存儲屬性,static卻可以
。
- 實例屬性和靜態屬性總結
1. 類、結構體,枚舉都支持靜態存儲屬性、靜態計算屬性,實例計算屬性;但是隻有類和結構體支持實例存儲屬性,枚舉不支持實例存儲屬性。
2. 基於第一條可知只有類和結構體支持添加屬性觀察者(因爲只有存儲屬性才能添加屬性觀察者)
3. 延遲屬性只能是延遲存儲屬性
4. 計算屬性必須是var聲明的
5. let修飾的存儲屬性,前可以加static稱爲靜態存儲屬性,不能加class
6. class修飾的屬性可以被重寫,但static修飾的屬性不允許被重寫。
7. class只能修飾計算屬性。
- 下標:Swift中,我們可以定義一些集合類型,,它們可以回有一些集合類型的存儲屬性,這些屬性可通過下標訪問,其如法格式如下。
面向對象類型(class/struct/enum) 類型名{
...
subscript (參數:參數數據類型)->返回值類型{
get{
return 返回值
}
set(新屬性值){
...
}
}
}
Swift中沒有提供二維數組,但是我們可以通過下標自定義一個二維數組。
struct DoubleDimensionalArray {
let rows:Int,colums:Int
var grid: [Int]
init(rows:Int,colums:Int) {
self.rows = rows //行數
self.colums = colums //列數
grid = Array(repeating: 0, count: rows * colums) //初始化數組都爲0
}
subscript(row:Int,col:Int) -> Int{
get{
return grid[row * colums + col] //返回對應的腳標取出二維數組的值
}
set{
grid[row * colums + col] = newValue //通過腳標給二維數組賦值
}
}
}
//初始化一個10行10列的二維數組
var arr = DoubleDimensionalArray(rows: 10, colums: 10)
for i in 0..<10 {
for j in 0..<10{
arr[i,j] = i*j //通過腳標給二維數組賦值爲腳標之和
}
}
for i in 0..<10 {
for j in 0..<10{
print("\t \(arr[i,j])",terminator: " ") //通過腳標獲取二維數組中的值
}
print("\n")
}
11.方法。
- Swift中,方法是在類,結構體,枚舉中定義的函數,分爲實例方法和靜態方法.
- 方法和函數的區別:方法是在在類,結構體,枚舉內部定義的.方法調用前面要有主體,而函數就不需要.
- 我們在枚舉和結構體方法掐面添加關鍵字mutatting,將方法聲明爲可以變方法,可變方法能夠修改
值類型變量屬性
,但不能修改值類型常量屬性
.也就說不可變方法值類型屬性是都不能訪問的,但引用類型的屬性是可以訪問的。- static修飾的方法爲靜態方法,當然類中class修飾的方法類方法.與計算屬性類似,實例方法中既可以訪問實例屬性和方法又可以訪問靜態屬性和方法,但是靜態方法不能訪問實例屬性和實例方法,只能訪問靜態屬性和方法.
- class修飾的方法能被重寫,static修飾的方法不能被重寫.
12.重寫
- 一個類繼承另一個類的屬性,方法,下標等特徵後,子類可以重寫(
override
)這些特徵。 - 重寫實例屬性:實例屬性重寫一方面可以Getter和Setter訪問器,另一方面可以重寫屬性觀察者。
class Person {
var name: String
var age: Int
init(name:String,age:Int) {
self.name = name
self.age = age
}
}
class Student: Person {
var school: String
override var age:Int {
get{
return super.age
}
set{
super.age = newValue<8?8:newValue
}
}
}
從屬性重寫來看,子類本身並不存儲數據,數據存儲在父類的存儲屬性中,子類將其變成了計算屬性並重寫。
注意:一個屬性重寫了Getter和Setter訪問器後就不能重寫觀察者。另外常量屬性和只讀計算屬性也都不能重寫屬性觀察者。
- 重寫靜態屬性:
class Account{
class var staticProp:Double{
return 0.0668 * 1000000
}
}
class TermAccount: Account {
override static var staticProp:Double{
return 0.0700*1000000
}
}
Account的靜態屬性staticProp只能用class修飾,因爲要在子類TermAccount重寫該靜態屬性,所以該屬性能被繼承才行,而TermAccount可以用class也可以用static修飾,因爲沒有子類繼承TermAccount的staticProp屬性。
- 重寫實例靜態方法:
class Person {
var name: String
var age: Int
init(name:String,age:Int) {
self.name = name
self.age = age
}
func description() -> String {
return "\(name)的年齡爲:\(age)"
}
}
class Student: Person {
var school: String
override var age:Int {
get{
return super.age
}
set{
super.age = newValue
}
}
override init(name:String,age:Int) {
self.school = "清華大學"
super.init(name: name, age: age)
}
override func description() -> String {
return "\(name)的年齡爲:\(age),所在學校爲\(school)"
}
}
靜態方法重寫與實例方法重寫類似,在方法名錢加上override關鍵字即可,但是隻有class修飾的靜態方法才能被被繼承被重寫,static修飾的靜態方法不能被重寫。
- 下標重寫:對下標重寫也是重寫Getter和Setter訪問器,類似於屬性,這裏不再舉例。
- final關鍵字:final關鍵字可以聲明類、屬性、方法、和下標。final關鍵字可以聲明類不能被繼承,聲明的屬性、方法和下標不能被重寫。
13.類檢查與轉換(is、as、as!、as?、AnyObject、Any)
- 使用is進行類型檢查:
is
操作符可以判斷一個實例是否是某個類的類型。(只要是該類型以及該類型的父類以及父類的父類類型,返回都爲true,類似於oc的isKindOfClass
方法)
//Student繼承於Person
let stu = Student(name: "馬雲", age: 18)
if stu is Student{
print("馬雲18歲是一個學生")
}
if stu is Person{
print("馬雲18歲是一個人")
}
- 使用as、as!、as?進行類型轉換:
- as操作符:用於向上轉型(子類轉換成父類),因爲向上轉型很少進行,所以代碼中很少能夠看到使用as操作符(通常都是向下轉型:父類轉出子類)。
- as!操作符: 在類型轉換過程中對可選值進行拆包,轉換結果是費可選類型。將費可選類型轉換爲非可選類型,將可選類型轉換爲非可選類型。
- as?操作符: 在類型轉換過程中不進行裁包,轉換結果是可選類型。將非可選類型轉換爲可選類型,將可選類型轉換爲可選類型。
//Student,Worker類都繼承於People
let stu1 = Student(name: "李彥宏", age: 35, school: "北京大學")
let stu2 = Student(name: "馬化騰", age: 45, school: "深圳大學")
let stu3 = Student(name: "馬雲", age: 55, school: "杭州師範大學")
let wk1 = Worker(name: "李開復", age: 56, factory: "微軟")
let wk2 = Worker(name: "張小龍", age: 46, factory: "騰訊")
let people = [stu1,stu2,stu3,wk1,wk2]
for p in people{
if let stu = p as? Student{ //這裏在是先轉換爲可選類型,並且在轉換成功後進行了可選綁定(因爲都有值就解包了)
print("Student \(stu.name),年齡:\(stu.age),畢業於:\(stu.school)")
}else if let wk = p as? Worker{
print("Worker \(wk.name),年齡:\(wk.age),工作於:\(wk.factory)")
}
}
let stu4 = people[0]as? Student //這裏是直接賦值爲可選類型
print("--------")
print(stu4 as Any)
print(stu4?.name as Any) //可選類型安全訪問其屬性的寫法
print(stu4!.name)
- 使用
AnyObject
和Any
類型:Swift提供了兩種類型來表示不確定類型(任意類型),AnyObject
表示任何類(class)的類型
;Any
則表示任何類型
,包括Int、Double、Array、struct等基本數據類型,也包括AnyObject
類型。也就是說AnyObject
是Any
的子集。 - 在OC與Swift混合編程時,OC的id類型和Swift的AnyObject類型可以互換,但是兩者有本質區別。id類型是泛性,可以代表任何指針類型,編譯時編譯器不檢查id類型,是動態的。AnyObject是實實在在表示類的類型,編譯時會檢查AnyObject類型。
- 原則上若能使用集體的數據類型,則儘量不要使用AnyObject類型,更要少考慮使用Any類型。從集合中取出這些實例時也要儘可能的將AnyObject類型和Any類型轉換爲特定類型,然後再進行接下來的操作。
14.擴展(extension)
- Swift中可以使用一種擴展機制,在原始類型(類、機構體、枚舉)的基礎上添加新功能。擴展是一種輕量級的繼承機制。
- Swift中擴展機制可以在原始類型中添加新功能包括:
- 實例計算屬性和靜態計算屬性
- 實例方法和靜態方法
- 構造函數(結構體中可以擴展構造函數;類中只能擴展便利構造函數,不能擴展指定構造函數和析構函數,指定構造函數和析構函數只能在原始類中提供)
- 下標