Swift隨筆

簡單記錄一些自己容易忘記的碎片化的點

一、tips

1、swift中文名雨燕
2、不用編寫main函數,將全局范圍內首句可執行代碼作為程序入口
3、一句代碼尾部可以省略分號,多句代碼寫到同一行必須用分號隔開
4、var定義變量,let定義常量,編譯器能夠自動推斷出變量和常量的類型

二、常見數據類型

Swift常見數據類型.png

三、函數文檔注釋

    ///
    /// 求和【概述】
    ///
    ///  將兩個整數相加【更加詳細的描述】
    ///
    /// - Parameter a: 參數a描述
    /// - Parameter b: 參數b描述
    /// - Returns :兩個整數的和
    ///
    /// - Note:傳入兩個整數即可【批注】
    ///
    func sum(a: Int, b: Int) -> Int {
        a + b
    }

調用的時候,按住option,點擊函數名即可出現下圖的注釋效果:


注釋.png

MARK / TODO / FIXME

  • MARK: 類似于OC中的 #pragma mark
  • MARK: - 類似于OC中的 #pragma mark - (預覽的時候跟上個相同級別的標注之間會有線隔開,見下面圖片中灰色線條)
  • TODO: 用于標記未完成的任務
  • FIXME: 用于標記待修復的問題
  • warning("undo"):如果覺得 TODO: 不夠明顯, 可以考慮用這個

    // MARK: - 私有方法
    
    // MARK: test1方法
    private func test1() {
        // TODO: 未完成
    }
    
    // MARK: test2方法
    private func test2() {
        // FIXME: 有待修復的問題
    }
    
    
    // MARK: - 公共方法
    
    // MARK: test3方法
    public func test3() {}
    
    // MARK: test4方法
    public func test4() {}
    
    // 警告,會在代碼中有明顯的黃色嘆號提示
    #warning("undo")

注釋.png

四、參數

1、可以修改參數標簽

    func gotoSchool(at time: String) {
        print("go to school \(time)")
    }
    gotoSchool(at: "08:00")

2、可以使用下劃線_ 省略參數標簽,相對復雜的盡量不要省略

    func sum(_ a: Int, _ b: Int) -> Int {
        a + b
    }
    print(sum(10, 20))

3、參數類型后面加上三個點表示可變參數,可以傳多個對應類型的參數

需要注意的問題:
1、一個函數最多只能有一個可變參數
2、緊跟在可變參數后面的參數不能省略參數標簽

    func sum(_ numbers: Int...) -> Int {
        var total = 0
        for number in numbers {
            total += number
        }
        return total
    }
    print(sum(10, 20, 30, 40)) // 100

五、Optional-可選項

可選項,一般也叫可選類型,它允許將值設置為nil,在類型名稱后面加個?來定義一個可選項

        var name: String? = "Jack"http:// 不寫= "Jack",默認就是nil
        name = nil

可選項是對其它類型的一層包裝,如果要從可選項中取出被包裝的數據,需要使用感嘆號!進行強制解包

        let count: Int? = 10
        var countAdd: Int = count!
        countAdd += 10
        print(countAdd)

如果對值為nil的可選項進行強制解包,會產生運行時錯誤,程序直接崩潰

        let count: Int?
        // 如果count為nil,強制解包程序會crash
        count!
        // 在實際開發中我們一般會這樣做
        if let temp = count {
            // 在這里進行處理
            print(temp)
        }

可選項的本質是 enum 類型,下面兩種寫法完全等價

        let a: Int? = 10
        
        let b: Optional<Int> = .some(10)

六、運算符

1、??:合并空值運算符

        a ?? b

(1)用于判斷常量或者變量的值是否為nil,如果為nil,則取后面的值,不為nil,取前面的值。有點兒類似三目運算符
(2)上面的表達式,如果a有值,則取a,如果a為nil,則取b

應用示例:

    func sum(a: Int?, b: Int?) -> Int {
        
        // 方法一:如果a或者b有nil,則程序會crash
        return a! + b!
        
        //方法二:判斷條件太多,容易遺漏
        if a != nil {
            if b != nil {
                return a! + b!
            } else {
                return a!
            }
        } else {
            if b != nil {
                return b!
            } else {
                return 0
            }
        }
        
        //方法三:簡潔、安全
        return (a ?? 0) + (b ?? 0)
        
    }

2、reversed():倒序索引

        for i in (0...9).reversed() {
            print(i)
        }
        // 輸出結果
        9
        8
        7
        6
        5
        4
        3
        2
        1
        0

3、\color{red}{,} (逗號)

做判斷的時候在兩個條件中間加一個 \color{red}{,} 相當于 &&

        let  a: Int = 11

        // 判斷1 和 判斷2 等價
        // 判斷1
        if a > 0, a > 11 {
            print(123)
        }
        // 判斷2
        if a > 0 && a > 11 {
            print(123)
        }
    

七、guard

guard語句,有點兒類似if語句,但是后面會一直跟著else語句,并且else里面的語句只有在guard條件不為真的時候才執行。下面兩段代碼是檢測ip地址是否正確,第一段用if實現,第二段用guard實現。

    // 試用if判斷ip地址是否正確
    func checkIpAddress(ipAddress: String) -> (Int, String) {
        // 用點來分割ip地址
        let compoment = ipAddress.split(separator: ".")
        if compoment.count == 4 {
            if let first = Int(compoment[0]), first >= 0 && first < 256 {
                if let second = Int(compoment[1]), second >= 0 && second < 256 {
                    if let third = Int(compoment[2]), third >= 0 && third < 256 {
                        if let fourth = Int(compoment[3]), fourth >= 0 && fourth < 256 {
                            return (100, "ip地址是正確的")
                        } else {
                            return (4, "ip地址第四部分不對")
                        }
                    } else {
                        return (3, "ip地址第三部分不對")
                    }
                } else {
                    return (2, "ip地址第二部分不對")
                }
            } else {
                return (1, "ip地址第一部分不對")
            }
        } else {
            return (0, "ip地址必須有四部分")
        }
    }
    // 試用guard判斷ip地址是否正確
    func checkIpAddress(ipAddress: String) -> (Int, String) {
        let compoment = ipAddress.split(separator: ".")
        
        guard compoment.count == 4 else {
            return (0, "ip地址必須有四部分")
        }
        
        guard let first = Int(compoment[0]), first >= 0 && first < 256 else {
            return (1, "ip地址第一部分不對")
        }
        
        guard let second = Int(compoment[1]), second >= 0 && second < 256 else {
            return (2, "ip地址第二部分不對")
        }
        
        guard let third = Int(compoment[2]), third >= 0 && third < 256 else {
            return (3, "ip地址第三部分不對")
        }
        
        guard let fourth = Int(compoment[3]), fourth >= 0 && fourth < 256 else {
            return (4, "ip地址第四部分不對")
        }
        
        return (100, "ip地址是正確的")
    }

八、字符串

1、首字母大寫:capitalized

        let str = "hello world"
        print(str.capitalized)
        // 輸出:Hello World

2、字符全部轉大寫

        let str = "hello world"
        print(str.uppercased())
        // 輸出:HELLO WORLD

3、字符全部轉小寫

        let str = "HeLLo WoRlD"
        print(str.lowercased())
        // 輸出:hello world

九、數組

1、以逗號拼接字符串數組所有元素為一個字符串

        let arr = ["you", "only", "live", "once"]
        let newArr = arr.joined(separator: ",")
        print(newArr)
        // 輸出
        you,only,live,once

2、字符串轉數組

        let str = "you only live once"
        let arr = str.components(separatedBy: " ")
        print(arr)
        // 輸出
        ["you", "only", "live", "once"]

十、輸入輸出參數(In-Out Parameter)

可以用inout定義一個輸入輸出參數,在函數內部修改外部變量的值
inout的本質是地址傳遞(引用傳遞)
inout參數不能有默認值
可變參數不能標記為inout
inout參數的傳入值能被多次賦值

        func swapValue(_ v1: inout Int, _ v2: inout Int) {
            let tmp = v1
            v1 = v2
            v2 = tmp
        }
        
        var num1 = 10
        var num2 = 20
        swapValue(&num1, &num2)
        print(num1, num2)
        // 打印結果
        // 20 10

十一、可變參數

參數類型后面加三個點表示可變參數
一個函數最多只能有1個可變參數
緊跟在可變參數后面的參數不能省略參數標簽

    func sum(_ numbers: Int..., other: Int) -> Int {
        var total = 0
        for item in numbers {
            total += item
        }
        return total + other
    }
    let result = sum(1, 2, 3, 4, other: 5)
    print(result)
    // 打印結果
    // 15

十二、屬性

嚴格來說,屬性可以按下面方式劃分

  • 實例屬性(Instance Property)
    1.存儲實例屬性(Stored Instance Property)存儲在實例的內存中,每個實例都有1份
    2.計算實例屬性(Computed Instance Property)

  • 類型屬性(Type Property)
    1.存儲類型屬性(Stored Type Property)整個程序運行過程中,就只有1份內存(類似于全局變量)
    2.計算類型屬性(Computed Type Property)

十三、mutating

結構體和枚舉是值類型,默認情況下,值類型的屬性不能被自身的實例方法修改
在 func 關鍵字前加 mutating 可以允許這種修改行為

    // 結構體
    struct Point {
        var x = 0.0, y = 0.0
        mutating func moveBy(_ deltaX: Double, _ deltaY: Double) {
            x += deltaX
            y += deltaY
        }
    }
    // 枚舉
    enum StateSwitch {
        case low, middle, high
        mutating func next() {
            switch self {
            case .low:
                self = .middle
            case .middle:
                self = .high
            case .high:
                self = .low
            }
        }
    }

十四、@discardableResult

調用有返回值的方法,如果沒有使用返回的值,會有一個黃色的警告,如果想消除這個警告,可以在方法前面加上 @discardableResult
注:除非特殊需求,建議非必要不要使用

    @discardableResult func add(_ a: Int, _ b: Int) -> Int {
        a + b
    }
    // 這樣直接調用就不會有警告了
    add(10, 3)

十五、class & static & final

1、被class修飾的類型方法、下標,允許被子類重寫
被static修飾的類型方法、下標,不允許被子類重寫
2、被class修飾的計算類型屬性,可以被子類重寫
被static修飾的類型屬性(存儲、計算),不可以被子類重寫
3、被 final 修飾的方法、下標、屬性,禁止被重寫
被final修飾的類,禁止被繼承

十六、(+) (-)

Swift 編譯器特性

        // 兩個 Int 類型參數相加、相減
        let dic: [String: (Int, Int) -> Int] = [
            "sum": (+),
            "minus": (-)
        ]
        
        let result1 = dic["sum"]?(10, 5)
        let result2 = dic["minus"]?(12, 5)
        
        print(result1)
        print(result2)

十七、Any / AnyObject

  • Any:可以代表任意類型(枚舉、結構體、類、也包括函數類型)
  • AnyObject:可以代表任意 類 類型(在協議后面加上:AnyObject,代表只有類能遵守和這個協議)

十八、數組、字典聲明

        // 下面兩種聲明數組的方法完全等價
        var arr = Array<Int>()
        var arr = [Int]()

        // 下面兩種聲明字典的方法完全等價
        var dic = Dictionary<Int, Int>()
        var dic = [Int: Int]()

十九、is、as、as?、 as!

i s 用來判斷是否為某種類型, as用來做類型強制轉換

二十、訪問控制(Access Control)

在訪問權限控制這塊,Swift提供了5個不同的訪問級別,以下是從高到低排列,實體指的是被訪問級別修飾的內容

  • open:允許在定義實體的模塊,其它模塊中訪問,允許其它模塊進行繼承、重寫(open只能用在類、類成員上)
  • public:允許在定義實體的模塊、其它模塊中訪問、不允許其它模塊進行繼承、重寫
  • internal:只允許在定義實體的模塊中訪問,不允許在其它模塊中訪問
  • fileprivate:只允許在定義實體的源文件中訪問
  • private:只允許在定義實體的封閉聲明中訪問

注:絕大部分實體默認都是 internal 級別

二十一、API可用性說明

比如你自己封裝了一個三方框架,但是在升級過程中有的API被廢棄掉,或者已過期,可以進行下面的操作

struct Student {
    
    // 方法名重命名
    @available(*, unavailable, renamed: "study")
    func study1() {}
    func study() {}
    
    // 方法在iOS被廢棄掉
    @available(iOS, deprecated: 11)
    func run() {}
}

        let stu = Student()
        // 會提示 'run()' was deprecated in iOS 11
        stu.run()
        // 會提示 'study1()' has been renamed to 'study'
        stu.study1()

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容