iT邦幫忙

0

[Cmoney 菁英軟體工程師戰鬥營] IOS APP 菜鳥開發筆記(2)

ios

前言

從上週末開始到週三,除了學習老師教的觀察者模式(Observer Pattern)和幾種排序方法外,其他的時間多數在利用Xcode的Playground,來練習Swift的基本語法。此外也將專案做了版本控制,和拆分了大致的專案資料夾架構(用MVVM的模式)。

以下附上目前整理完成的Swift筆記:

資料型態

  • 基本資料型態大致有 Int 、 Double 、 Float 、 Bool

  • 查看型別:

    var str
    str =  "abc"
    print(type(of:str))
    

可選型別(Optional)

  • Optional 本質是一個 enum 型別,裡面定義了兩種狀況。

    1. none : 放 nil
    2. some: 放非 nil 值 ,可用 ! 取出 some 裡的值
  • 任何型別只要有加上可選型別(optional type)都可以設置成nil。使用方法為在型別標註後面加上一個問號?,如下:

        // 在宣告變數時 型別標註後面加上一個問號 ?
        var someScore: Int?  // 因為目前尚未指派 所以目前 someScore 會被設置成 nil , 也就是沒有值的狀態
        someScore = 100
        print(someScore!) //如果確定可選型別的變數內有值,加上驚嘆號可取出值
        someScore = nil

​ 如果沒有經過這個步驟,不能直接把變數設成 nil , 比如以下這樣寫會報錯:

        var someScore: nil		


空值判斷 (if / guard let)

  • guard let 和 if let 的作用大同小異,同樣可讓 let 後的常數名和 optional 同名,主要的差別在以下幾個地方:

    • guard let 的 else { } 程式將在 optional 無值時執行,跟 if let 相反,if let 的 { } 程式將在 optional 有值時執行。
    • guard let 後的常數可在 guard let else { } 後繼續使用,if let 後的常數只能在 if let 的 { } 裡使用。
    	// newName 可在 guard let else { } 後繼續使用   
    	func showName(name: String?) {
           guard let newName = name else { return }
           print("my name is \(newName)")
        }
    
    	//newName 不可在 if let else { } 後繼續使用    
    	func showName2(name: String?) {  
    
            if let newName = name {     
                print("my name is \(newName)") 
            }   
            print("my name is \(newName)")
        }
    
  • App 的表單輸入頁面很適合搭配 guard let 檢查欄位。

  • guard let 也可以串接多個 optional,以下為檢查表單欄位新增資料的例子:

        func createBook(title: String?, price: Double?, pages: Int?) {
    
           guard let title = title, let price = price, let pages = pages else { 
               return 
           }
           // 以下區塊可加入新增 Book 的程式碼
           print("\(title) costs $\(price) and has \(pages) pages.")
        }
    

字串(String)

  • 字串相加可以用 + 號 ,也可以用 .append()

  • 字串相等判斷用 ==

  • == "" 或屬性 .isEmpty判斷是否為空字串

  • 屬性 .count取得字串長度

  • 分割字串 : split(separator) ,分割後以陣列型態傳回

    let str = "ab,cd,ef"
    let arr = str.split(separator:",") //用逗號分割
    
        var a = "a";
        //字串中用 " \(變數、常數或表達式) " 來串接其他型態變數,其他型態與字串不能直接用加號串接!
        var b = "ddd\(a)";    
        print(b) // 印出 ddda

        var c = "cc"
        var e = "e"
        print(c+e); //印出cce

        // u{24}的值為$這個符號, 代表 Unicode 純量 U+0024
        let dollarSign = "\u{24}"  


        let str2 = "What a lovely day !"
        print(str2.count)  // 印出字元數量:19


        if str4.hasPrefix("It is") {  //如果前綴字串相同
            print("Prefix")
        }
 		if str4.hasSuffix("Sunday") {  //如果後綴字串相同
            print("Suffix")
        }


元組(tuple)

  • 將多個值組合成一個複合值,其內的型別可以不同,以一對小括號()前後包起來,每個值以逗號分隔,範例如下:
        let myInfo = ("Kevin Chang", 25, 178.25)

        let myHeight = myInfo.2  //這邊依照順序的索引值,取出178.25


        // 將上面宣告的 myInfo 分解成三個常數
        let (myName, myAge, myRealHeight) = myInfo        
        print("My name is \(myName) .") // 印出:My name is Kevin Chang .


        //把不需要的用底線 _ 標記
        let (_, _, myTrueHeight) = myInfo 
        print("My height is \(myTrueHeight) .") // 印出:My height is 178.25 .


        //在宣告元組時就個別給裡面的值一個名稱
        let herInfo = (name:"Jess", age:24, height:160.5)
        print("Her name is \(herInfo.name) . ") // 印出:Her name is Jess .
  • 元組比較大小會依序由左到右逐個比較,直到有兩個值不相等為止。而如果所有值都相等,則會將這一對元組稱為相等的。

  • Swift 在比較元組的成員時,限制最多只能比較六個成員,如果有七個或七個以上成員則無法比較。

        // true 因為 3 等於 3,但是 apple 小於 bird (依字串的各字元由左至右逐個比較)
        (3, "apple") < (3, "bird")
    

集合型別

​ Swift 提供三種基本的集合型別:ArraySetDictionary來儲存集合資料。

  • Array 陣列:按順序儲存資料。

  • Set 集合:沒有順序、不能重複儲存資料。

  • Dictionary 字典:沒有順序,鍵值對 key : value ,也就是可以經由唯一的識別鍵找到需要的值。

變數宣告

  • var : 宣告一般變數
  • let : 宣告常數

轉型

var a = 1.2
var b = Int(a)  // b強轉後等於1

空值聚合運算子

  • 即使變數或常數是 nil 也能變出預設值

  • a ?? b , 先判斷a是否為nil,如果a有值,不是nil,就會解析a並返回,但如果anil,則返回預設值b

    let defaultColor = "red"
    
    var userDefinedColor: String? // 未指派值 所以預設為 nil
    
    var colorToUse = userDefinedColor ?? defaultColor // 未指派值給 userDefinedColor ,所以會返回 defaultColor
    
    print(colorToUse) // 這邊即印出:red
    

區間運算子

  1. 閉區間運算子: a...b,定義一個包含從ab(包括ab)的所有值的區間。b必須大於等於a

  2. 半開區間運算子: a..<b,定義一個從ab但不包括b的區間。b必須大於等於a,但當a等於b時,則不會有值。

  3. 單側區間運算子: a......a,代表一個只有以一邊a為起點或終點,另一邊則是無限延伸的區間

    let names = ["Anna", "Alex", "Brian", "Jack"]
    
    for name in names[2...] {  // 從陣列索引值為 2 的值開始依序印出 Brian  Jack
        print(name)
    }
    
    

陣列

  • 宣告陣列
        var arr3 = [Int]()  // 宣告一個型別為 Int 的空陣列
        var anotherArr: [Int] = []  // 宣告另一個型別為 Int 的空陣列
 		var arr : Array<Int> = Array<Int>() 
  • 合併陣列內容

        var threeInts = Array(repeating: 0, count: 3)  // repeating是指定預設值,這邊代表陣列為 [0, 0, 0]
    
        // 接著再創建一個 [2,2,2] 的陣列
        var anotherThreeInts = Array(repeating: 2, count: 3)
    
        // 最後將兩個陣列合併
        var SixInts = threeInts + anotherThreeInts
        // 會變成 [0,0,0,2,2,2]
    
  • 新增 / 插入 / 刪除陣列內容

        var arr6 = ["Apples", "Eggs"]
    
        arr6.append("Milk")  //新增。變成 ["Apples", "Eggs", "Milk"] 
    
        arr6.insert("Rice" ,at: 0) //插入。變成 ["Rice" ,"Apples", "Eggs", "Milk"]
    
        arr6.remove(at:1) //移除。變成 ["Rice", "Eggs", "Milk"]
    
  • 用 for in 遍歷 Array 中的值(類似for each)

        var arr7 = ["Rice" ,"Apples", "Eggs", "Milk"]
        for item in arr7 {
            print(item)
        }
        //當同時也需要獲得陣列值時 可以使用 enumerated() 方法
        for (index, value) in arr7.enumerated() {
            print("Item \(index + 1): \(value)")
        }
        // 會依序印出:
        // Item 1: Rice
        // Item 2: Apples
    
  • sort 排序。 sort() 會影響原本的陣列內容; sorted() 則會將排序結果回傳成另一陣列,不影響原內容。

    	arr.sort() //[1,2,5,7]
    
  • sort(by:) 設定排序方式。

    	arr.sort(by:>)  //[7,5,2,1]
    
  • reverse()reversed() 將陣列反置。

     	arr.reverse()  //[1,2,5,7]
    
  • contains(_:) 檢查某元素是否存在於陣列中,並回傳 boolean 值。

    	arr.contains(2) // true
    

字典(dictionary)

  • key(鍵) 必須是唯一且不可重複

  • 用來儲存多個相同型別的值。每個值(value)都屬於一個唯一的鍵(key),鍵作為字典中這個值的識別符號,所有鍵的型別也必須相同(鍵與值的型別不一定要相同)。

  • 字典內的值沒有順序,所以需要根據這個鍵(key)來找到需要的值(value)。宣告字典型別時,使用 Dictionary<Key, Value>

        // 宣告一個字典型別
        var someDict: Dictionary<String, String>

        // 或是這樣也可以
        var someAnotherDict: [String:String , String:a, String:b]

條件判斷 guard else

  • guard else跟 if else一樣,後面都是接結果為 true 或 false 的條件,但 guard 卻有以下幾點不同之處:

    • guard 喜歡依賴別人,不能沒有 else。

    • guard 後專門描述我們希望成立的條件。當條件成立時,程式將離開 guard 搭配的 else { },繼續往下執行我們希望條件成立時做的事。

    • 當 guard 的條件不成立時,將執行 else { } 的程式。

    • else { } 的程式執行後,必須離開 guard 所在區塊,如此才不會繼續往下執行條件成立時要做的事。就像剛剛的例子,我們利用 return 離開 function motherSay。

         guard age > 18, weight > 40 else {  //多重條件
            print("年紀不夠大,體重太輕,只能乖乖唸書")
            return
         }
      

流程控制

for in 循環

  • 使用for-in遍歷一個集合內的所有元素,像是一個數字區間、陣列、字典中的值或是字串內的字元,例子如下:

    for index in 1...3 {
        print(index)
    }
    

while循環

repeat-while循環

  • 類似Java的 do while 循環

switch case

  • swift 的 switch case 不需要寫break,執行完第一個成功的case後,就會自動跳出。如果在特殊情況下需要執行緊接著的下一個case內的程式,就要用到 fallthrough。加上 fallthrough後進入到的下一個case,不會對其條件做比對,而是直接執行其內的程式。 比如以下程式碼:

        let number7 = 5
        var str4 = ""
    
        switch number7 {
            case 2,3,5,7,11,13,17,19:
                str4 += "It is a prime number. "
                fallthrough
            case 100,200:
                str4 += "Fallthrough once. "
        }
        print(str4) //印出 It is a prime number. Fallthrough once.
    
  • case中比對的情況也可以是一個區間

        let number5 = 0
        var str3: String
    
        switch number5 {
            case 0...10:
                str3 = "幾"
            case 11...100:
                str3 = "很多"
            default:
                str3 = "超級多"
        }
    
    	print("我有\(str3)顆蘋果")  //印出:我有很多顆蘋果
    

版本判斷

  • 當不同版本的作業系統提供的API不一樣時,在程式中必須判斷作業系統版本,確保app可以順利運作,程式碼範例如下:

    //平台名稱可以是iOS、macOS或watchOS。版本號可以是大版本號像是iOS 10,或是較小的版本像是macOS 10.12
    
    if #available(平台名稱 版本號, ..., *) {   										     
        // 在某個平台或版本下使用特別的 API
    } else {
        // 而其他的平台或版本則使用其他的 API
    }
    
    if #available(iOS 10, macOS 10.12, *) {
        // 在 iOS 使用 iOS 10 的 API
        // 在 macOS 使用 macOS 10.12 的 API
    } else {
        // 使用先前版本的 iOS 和 macOS 的 API
    }
    

存取等級

  • 從寬鬆到嚴格依序為:

    1. open : 不同的模組可以繼承也能夠存取。例如一個定義在framework中的open類別,可以在 APP 中 import framework 然後繼承、覆寫它

    2. public: 模組內可以繼承、覆寫;模組外可以看到與使用,但不能繼承、覆寫。

    3. internal (預設) : 模組內可以繼承、覆寫;模組外看不到。

    4. fileprivate: 同一個檔案內可以存取。

    5. private: 同一類可以存取。

      swift 4 開始,允許 extension 中的程式可以存取原本類別中的 private 等級變數或函式,但 extension 必須與原類別在同一個檔案中

函式

  • 建立一個函式要使用func關鍵字,函式格式如下:
        func 函式名稱(參數: 參數型別) -> 返回值型別 {
            內部執行的程式
            return 返回值
        }

      實際寫成如下:

        func addOne(number: Int) -> Int  {
            // number 即為被指派參數的常數 只能在函式內部範圍內使用
            let n = number + 10
            print(n)
            return n
        }

        addOne(number: 12)  // 呼叫函式傳入整數 12  印出 13
      

​ 如果在函式呼叫時,不想要加上 argument label,可以用 _ 代替。範例如下:

 // ... 宣告一個參數數量不固定的函式,傳進函式中的參數被轉為陣列型態	
 // func addOne(_number: Int ...) 
 
 //  = 後為呼叫時沒給值時的預設值	
 // func addOne(_number: Int = 5)  

		func addOne(_number: Int ) -> Int  { 
            // number 即為被指派參數的常數 只能在函式內部範圍內使用
            let n = number + 10
            print(n)
            return n
        }
		addOne(12) 

​ // inout關鍵字,傳址, 取出時變數前加 &

列舉(enum)

  • swift中的enum可以寫function,容易實現狀態模式

  • 列舉使用case關鍵字定義成員值,例子如下:

    enum CompassPoint {
        case north
        case south
        case east
        case west
    }
    
    var directionToHead = CompassPoint.west
    
    // 這時已經可以自動推斷這個變數的型別為 CompassPoint
    
    directionToHead = .south // 如果要再指派新的值 可以省略列舉的型別名稱
    
    switch directionToHead {
        case .north:
        print("Lots of planets have a north")
        case .south:
        print("Watch out for penguins") // 這行會被印出
        case .east:
        print("Where the sun rises")
        case .west:
        print("Where the skies are blue")
    }
    

值型別與參考型別

  • Swift 中以記憶體配置的方式不同來說,可以分為值型別(value type)與參考型別(reference type)。值型別會儲存實際的值,而參考型別只是儲存其在記憶體空間中配置的位置。
  • class和closure(閉包)是參考型別
  • struct和enum是值型別
  • 在 Swift 中,所有的基本型別:整數、浮點數、布林值、字串、陣列和字典,都是值型別,並且背後都是以struct的形式實作。

下半週目標

本週剩下的時間會繼續練習後面的語法,並且開始摸索 ARKit 的使用方式,因為我們的 APP 將會使用到 AR 的技術。


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言