大白话Swift入门教程

17,167 阅读9分钟

一. !?

?表示可选类型,如果申明属性或变量的话就是默认值为nil的意思,


!表示解包,对加!的在使用  前一定要做判nil处理,一般用if letguard let来判断,或者用 if a != nil 来做判断

二. 闭包的使用

1.闭包的表达式:

{(参数)-> 返回值 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)是传过来的参数

2.逃逸闭包:

就是闭包作为函数的参数,但是在函数结束以后才去执行这个参数的就叫逃逸闭包,在参数类型前加@escaping

逃逸闭包的使用例子

private func requestData(success:@escaping (Any) -> Void) {
    
    DispatchQueue.global().async {
    
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3, execute: {
            success("data") //3秒后才执行闭包success
        })
    
    }
    

在这个例子中闭包success作为参数,但是他在函数执行完以后过了一段时间才执行,所以他就是逃逸闭包

三. 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类型的时候就需要做类型匹配

四. 申明函数参数或返回值的时候加?,否则传参数或返回返回值的时候对于可选类型的值要加"!"

五. 写代理模式的时候

     protocol CCDelegate : class {
         func doSomething()
    }

记得在后面加上class关键字,一般加class ,

代理当作变量的时候用weak 修饰防止循环引用

 weak var  delegate: CCDelegate?

六. 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)
    

七. 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

八. .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

从上面的例子可以得到验证

九. Swift Protocol 及面向协议编程(POP)的理解

  1. 协议的一般书写格式

     protocol TestProtocol {
         var testVar: Int { get set}
         func testFunc()
     }
    

Protocol是约定的一种协议,协议中可以有变量,和方法,协议就是一种约定,如果某个对象遵守了该约定就要去实现该约定(协议)的方法和变量(如果遵守了就好比是承诺了就得去实现),协议中方法和变量也可以定义为可选(optional)类型的,如果变量或方法是可选类型的就不需要一定去实现。

  1. 协议中方法和变量为可选的protocol格式如下:

     @objc protocol TestProtocol {
          @objc optional var testVar: Int { get set}  //可选 
          //协议中的变量需要指定 get set
          @objc optional func testFunc() //可选
          func noOptionFunc()  //不可选
    }
    

3.协议的使用

  class TestClas: TestProtocol {

    //实现协议TestProtocol中的方法
    func noOptionFunc() {
    
        print("一定要实现的函数")
    }
    
    //实现协议TestProtocol中的方法
    func testFunc() {
        print("不需要一定实现的函数")
    }

}

4.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即可

5.协议的扩展( 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()

//打印结果如下

//我想上厕所
//我是男的也在跑步
//去女厕所上厕所
//我在跑步

上面例子就是对协议扩展的应用

6.面向协议编程(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协议就可以达到面向对象编程中继承的效果,如果有多个协议要遵守的话就可以通过遵守多个协议来达到面向对象编程中的多继承的效果

十. 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: "传的参数")


十一. Swift中的高阶函数map,filter,reduce,flatMap的简单理解

map, filter, reduce,flatMap函数用的是一种函数式编程的思想

map 操作返回的是一个结果数组(集合),该数组(集合)中的元素是对操作前的数组中每个元素进行相同操作后形成的新元素

filter操作返回结果是一个数组(集合),该数组(集合)中的元素是操作前数组中符合筛选条件的元素

reduce操作返回结果是一个值,该值是用初始值和数组(集合)中的每个元素调用相同操作来生成的

flatMap返回的是一个数组,这个返回的数组是将多个数组(集合中)的元素放到一个数组中形成的新数组

十二. 在定义变量的时候尽可能的给个初始值,不然会有一大堆的?要处理

例子如下

    class Model: NSObject {
  
        var data: [CellModel] = [CellModel]()
        var title = ""
    }

    class CellModel: NSObject {
        var name = ""
        var iconImg = ""
        var productID = ""

    }

十三.元祖(Tuple)

最简单的元组就是在圆括号中,用逗号分割的一组值。例子如下:

   var tuple = (100, "哈哈哈", 222)

元祖中的元素带有名称的元祖例子如下:

 var tuple = (code: 1000, des: "请求失败")

元祖有以下特点:

.元祖一旦声明,就不能再添加/删除其中的元素,但是可以改变元素的值。

.不能更改已经声明的元素名称

元祖的取值

根据声明时元素是否有名称,取值方法分为两种,没有名称的用下标取值,有名称的使用名称取值例子如下:

    var aTuple = (1000,"请求失败") //无名称的
    var bTuple = (code:1000,des: "请求失败") //有名称的
    
    print(aTuple.0)  // 输出结果: 1000
    print(aTuple.1)  // 输出结果: "请求失败"
    
    print(bTuple.code) //输出结果:  1000
    print(bTuple.des)  //输出结果:  "请求失败"

十四. 如果是oc和swift混合编程,那么如果想让swift类中的属性或方法能被oc访问,就需要在属性或方法的前面加 @objc 关键字,例子如下

    @objc  var isLog: Bool = true
    @objc  var dic = Dictionary<String, Any>()
    
    @objc func callRequest(){
        //do something
    }
    
    

十五. Swift中的函数式编程,then的用法


一些基础的总结,有不对的地方还请留言指正