大白話Swift入門

wangcj123發表於2020-03-15
  1. !?

    ?表示可選型別,如果申明屬性或變數的話就是預設值為nil的意思,

    !表示解包,對加!的在使用 前一定要做判nil處理,一般用if let 和 guard let來判斷,或者用 if a != nil 來做判斷

  2. 閉包的使用

    閉包的表示式:

    {(引數)-> 返回值 in

    //程式碼

    }

使用例子

申明為變數:

typealias Swiftblock = (String,Any) -> Void

var testBlock: Swiftblock?
複製程式碼

使用:

 testBlock?("ddd","ffffff")
複製程式碼

實現:

{ [weak self] (a,b) in
        
    print(a)
    print(b)
}

[weak self]是為了防止迴圈引用,(a,b)是傳過來的引數
複製程式碼

逃逸閉包:

就是閉包作為函式的引數,但是在函式結束以後才去執行這個引數的就叫逃逸閉包,在引數型別前加@escaping

逃逸閉包的使用例子

private func requestData(success:@escaping (Any) -> Void) {
    
    DispatchQueue.global().async {
    
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3, execute: {
            success("data") //3秒後才執行閉包success
        })
    
    }
複製程式碼

在這個例子中閉包success作為引數,但是他在函式執行完以後過了一段時間才執行,所以他就是逃逸閉包

  1. Any 和AnyObject 型別的 付值時一定要用 as! 或 as? 做型別匹配

例子:

 requestData { (data) in
        
        let str: String = data as! String //因為data是Any型別的付值給String型別的就需要做型別匹配 ,用as!要確保型別一致且不為nil
        print(str)
        
        //或者用as? 來做型別匹配如下
        
        if let stra = data as? String {
            print(stra)
        }
        
        let strb: String = data as? String ?? ""
        print(strb)
        
        guard let strc = data as? String else {
            return
        }
        print(strc)
        

}

func requestData(success:@escaping (Any) -> Void) {
    success("data")
}
複製程式碼

上面例子中因為引數data是Any型別的付值給String型別的時候就需要做型別匹配

  1. 申明函式引數或返回值的時候加?,否則傳引數或返回返回值的時候對於可選型別的值要加"!"

  2. 寫代理模式的時候

     protocol CCDelegate : class {
         func doSomething()
    }
    複製程式碼

記得在後面加上class關鍵字,一般加class ,

代理當作變數的時候用weak 修飾防止迴圈引用

 weak var  delegate: CCDelegate?
複製程式碼
  1. if let 和 guard let 的用法,一般用來做非空判斷

    var some: String?	
    
    if some != nil{
        
        print(some!)
    }
    
    //或者
    guard some != nil else{ return }
    
    print(some!)
    
    //上面的判斷用 if let 和guard let 如下
    
    if let aSome = some{
        
        print(aSome)
    }
    
    guard let aSome = some else {
        return
    }
    print(aSome)
    複製程式碼
  2. swift單例的使用

單例的一般書寫格式

class SingleTest {
   static let shared = SingleTest() 
   private init() {}  //一定要加private防止外部通過init直接建立例項
}
複製程式碼

單例的使用例子:

單例類

class SingleTest {

   var aValue: NSString?
   var bValue: NSString?
   static let shared = SingleTest()
   private init() {}  //一定要加private防止外部通過init直接建立例項
}


單例的使用

SingleTest.shared.aValue = "aaa"
SingleTest.shared.bValue = "bbb"
    
print("SingleTest.shared.aValue =\(SingleTest.shared.aValue ?? "kong")")
    
//輸出結果為:SingleTest.shared.aValue =aaa
複製程式碼
  1. .type .self 和 type(of:) 的簡單理解

.type 是類的型別相當於oc中的Class,

.self 是 靜態的在編譯時就確定的類 相當於oc中的class

type(of:) 是例項的類 ,相當於oc 中的 class

例子:

    let aa = "aaaa"
    
    let stringMetaType: String.Type = String.self
    
    let stringInstanceType: String.Type = type(of: aa)
  
    print("stringMetaType = \(stringMetaType)")
    
    print("stringInstanceType = \(stringInstanceType)")
    
    
    if type(of: aa)  ==  String.self  {
        print("bbbbbbbb")
    }
    
    if type(of: aa) is String.Type{
        
        print("cccccc")
    }
複製程式碼

//列印結果如下

stringMetaType = String

stringInstanceType = String

bbbbbbbb

cccccc

從上面的例子可以得到驗證

  1. Swift Protocol 及面向協議程式設計(POP)的理解

協議的一般書寫格式

protocol TestProtocol {
    var testVar: Int { get set}
    func testFunc()
}
複製程式碼

Protocol是約定的一種協議,協議中可以有變數,和方法,協議就是一種約定,如果某個物件遵守了該約定就要去實現該約定(協議)的方法和變數(如果遵守了就好比是承諾了就得去實現),協議中方法和變數也可以定義為可選(optional)型別的,如果變數或方法是可選型別的就不需要一定去實現。

協議中方法和變數為可選的protocol格式如下:

 @objc protocol TestProtocol {
    @objc optional var testVar: Int { get set}  //可選 
    //協議中的變數需要指定 get set
    @objc optional func testFunc() //可選
    func noOptionFunc()  //不可選
}
複製程式碼

協議的使用

  class TestClas: TestProtocol {

    //實現協議TestProtocol中的方法
    func noOptionFunc() {
    
        print("一定要實現的函式")
    }
    
    //實現協議TestProtocol中的方法
    func testFunc() {
        print("不需要一定實現的函式")
    }

}
複製程式碼

protocol中的 associatedtype關鍵字

associatedtype用來定義一個在協議中的“泛型”型別 定義為 associatedtype型別的在實現協議的類中使用的時候指明該型別的具體型別是什麼就可以了

associatedtype的例子如下

 protocol TestProtocol {
    associatedtype Num
    func testFunc() -> Num
}

class TestClassInt: TestProtocol {
    func testFunc() -> Int {
        return 1
    }

}

class TestClassDouble: TestProtocol {

     func testFunc() -> Double {
         return 1.666666666
     }
}
複製程式碼

上面例子 TestProtocol中的 Num 被定義為associatedtype,在 TestClassInt和TestClassDouble中用的時候 把Num分別替換為相應的Int 和 Double即可

協議的擴充套件( Protocol Extension):

協議擴充套件可以給協議內部的函式新增實現以及給協議新增新的函式等,從而將函式功能新增到遵守協議的所有型別中

例子如下:

 @objc protocol Person {
    @objc optional var age: Int { get set}
    @objc optional func work()
}

//Person的擴充套件
 extension Person {

    func work(){
        print("我想上廁所")
    }

    func run() {
    
        print("我在跑步")
    }
}
複製程式碼

//Man遵守protocol Person協議

class Man:Person  {

    var age: Int = 20
    func run() {
        print("我是男的也在跑步")
    }
}

//Woman 遵守protocol Person 協議
class Woman: Person {
    var age: Int = 18
    func work() {
        print("去女廁所上廁所")
    }
}

let man = Man()
man.work()
man.run()
let woman = Woman()
woman.work()
woman.run()
複製程式碼

//列印結果如下

//我想上廁所
//我是男的也在跑步
//去女廁所上廁所
//我在跑步
複製程式碼

上面例子就是對協議擴充套件的應用

面向協議程式設計(POP)的理解

簡單理解面向協議程式設計就是用定義協議來代替物件導向程式設計中的繼承多繼承等還能達到使用靈活和解偶的目的。

  @objc protocol Person {

     @objc optional var age: Int { get set}
     @objc optional func work()
  }
複製程式碼

//男性

  class Man:Person  {

      var age: Int = 20
      func work() {
          print("去男廁所上廁所")
      }
   }
複製程式碼

//女性

 class Woman: Person {
    var age: Int = 18
    func work() {
        print("去女廁所上廁所")
    }
 }
複製程式碼

上面例子中定義了一個Person的協議,讓Man類和Woman類遵守Person協議就可以達到物件導向程式設計中繼承的效果,如果有多個協議要遵守的話就可以通過遵守多個協議來達到物件導向程式設計中的多繼承的效果

  1. Swift 初始化函式及便利構造器(convenience)的簡單理解

Swift的初始化函式有兩種一種是指定初始化函式(Designated Initializers )就是通常的 init函式,一種是便利初始化函式(Convenience Initializers)就是在init函式前加convenience關鍵詞的初始化函式

Swift對初始化有很嚴格的規則要求,我理解如下:

.自己至少要有一個“指定初始化函式”

.便利初始化函式中必須要呼叫自己的指定初始化函式

.如果有父類要在自己的指定初始化函式中呼叫父類的指定初始化函式

例子如下:

建立一個自定義view

class MyView: UIView {

    private var testvar: String?

    //自己的指定初始化函式
    override init(frame: CGRect) {
     
        //父類的指定初始化函式
        super.init(frame: frame)
    }

    //定義一個帶引數的便利初始化函式
    convenience init (param: String){ 
       
       //便利初始化函式中呼叫自己的指定初始化函式
        self.init(frame: CGRect.zero)
        
        //賦值
         testvar = param
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}
複製程式碼

使用如下:

//用便利初始化函式初始化一個myView

 let myView = MyView(param: "傳的引數")
複製程式碼

上面例子中定義了一個帶引數param的便利初始化函式init (param: String),在便利初始化函式中呼叫了自己的指定初始化函式init(frame:CGRect),在自己的指定初始化函式中呼叫了父類的指定初始化函式super.init(frame:frame)。

上面的例子只是簡單的說明了便利建構函式的用法,一般像本例中的初始化可以不用便利建構函式來實現,用指定初始化函式就可以,指定初始化函式實現的例子如下:

 class MyView: UIView {

    private var testvar: String?

    init (param: String){
        super.init(frame: CGRect.zero)
        testvar = param
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
複製程式碼

使用 指定初始化函式初始化myView

  let myView = MyView(param: "傳的引數")
複製程式碼
  1. Swift中的高階函式map,filter,reduce,flatMap的簡單理解

map, filter, reduce,flatMap函式用的是一種函數語言程式設計的思想

map 操作返回的是一個結果陣列(集合),該陣列(集合)中的元素是對操作前的陣列中每個元素進行相同操作後形成的新元素

filter操作返回結果是一個陣列(集合),該陣列(集合)中的元素是操作前陣列中符合篩選條件的元素

reduce操作返回結果是一個值,該值是用初始值和陣列(集合)中的每個元素呼叫相同操作來生成的

flatMap返回的是一個陣列,這個返回的陣列是將多個陣列(集合中)的元素放到一個陣列中形成的新陣列

  1. 在定義變數的時候儘可能的給個初始值,不然會有一大堆的?要處理,例子如下

    class Model: NSObject {
    
        var data: [CellModel] = []
        var title = ""
    }
    
    class CellModel: NSObject {
        var name = ""
        var iconImg = ""
        var productID = ""
    
    }
    複製程式碼

一些基礎的總結,有不對的地方還請留言指正


相關文章