源码阅读笔记之--<Stencil源码阅读>

GitHub链接:https://github.com/stencilproject/Stencil

一、defer

  1. 读到这段有个小疑惑,defer是干啥的
/// Push a new level onto the context for the duration of the execution of the given closure
  public func push<Result>(dictionary: [String: Any] = [:], closure: (() throws -> Result)) rethrows -> Result {
    push(dictionary)
    defer { _ = pop() }
    return try closure()
  }

defer翻译成中文,是"推迟"的意思。
1.在代码块结束之前,或调用return、break之前,会调用这个defer里面的内容
2.简单来说,就是一个代码块,即将结束时候的“遗言”
3.如果有多个defer,那么是从下到上,反着执行

// defer
    func deferTest() {
        defer {
            print("------0------")
        }
        print("-----1-------")
        if true {
            defer {
                print("-----2------")
            }
            print("-------3-------")
        }
        
        print("------4------")
    }
    
    // 1 , 3,  2, 4, 0
//    -----1-------
//    -------3-------
//    -----2------
//    ------4------
//    ------0------
    
    /*
    func loadCityList(_ finish: ((Error?, [String]?) -> ())?) {
        DispatchQueue.global().async { // 模拟网络请求
            let data: AnyObject? // 模拟服务器返回的数据
            guard let dict = data as? [String: AnyObject] else {
                DispatchQueue.main.async {
                    finish?(error, nil)
                }
                return
            }
            guard let code = dict["code"] as? Int, code == 200 else {
                DispatchQueue.main.async {
                    finish?(error, nil)
                }
                return
            }
            guard let citys = dict["data"] as? [String]? else {
                DispatchQueue.main.async {
                    finish?(error, nil)
                }
                return
            }
            DispatchQueue.main.async {
                finish?(nil, citys)
            }
        }
    }

	// 可以改为下面这种写法
    func loadCityList(_ finish: ((Error?, [String]?) -> ())?) {
        DispatchQueue.global().async { // 模拟网络请求
            var error: Error? = nil
            var citys: [String]? = nil
            defer {
                DispatchQueue.main.async {
                    finish?(error, citys)
                }
            }
            
            let data: AnyObject? // 模拟服务器返回的数据
            guard let dict = data as? [String: AnyObject] else {
                error = ...
                return
            }
            guard let code = dict["code"] as? Int, code == 200 else {
                error = ...
                return
            }
            guard let tempCitys = dict["data"] as? [String]? else {
                error = ...
                return
            }
            citys = tempCitys
        }
    }
    使用defer既解决了代码冗余,又解决了可能忘记回调的问题,还有当我们看到defer时,我们很清楚知道,无论网络请求结果如果,都会回调
    */

二、异常抛出的方式

  1. 源码如下
public class TemplateDoesNotExist: Error, CustomStringConvertible {
  let templateNames: [String]
  let loader: Loader?

  public init(templateNames: [String], loader: Loader? = nil) {
    self.templateNames = templateNames
    self.loader = loader
  }

  public var description: String {
    let templates = templateNames.joined(separator: ", ")
      
    if let loader = loader {
      return "Template named `\(templates)` does not exist in loader \(loader)"
    }

    return "Template named `\(templates)` does not exist. No loaders found"
  }
}
  • 笔记如下:
class StencilClass {
    func loadName(name: String) throws -> String {
        let myName = name
        if myName == "张三" {
            return "Success"
        } else {
            throw StencilError(stencilError: name)
        }
    }
}

class StencilError: Error,CustomStringConvertible {
    let myError: String
    
    public init(stencilError: String) {
        self.myError = stencilError
    }
    
    public var description: String { // 遵守这个协议CustomStringConvertible,就要实现这个属性
        return "这次报错 \(myError)"
    }
}
  • 调用
try StencilClass().loadName(name: "张三1")
  • 报错内容

Swift/ErrorType.swift:200: Fatal error: Error raised at top level: 这次报错 张三1
[5613:7424652] Swift/ErrorType.swift:200: Fatal error: Error raised at top level: 这次报错 张三1
(lldb)

ps:这篇文章也可以参考下

三、Equatable

class StreetAddress: Equatable {
    static func == (lhs: StreetAddress, rhs: StreetAddress) -> Bool { // 只要遵守这个Equatable协议,就要实现这个方法
        return
            lhs.street == rhs.street &&
            lhs.number == rhs.number
    }
    
    let number: String
    let street: String
    
    init(_ number: String, _ street: String) {
        self.number = number
        self.street = street
    }
    
}
let a = StreetAddress("0", "1")
let b = StreetAddress("1", "1")
let res = a == b // 打印false

四、高阶函数

推荐博客

func test() {
        // map
        // 1. 读每个元素计算
        var values1 = [1,2,3,4,5]
        values1 = values1.map{$0 + 10}
        print("values1 == ",values1) // [11, 12, 13, 14, 15]
        
        // 2. 对元素字符个数计算
        let strs = ["JiB", "MotuoKe", "NiuBi", "DaHa", "DanDan"]
        let cnts = strs.map({$0.count})
        print("cnts == ", cnts) // cnts ==  [3, 7, 5, 4, 6]
        
        // 3. 变小写
        let lowerStrs = strs.map({$0.lowercased()})
        print("lowerStrs == ", lowerStrs) // lowerStrs ==  ["jib", "motuoke", "niubi", "daha", "dandan"]
        
        
        // flatMap : 降维(3维降2维,2维降1维),不存在nil, 自动解包
        // compactMap : 可选值自动解包
        let values = [[1,2,3],[4,5,6],[7,8,9]]
        let res = values.compactMap { e in
            return e
        }
        print(res) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
        
        let res1 = values.compactMap({$0})
        print(res1) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
        
        let res2 = values.flatMap({$0}) // 二维降一维
        print(res2) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
        
        let array = ["1", "two", "3", "4", "five", "6"]
        let maps: [Int?] = array.map({Int($0)}) // 可选的
        print("maps == ",maps)  // maps ==  [Optional(1), nil, Optional(3), Optional(4), nil, Optional(6)]
        
        let compactMaps = array.compactMap({Int($0)}) // 自动解包
        print("compactMaps == ",compactMaps) // compactMaps ==  [1, 3, 4, 6]
        
        let values3 = [[[1,2,3],[1,2,3],[1,2,3]],[[1,2,3],[1,2,3],[1,2,3]],[[1,2,3],[1,2,3],[1,2,3]]]
        let res3 = values3.flatMap({$0}) // 三维降二维
        print("res3 == ", res3) // res3 ==  [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
        
        // filter: 条件过滤函数
        var values2 = [6, 7, 8, 9]
        values2 = values2.filter{$0 > 7}
        print("values2 == ", values2) // [8, 9]
        
        // reduce: 叠加递增器函数
        // 1. 拼接元素
        let arr = ["love","you", "so", "much"]
        let resArr = arr.reduce("I") { (partialResult, curStr) -> String in
            return partialResult + " " + curStr
        }
        print("resArr == ", resArr) // resArr ==  I love you so much
        // 2. 计算元素字符个数
        let coutArr = arr.reduce(0) { (partialResult, curStr) -> Int in
            return partialResult + curStr.count
        }
        print("count == ",coutArr) // count ==  13
        
        // 3. 计算字符串中相同字符,通过字典
        let letters = "avbracdgbbcc"
        let letterDict = letters.reduce(into: [:]) { partialResult, char in
            partialResult[char, default: 0] += 1
        }
        print("letterDict == ", letterDict) // letterDict ==  ["v": 1, "c": 3, "d": 1, "b": 3, "a": 2, "r": 1, "g": 1]
        
        // 4. 计算二维数组的总和,map配合reduce使用
        let arrays1 = [[5,2,7],[4,8],[9,1,3]]
        let sums = arrays1.map({$0.reduce(0, +)})
        // 等价于
        let sums1 = arrays1.map({$0.reduce(0) { (partialResult, ele) -> Int in
            return partialResult + ele
        }})
        
        print("sums == ", sums, "\n" , "sums1 == ", sums1) // sums ==  [14, 12, 13]
        // sums1 ==  [14, 12, 13]
    }

五、三引号和反斜杠的细节

看到下面的代码,有点眼生:

let highlight = """
        \(String(Array(repeating: " ", count: location.lineOffset)))\
        ^\(String(Array(repeating: "~", count: max(token.contents.count - 1, 0))))
        """

因为平时用到比较少,就记录一下。

let highlight = """
  张三
 \(String(Array(repeating: "a", count: 4)))
 ^
 ---
 是\
 \(String(Array(repeating: "~", count: 4)))\
 帅哥
 """

打印内容:

 张三
aaaa
^
---
是~~~~帅哥
  1. 三引号,里面内容会自动换行,不用额外加\n
  2. 在每一行最后面加一个\ 是可以与下面一行内容连接在一行

六、final关键字使用

详情参考这篇文章,写的挺好的
我在大概总结几句,一般场景用于工具类或方法里面

  1. 权限控制,就是说,写在class前面,不想这个class被别人继承。
  2. 写在func前面,当这个func的类被继承后,这个func是不能被重写的。

七、class func 和 static func

  1. 都是表示静态方法
  2. static func 不能被继承,等价于 class final func (CFF,联想到CF游戏, 这样记忆,保证顺序)

八、zip函数,不是压缩文件,而是swift的接口

这篇文章不错

let a = [1, 2, 3, 4, 5]
let b = ["a", "b", "c", "d"]

let c = zip(a, b).map {$0}
print("c ->", c) // c -> [(1, "a"), (2, "b"), (3, "c"), (4, "d")]
let d = zip(1..., b).map {$0}
print("d ->", d) // d -> [(1, "a"), (2, "b"), (3, "c"), (4, "d")]


let dict = Dictionary(uniqueKeysWithValues: zip(a, b))
print("dict ->", dict) // dict -> [3: "c", 4: "d", 2: "b", 1: "a"]
let array = ["Apple", "Pear", "Pear", "Orange"]
let dict1 = Dictionary(zip(array, repeatElement(1, count: array.count)), uniquingKeysWith: +)
print("dict1 ->", dict1) // dict1 -> ["Apple": 1, "Orange": 1, "Pear": 2]


let a1 = ["a", "b", "c", "d"]
let b1 = ["A", "B", "C", "D"]
let c1 = [a1,b1].flatMap({$0}) // 分批合并
print("c1 ->", c1) // c1 -> ["a", "b", "c", "d", "A", "B", "C", "D"]
let c2 = zip(a1, b1).flatMap({ [$0, $1]}) // 交替合并
print("c2 ->", c2) // c2 -> ["a", "A", "b", "B", "c", "C", "d", "D"]
  • zip的骚气用法
override func viewDidLoad() {
        super.viewDidLoad()
        
        let titles = ["按钮1", "按钮2", "按钮3"]
        let colors = [UIColor.red, UIColor.blue, UIColor.orange]
         
        let buttons = zip(0..., titles).map { (i, title) -> UIButton in
            let button = UIButton(type: .system)
            button.frame = CGRect(x: i * 100, y: 200, width: 80, height: 80)
            button.setTitle(title, for:.normal)
            button.tag = i
            self.view.addSubview(button)
            return button
        }
        
//        zip(buttons, colors).forEach { (btn, color) in
//            btn.backgroundColor = color
//        } // 简化如下写法:
        
        zip(buttons, colors).forEach({
            $0.0.backgroundColor = $0.1
        })
    }

http://www.javashuo.com/article/p-sihljwtz-nk.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值