Swift 2.2 語法 (中)

前言:
1.此文中的語法會根據Swift的升級變動而更新。
2.如果需要請移步 -> swift2.2 語法(上)swift 2.2語法(下)

函數

  • 和C語言一樣,swift也有函數,性質和我們熟悉的Objective-C的方法相當

  • 格式:


    func 函數名(參數列表) -> 返回值類型 {
        代碼塊
        //  如果設置了返回值類型,就需要返回相應的返回值
        return 返回值
    }
    
    
    • func是swift內的關鍵字,參數列表內多個參數之間用 "," 隔開,可以沒有參數
    • "->" 指向返回值類型
    • 當然,如果函數沒有返回值(返回值為Void),那么 "-> 返回值類型" 這部分可以省略不寫(默認就是沒有返回值)
  • 函數幾種定義方式:

    //  定義沒有參數,沒有返回值的函數
    
    //  標準寫法
    func test1() -> Void {
        print("沒有參數沒有返回值的函數")
    }
    //  簡寫方式一
    func test2() -> () {
        print("沒有參數沒有返回值的函數")
    }
    //  簡寫方式二
    func test3() {
        print("沒有參數沒有返回值的函數")
    }
    
    //  定義有參數,沒有返回值的函數
    
    //  標準寫法
    func test1(num : Int) -> Void {
        print("有參數沒有返回值的函數")
    }
    //  簡寫方式一
    func test2(num : Int) -> () {
        print("有參數沒有返回值的函數")
    }
    //  簡寫方式二
    func test3(num : Int) {
        print("有參數沒有返回值的函數")
    }
    
    //  定義沒有參數,有返回值的函數
    
    //  標準寫法
    func test1() -> Int {
        return 0
    }
    
    //  定義有返回值,有參數的函數
    
    //  標準寫法
    func test1(num1 : Int, num2 : Int) -> Int {
        return num1 + num2
    }
    
    //  定義一個有參數,且有多個返回值的函數
    
    //  標準寫法
    func test1(nums : [String]) -> (strCount : Int, spellString : String) {
    
        var strCount = 0
        var spellString = ""
    
        for num in nums {
            strCount++
        
            spellString = spellString + num
        }
    
        return (strCount, spellString)
    }
    //  調用函數
    print(test1(["abc", "def", "ghi"]))
    
    
  • 函數的外部參數和內部參數

    • 內部參數:在函數內部可以看到的參數
    • 外部參數:在函數外面可以看到的參數
    • 從第二個參數開始,參數名稱即是內部參數也是外部參數(默認)


    //  先來定義一個擁有多個參數的函數
    func test1(num1 : Int, num2 : Int, num3 : Int) -> Void {
        print(num1, num2, num3)
    }
    
    //  在調用函數的時候可以看下區別
    /*
    *  第一個函數沒有跟上我們定義參數時所給的標簽
    *  后面的所有函數都有我們定義參數時所給的標簽
    *  原因:從第二個參數開始,參數名稱即是內部參數也是外部參數(默認)
    *  也就是說第一個參數默認為內部參數,所以不會顯示標簽
    */
    test1(5, num2: 6, num3: 7)
    
    
    • 如果第一個參數也想有外部參數,可以設置標簽:在變量名前增加標簽


    //  先來定義一個擁有多個參數的函數,但是這次我們要讓第一個參數也有外部參數
    
    func test1(num1 num1: Int, num2 : Int, num3 : Int) -> Void {
        print(num1, num2, num3)
    }
    
    //  現在再調用函數可以看到第一個參數也變擁有外部參數
    test1(num1: 5, num2: 6, num3: 7)
    
    
    • 在參數名稱前加 "_" ,表示不需要外部參數


    //  先來定義一個擁有多個參數的函數,這次我們讓所有參數都為內部參數
    
    func test1 (num1 : Int, _ num2 : Int, _ num3 : Int) -> Void {
        print(num1, num2, num3)
    }
    
    //  現在調用函數就會發現所有的參數都成為內部參數了
    test1(5, 6, 7)
    
    
  • 函數重載

    • 函數名稱相同,但參數不同,可以稱為函數重載
    • 參數擁有內部參數或外部參數不同,也被認定為參數不同


    //  函數重載例:定義三個函數,函數名相同但函數的參數不同
    
    //  無返回值,第一個參數為內部參數,第二個參數同時擁有外部和內部參數
    func test(num1 : Int, num2 : Int) -> Void {
        print("第一個函數")
    }
    
    //  無返回值,且都同時沒有外部參數
    func test(num1 : Int, _ num2 : Int) -> Void {
        print("第二個函數")
    }
    
    //  無返回值,但同時擁有外部和內部參數
    func test(num1 num1 : Int, num2 : Int) -> Void {
        print("第三個函數")
    }
    
    //  調用函數
    test(1, num2: 2)
    test(1, 2)
    test(num1: 1, num2: 2)
    
    
  • 默認參數

    • 在一些特定情況下,調用函數時如果沒有傳入具體參數,可以使用默認參數代替(相當于我們在定義參數時就給參數一個默認值)
    //  默認參數
    
    func test(num : Int = 5) -> Int {
    
        return num
    }
    
    //  調用參數不給值,返回的的就是默認值 “5”
    test()
    
    
  • 可變參數

    • swift函數的參數個數可以變化,可以接收不確定數量的輸入類型參數
    • 需要注意的是,這些參數必須具有相同的類型
    • 方法:在參數類型后面加 "..." 表示參數為可變參數


    //  定義函數,參數為可變參數
    func test(nums : Int...) -> Int {
    
        var sum : Int = 0
        //  遍歷內部元素
        for temp in nums {
            sum += temp
        }
    
        return sum
    }
    
    //  調用函數,結果為202
    test(20, 15, 35, 32, 100)
    
    
  • 指針傳遞(引用類型)

    • 函數的參數是通過值傳遞的方式,如果想改變外面的變量,需要傳遞變量地址(默認)
    • swift提供了 "inout" 關鍵字來幫助我們實現
    • 需要注意的都是,操作的必須是變量,因為需要在內部改變值


    //  比如C語言中常見的問題:交換2個變量的值
    
    //  先來看看正常的值傳遞
    //  定義需要交換值的2個變量a,b
    var a = 6
    var b = 9
    
    //  值傳遞方式
    func test(var num1: Int, var num2: Int) -> (num1 : Int, num2 : Int) {
    
        let temp = num1
        num1 = num2
        num2 = temp
    
        return (num1,num2)
    }
    
    //  調用函數(交換的只是函數內部參數的值,而a,b的值并沒變)
    test(a, num2: b)    //  結果 9  6
    print(a, b) //  結果  6   9
    
    //  通過上面的方式可以明顯看出值傳遞并不能真實轉換外部變量的值,在swift中我們可以通  過"inout"關鍵字來講外部變量的值傳給函數參數,再改變其值
    func test(inout num1 : Int, inout num2 : Int) -> (num1 : Int, num2 : Int) {
    
        let temp = num1
        num1 = num2
        num2 = temp
    
        return (num1, num2)
    
    }
    
    //  調用函數(因為傳入的是a,b的變量地址,等于拿到了外部變量,函數內部操作的num1,num2可以看成a,b,因為他們的指針指向了a,b)
    test(&a, num2: &b)
    print(a,b)
    
    
  • 函數嵌套使用

    • swift中函數可以嵌套使用
    • 雖然可以嵌套使用,但是這種做法降低了可讀性,所以盡量不要這樣做

    //  函數嵌套
    
    let a = 100
    let b = 35
    
    func test() {
        func sum(num1 : Int, num2 : Int) {
            print("和為\(num1 + num2)")
        }
    
        print("test函數")
        sum(a, num2: b)
    }
    
    //  調用函數
    test()  //  先調用test函數,再調用sum函數
    
    

    注意:無法調用sum函數,因為它是test函數的一部分

  • 函數類型

    • 每個函數都有屬于自己的類型,由函數的參數類型和返回值類型組成


    //  函數類型:定義2個函數,且都為 (String, String) -> (String) 類型
    
    func test1(name : String, city : String) -> String {
        return name + city
    }
    
    func test2(tiele : String, iconUrl : String) -> String {
        return "圖片名稱:\(tiele)圖片地址為:\(iconUrl)"
    }
    
    
  • 將函數作當成變量傳遞

//  根據函數類型定義變量并將函數傳遞給變量
var tempFunction : (String, String) -> String = test1
//  使用變量名調用函數
tempFunction("sd", "lw")

  • 將函數當成參數使用
//  將函數當成參數使用
func test3(str1 : String, str2 : String, tempFunction : (String, String) -> String) {
    print(tempFunction(str1, str2))
}

//  調用函數
test3("aa", str2: "bb", tempFunction: test1)    //  結果 aabb

  • 函數當成返回值
//  函數作為方法返回值
/**
 *  判斷一數是否為負數,是負數返回0,不是則返回原來的值
 */

//  正數調用此函數
func positive(num : Int) -> Int {
    
    return num
}
//  負數調用此函數
func negative(num : Int) -> Int {
    
    return 0
}

//  將函數作為返回值
func test(num : Int) -> (Int) -> Int {
    //  如果函數小于1就是負數,返回negative函數,如果大于1,則是正數,返回positive函數
    return num < 0 ? negative : positive
}

//  獲取返回值(函數)
let function = test(-1) //  因為是負數,所以返回negative函數

//  調用方法(再將-1傳入返回的函數)
function(-1)   //  結果為 0

枚舉類型

  • 枚舉用來定義一組通用類型的相關值,可以讓達到讓使用者按照設計者的規范使用特定的值

  • swift的枚舉非常靈活,可以給枚舉成員提供一個字符串,一個字符,一個整型或浮點值,不必給每個枚舉成員提供值

  • C語言和OC里面枚舉指定的一組相關成員為整型

  • 枚舉類型定義

    • 使用 enum 關鍵詞,將定義放在{}內
    • 使用 case 關鍵詞定義新枚舉成員
    • 需要注意的是,swift的枚舉在被創建的時候不會像C和OC那樣賦予默認整型值
    //  枚舉定義
    enum testType {
        case testTypeOne
        case testTypeTwo
        case testTypeThree
    }
    //  當然也可以簡寫成下面的方式(在枚舉成員特別多的情況下很好用)
    enum testType {
        case testTypeOne, testTypeTwo, testTypeThree
    }
    
    
  • 枚舉類型賦值

  • 枚舉類型賦值可以是整型、浮點型、字符、字符串

    • 如果有給枚舉類型賦值,必須在枚舉類型后面明確類型使用的類型


    //  枚舉類型賦值
    enum testType1 : Int {
        case One = 1
        case Two = 2
        case Three = 3
    }
    //  或
    enum testType2 : Int{
        case One = 1, Two, Three
    }
    
    
  • 枚舉類型使用

//  枚舉類型賦值(整型)
enum testType1 : Int {
    case One = 1
    case Two 
    case Three 
}

//  枚舉類型賦值(字符串)

enum testType2 : String{
    case One = "a", Two = "b", Three
}

let j = testType1(rawValue: 2)  //  獲取到枚舉成員Two

//  結果為Two
if let j = j {
    switch j {
    case .One:
        print("One")
    case .Two:
        print("Two")
    case .Three:
        print("Three")
    }
}

let i = testType2(rawValue: "a")    //  獲取到枚舉成員One

//  結果為One
if let i = i {
    switch i {
    case .One:
        print("One")
    case .Two:
        print("Two")
    case .Three:
        print("Three")
    }
}

注意:

1.如果明確了類型為整型且未設置初始值,那么由0開始依次遞增(默認)

2.如果明確了類型為整型但設置了初始值,就由初始值依次遞增


結構體(struct)

  • 結構體是一種數據結構

  • 結構體在方法(函數)中傳遞時時值傳遞,是值類型

  • 結構體是由一組相同類型或不同類型的數據組成的數據集合

  • 在特定情況下使用結構體,能使我們的代碼結構更清晰

  • 定義結構體格式

struct 結構體名稱 {
    屬性
}

  • 結構體使用
/**
 *  在手勢開發過程中,我們需要監聽手指移動的位置,這邊我們來判斷手指移動的開始位置和結束位置距離是否大于50
 */
 
//  初始化結構體
struct touchPoint {
    var x : Double
    var y : Double
}

//  定義函數
func Range(point : touchPoint) -> Bool {
    let tempX = point.x - startX
    let tempY = point.y - startY
    //  sqrt(n)用來計算n的平方根
    //  pow(x, n)用來計算x的n次方
    let range = sqrt(pow(tempX, 2) + pow(tempY,2))
    
    return range > 50
}

//  創建結構體
let start = touchPoint(x:53.0, y:21.0)
let end = touchPoint(x: 120.0, y: 320.0)

//  調用函數
Range(point)    //  結果:true

  • 結構體增強
    • 擴充構造函數
      • 默認情況下創建touchPoint時使用touchPoint(x:,y:)
      • 為了更加靈活地使用結構體,swift支持對構造函數進行擴充
      • 在擴充的構造函數中必須保證成員變量有值
      • 擴充的構造函數會覆蓋原有的構造函數

截止至:5.17 —— 1:00 5.18繼續

類的定義

  • swift也是面向對象開發的語言,而面向對象的基礎是類,由類產生對象

  • 在swift中定義類使用 class 關鍵字

  • 類的注意點:

    • 定義的類可以沒有父類,也就是這個類就是rootClass
    • 一般情況下,定義類的時候,繼承自NSObject(但并不是OC中的NSObject)
  • 格式:class 類名 : 父類 {
    屬性,方法
    }

  • 類的屬性

    • siwft中類的屬性分為:
      • 存儲屬性: 存儲實例常量和變量的屬性
      • 類屬性:與整個類自身相關的屬性
      • 計算屬性:通過某些算法計算出來的屬性
  • 存儲屬性

    • 存儲屬性是最簡單的屬性,作為類實例的一部分,用于存儲變量和常量
    • 可給存儲屬性提供默認值,也可以在初始化方法中對其進行初始化


    //  定義person類
    class person: NSObject {
        //  定義存儲屬性
        var name : String?  //  名字
        var age : Int = 0   //  年齡
    }
    
    //  創建person對象
    let ps = person()
    
    //  給存儲屬性賦值
    ps.name = "stephen"
    ps.age = 23
    
    
  • 類屬性

    • 類屬性是與類相關聯的屬性,但不是與類實例相關聯的屬性
    • 所有的實例和類共有一份類屬性,所以只要有某一處修改,這個類的屬性就會被修改
    • 類屬性的設置和修改必須通過類來完成
    • 類屬性使用 static 來修飾


    //  定義person類
    class person: NSObject {
        //  定義存儲屬性
        var name : String?  //  名字
        var age : Int = 0   //  年齡
    
        //  類屬性
        static var nickName : String?
    }
    
    //  設置類屬性值
    person.nickName = "laoWang"
    //  打印
    print(person.nickName!) //  結果:laoWang
    
    
  • 計算屬性

    • 計算屬性并不會存儲實際的值,而是提供一個getter和一個setter(可選類型)間接獲取和設置其它屬性
    • 一般情況下,只會提供getter方法,這種情況下的計算屬性為只讀屬性,可以省略 get{}


    //  定義person類
    class person: NSObject {
        //  定義存儲屬性
        var foodIntake : Double = 0.0 //    人的食量(一頓吃幾碗)
        var consume : Double = 0.0   //     消耗量
    
        //  定義計算屬性(差值)
        var difference : Double {
            get {
                return (foodIntake - consume)
            }
        
            //  newValue是系統自動分配的變量名,內部用來存儲新的值
            //  里面放的是get方法里面計算的值
            set {
                self.difference = newValue
            }
        }
    
    }
    
    //  創建person對象
    let  ps = person()
    
    ps.foodIntake = 50  //  吃的有點多肯定比我胖
    ps.consume = 25 //  消耗這么多驚呆小伙伴,看來是個肌肉男
    
    //  打印
    print(ps.difference)    //  結果 25.0
    
    

類的屬性改變監聽

  • OC里面我們可以重寫set方法來監聽屬性值的改變
  • swift則需要通過屬性觀察者來監聽和相應屬性值的變化
  • 一般只會監聽存儲屬性和類屬性改變,計算屬性我們不需要定義屬性觀察者,因為我們可以在計算屬性的setter中直接觀察并響應其值得變化
  • swift使用下面的觀察方法定義觀察者
    • willSet:在屬性值被存儲之前設置(新值會通過常量參數的方式傳入,這個參數就是newValue,我們可以給這個參數定義參數名,但一般保持默認)
    • didSet:新值被存儲后立即調用這個方法,和willSet相同,這時傳入的值是屬性的舊值,默認的參數名叫oldValue
    • willSet和didSet只在屬性第一次被設置的時候才會調用,初始化的時候并不會調用這2個監聽方法
class person: NSObject {
    var name : String? {
        
        willSet (newValue) {    //  屬性即將改變時調用
            //  會傳入系統默認的屬性newValue,用來存儲新值
            print("name:\(name), newValue:\(newValue)") //  結果:name:nil, newValue:Optional("laoWang")
        }
        
        didSet (oldValue) {
            //  會傳入系統默認的屬性oldValue,用來存儲舊值
            print("name:\(name), oldValue\(oldValue)")  //  結果:name:Optional("laoWang"), oldValuenil
        }
    }
    
}

//  創建person對象
let ps : person = person()

ps.name = "laoWang"


類的構造函數

  • 默認情況下創建一個類的時候,就會調用一個構造函數

  • 就算我們沒有編寫任何構造函數,編譯器也會提供一個默認的構造函數

  • 如果類繼承自NSObject,可以對父類的構造函數進行重寫

  • 構造函數和OC中的初始化方法init:相似

  • 構造函數使用

    • 類的屬性必須有值
    • 如果在定義時沒有初始化值,可以在構造函數內進行賦值


    class person: NSObject {
    
        var name : String
    
        //  因為繼承自NSObject,我們就重寫(父類)的構造方法
        //  override關鍵字表示調用父類方法
        override init() {
            //  在初始化name屬性時沒有給它賦值,所以可以在構造函數里面進行賦值
            name = "laoWang"
        }
    }
    
    //  創建person對象
    let ps : person = person()
    
    print(ps.name)  //  結果:laoWang
    
    
  • 初始化時給屬性賦值

    • 一般我們在創建一個對象的時候就會同時給屬性賦值,這時候我們可以自定義構造函數
    • 需要注意的:如果我們自定義了構造函數,就會覆蓋init:方法,也就是說不會有默認構造函數


    class person: NSObject {
    
        var name : String
    
        //  自定義構造函數,覆蓋init:函數
        init(name : String) {
            //  在初始化self.name屬性時沒有給它賦值,所以可以在構造函數里面進行賦值
            self.name = name
        }
    
    }
    
    //  創建person對象
    let ps : person = person(name: "laoWang")
    
    print(ps.name)  //  結果:laoWang
    
    
  • 字典轉模型方式一

    • 開發中,我們經常會將字典轉換成模型在來使用,這邊就以此做例子
    • 需要注意的是:字典中取出的數據類型為NSObject,我們可以通過as!將其轉成需要的類型


    class person: NSObject {
    
        var name : String
    
        //  自定義構造函數,覆蓋init:函數
        init(dict : [String : NSObject]) {
        
            self.name = dict["name"] as! String
        }
    
    }
    
    //  創建person對象
    let ps : person = person(dict:["name" : "laoWang"])
    
    print(ps.name)  //  結果:laoWang
    
    
  • 字典轉模型方式二

    • 開發中我們經常會用KVC的方式將字典轉成模型,這邊就使用KVC對字典進行轉換

    • 需要注意的是:KVC不能保證給所有屬性賦值,所以屬性需要有默認的值

      • 對象、結構體類型定義一般為可選類型就可以了,因為可選類型沒有賦值前為nil
      • 基本數據類型一般設置為0


      class person: NSObject {
          //  KVC方式下,對象、結構體類型必須是可選類型,否則無法轉換
          var name : String?
      
          //  自定義構造函數,覆蓋init:函數
          init(dict : [String : NSObject]) {
      
              //  必須先初始化對象
              super.init()
      
              //  調用對象的KVC方法
              setValuesForKeysWithDictionary(dict)
           }
      
      }
      
      //  創建person對象
      let ps : person = person(dict:["name" : "laoWang"])
      
      print(ps.name)  //  結果:laoWang
      
      
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容