GithubHelp home page GithubHelp logo

ming1016 / swiftpamphletapp Goto Github PK

View Code? Open in Web Editor NEW
2.2K 33.0 362.0 2.52 MB

戴铭的开发小册子,一本活的开发手册。使用 SwiftUI + SwiftData + Swift Concurrency Aysnc/Await Actor + GitHub API 开发的 macOS 应用

License: MIT License

Swift 60.11% Shell 0.15% HTML 39.72% C 0.02%
swift github github-api swiftui combine concurrency

swiftpamphletapp's Introduction

戴铭的开发小册子 5.0

Swift开发的手册,是个 macOS 程序。在线文字版

下载

直接下载最新 dmg 使用:戴铭的开发小册子5.0.dmg.zip

编译

自己编译生成程序的方法是:

方式一:本地编译

  • 拉代码。直接编译生成无 Github 功能的手册程序。
  • 如要带 Github 功能可在 SwiftPamphletAppConfig.swift 里 gitHubAccessToken 加入你的 GitHub Access Token。GitHub Access Token 在 Personal Access Tokens 这里获取。记得scope 勾上 repo 和 user。
  • 使用Xcode编译生成这个手册程序或是连点两下compile.command。

Xcode 和 macOS 都需要升到最新版。如果遇到 swift package 下载不下来的情况,参看这个议题来解决:Issue #88

方式二:云编译

无需 Xcode 设置开发人员帐号编译

  • 可使用 compile.command 编译手册程序,无需开启 Xcode 设置个人开发帐号,只需在 SwiftPamphletAppConfig.swift 里 gitHubAccessToken 加入你的 GitHub Access Token,完成后连点 compile.command 两下等待作业完成。
  • 或使用 Github action workflow 编译(感谢@powenn),无需在本地操作、也无需开启 Xcode 设置个人开发帐号,只需设置 personal access token(PAT) 在 repository 设定中 action secrets,并命名为 PAT。Fork 此 repository,设置 PAT,手动启用 action,等候约3分钟即可下载档案,往后专案更新时,只需 fetch and merge,action 会自动进行。

英文说明: Requires storaging PAT to actions secrets and name it to PAT

  • Fork this repository.
  • Go to get a Personal Access Token(PAT) if you haven't done it yet.(GitHub Access Token in Personal Access Tokens,scope checked repo and user)
  • Set your token in action secrets ,and name it to PAT.
  • Get the compiled app package after Github action complete.

While project update ,you won't need to compile it manually in local, only need to fetch and merge commits and wait for about 3 minutes then download it

介绍

小册子能够方便的查看 Swift 语法,还有一些主要库的使用指南,内容还在完善中,选择的库主要就是开发小册子应用使用到的 SwitUI、Combine、Swift Concurrency

除了这些速查和库的使用内容外,这个应用还有一些开发者的动态,当他们有新的动作,比如提交了代码、star 了什么项目,提交和留言了议题都会直接在程序坞中提醒你。

我对一些库做了分类,方便按需查找,库有新的提交也会在程序坞中提醒。

还能方便的查看库的议题。比如在阮一峰的《科技爱好者周刊》的议题中可以看到有很多人推荐和自荐了一些信息。保留议题有一千六百多个。

博客动态的功能,可以跟进一些博客内容的更新。

代码说明参看这篇《如何用 SwiftUI + Combine + Swift Concurrency Aysnc/Await Actor 欢畅开发》文章

小册子文字版 《戴铭的 Swift 小册子

swiftpamphletapp's People

Contributors

cczallen avatar chenxiaoqiang03 avatar feuvan avatar kam-to avatar ming1016 avatar powenn avatar sinterchen avatar wtracyliu avatar xugj-gits avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftpamphletapp's Issues

类可以定义属性、方法、构造器、下标操作。类使用扩展来扩展功能,遵循协议。类还以继承,运行时检查实例类型。

 class C {
     var p: String
     init(_ p: String) {
         self.p = p
     }
     
     // 下标操作
     subscript(s: String) -> String {
         get {
             return p + s
         }
         set {
             p = s + newValue
         }
     }
 }
 
 let c = C("hi")
 print(c.p)
 print(c[" ming"])
 c["k"] = "v"
 print(c.p)

遍历 For-in

let a = ["one", "two", "three"]
for str in a {
    print(str)
}

// 使用下标范围
for i in 0..<10 {
    print(i)
}

// 使用 enumerated
for (i, str) in a.enumerated() {
    print("\(i + 1)个是:\(str)")
}

// for in where
for str in a where str.prefix(1) == "t" {
    print(str)
}

// 字典 for in,遍历是无序的
let dic = [
    "one": 1,
    "two": 2,
    "three": 3
]

for (k, v) in dic {
    print("key is \(k), value is \(v)")
}

// stride
for i in stride(from: 10, through: 0, by: -2) {
    print(i)
}
/*
 10
 8
 6
 4
 2
 0
 */

属性

类、结构体或枚举里的变量常量就是他们的属性。

struct S {
    static let sp = "类型属性" // 类型属性通过类型本身访问,非实例访问
    var p1: String = ""
    var p2: Int = 1
    // cp 是计算属性
    var cp: Int {
        get {
            return p2 * 2
        }
        set {
            p2 = newValue + 2
        }
    }
    // 只有 getter 的是只读计算属性
    var rcp: Int {
        p2 * 4
    }
}
print(S.sp)
print(S().cp) // 2
var s = S()
s.cp = 3
print(s.p2) // 5
print(S().rcp) // 4

willSet 和 didSet 是属性观察器,可以在属性值设置前后插入自己的逻辑处理。

不透明类型

不透明类型会隐藏类型,让使用者更关注功能。不透明类型和协议很类似,不同的是不透明比协议限定的要多,协议能够对应更多类型。

protocol P {
    func f() -> String
}
struct S1: P {
    func f() -> String {
        return "one\n"
    }
}
struct S2<T: P>: P {
    var p: T
    func f() -> String {
        return p.f() + "two\n"
    }
}
struct S3<T1: P, T2: P>: P {
    var p1: T1
    var p2: T2
    func f() -> String {
        return p1.f() + p2.f() + "three\n"
    }
}
func someP() -> some P {
    return S3(p1: S1(), p2: S2(p: S1()))
}

let r = someP()
print(r.f())

元组 (a, b, c)

元组里的值类型可以是不同的。元组可以看成是匿名的结构体。

let t1 = (p1: 1, p2: "two", p3: [1,2,3])
print(t1.p1)
print(t1.p3)

// 类型推导
let t2 = (1, "two", [1,2,3])

// 通过下标访问
print(t2.1) // two

// 分解元组
let (dp1, dp2, _) = t2
print(dp1)
print(dp2)

类型转换

使用 is 关键字进行类型判断, 使用as 关键字来转换成子类。

class S0 {}
class S1: S0 {}
class S2: S0 {}

var a = [S0]()
a.append(S1())
a.append(S2())
for e in a {
    // 类型判断
    if e is S1 {
        print("Type is S1")
    } else if e is S2 {
        print("Type is S2")
    }
    // 使用 as 关键字转换成子类
    if let s1 = e as? S1 {
        print("As S1 \(s1)")
    } else if let s2 = e as? S2 {
        print("As S2 \(s2)")
    }
}

比较运算符 ==, >

遵循 Equatable 协议可以使用 == 和 != 来判断是否相等

print(1 > 2) // false

struct S: Equatable {
    var p1: String
    var p2: Int
}
let s1 = S(p1: "one", p2: 1)
let s2 = S(p1: "two", p2: 2)
let s3 = S(p1: "one", p2: 2)
let s4 = S(p1: "one", p2: 1)

print(s1 == s2) // false
print(s1 == s3) // false
print(s1 == s4) // true

类需要实现 == 函数

class C: Equatable {
    var p1: String
    var p2: Int
    init(p1: String, p2: Int) {
        self.p1 = p1
        self.p2 = p2
    }
    
    static func == (l: C, r: C) -> Bool {
        return l.p1 == r.p1 && l.p2 == r.p2
    }
}

let c1 = C(p1: "one", p2: 1)
let c2 = C(p1: "one", p2: 1)
print(c1 == c2)

数组 [1, 2, 3]

数组是有序集合

var a0: [Int] = [1, 10]
a0.append(2)
a0.remove(at: 0)
print(a0) // [10, 2]

let a1 = ["one", "two", "three"]
let a2 = ["three", "four"]

// 找两个集合的不同
let dif = a1.difference(from: a2) // swift的 diffing 算法在这 http://www.xmailserver.org/diff2.pdf swift实现在  swift/stdlib/public/core/Diffing.swift
for c in dif {
    switch c {
    case .remove(let o, let e, let a):
        print("offset:\(o), element:\(e), associatedWith:\(String(describing: a))")
    case .insert(let o, let e, let a):
        print("offset:\(o), element:\(e), associatedWith:\(String(describing: a))")
    }
}
/*
 remove offset:1, element:four, associatedWith:nil
 insert offset:0, element:one, associatedWith:nil
 insert offset:1, element:two, associatedWith:nil
 */
let a3 = a2.applying(dif) ?? [] // 可以用于添加删除动画
print(a3) // ["one", "two", "three"]

从数组中随机取一个元素

extension Array {
  public var randomElement: Element? {
    guard count > 0 else {
      return nil
    }
    let index = Int(arc4random_uniform(UInt32(count)))
    return self[index]
  }
}

数组排序

// 排序
struct S1 {
    let n: Int
    var b = true
}

let a4 = [
    S1(n: 1),
    S1(n: 10),
    S1(n: 3),
    S1(n: 2)
]
let a5 = a4.sorted { i1, i2 in
    i1.n < i2.n
}
for n in a5 {
    print(n)
}
/// S1(n: 1)
/// S1(n: 2)
/// S1(n: 3)
/// S1(n: 10)

let a6 = [1,10,4,7,2]
print(a6.sorted(by: >)) // [10, 7, 4, 2, 1]

可以加到数组扩展中,通过扩展约束能够指定特定元素类型的排序,代码如下:

extension Array where Element == Int {
    // 升序
    func intSortedASC() -> [Int] {
        return self.sorted(by: <)
    }
    // 降序
    func intSortedDESC() -> [Int] {
        return self.sorted(by: <)
    }
}

print(a6.intSortedASC()) // 使用扩展增加自定义排序能力

在数组中检索满足条件的元素,代码如下:

// 第一个满足条件了就返回
let a7 = a4.first {
    $0.n == 10
}
print(a7?.n ?? 0)

// 是否都满足了条件
print(a4.allSatisfy { $0.n == 1 }) // false
print(a4.allSatisfy(\.b)) // true

// 找出最大的那个
print(a4.max(by: { e1, e2 in
    e1.n < e2.n
}) ?? S1(n: 0))
// S1(n: 10, b: true)

// 看看是否包含某个元素
print(a4.contains(where: {
    $0.n == 7
}))
// false

一些切割数组的方法。

// 切片
// 取前3个,并不是直接复制,对于大的数组有性能优势。
print(a6[..<3]) // [1, 10, 4] 需要做越界检查
print(a6.prefix(30)) // [1, 10, 4, 7, 2] 不需要做越界检查,也是切片,性能一样

// 去掉前3个
print(a6.dropFirst(3)) // [7, 2]

prefix(while:) 和 drop(while:) 方法,顺序遍历执行闭包里的逻辑判断,满足条件就返回,遇到不匹配就会停止遍历。prefix 返回满足条件的元素集合,drop 返回停止遍历之后那些元素集合。

let a8 = [8, 9, 20, 1, 35, 3]
let a9 = a8.prefix {
    $0 < 30
}
print(a9) // [8, 9, 20, 1]
let a10 = a8.drop {
    $0 < 30
}
print(a10) // [35, 3]

可选 ?, !

可能会是 nil 的变量就是可选变量。当变量为 nil 通过??操作符可以提供一个默认值。

var o: Int? = nil
let i = o ?? 0

函数 func

函数可以作为另一个函数的参数,也可以作为另一个函数的返回。函数是特殊的闭包,在类、结构体和枚举中是方法。

// 为参数设置默认值
func f1(p: String = "p") -> String {
    "p is \(p)"
}

// 函数作为参数
func f2(fn: (String) -> String, p: String) -> String {
    return fn(p)
}

print(f2(fn:f1, p: "d")) // p is d

// 函数作为返回值
func f3(p: String) -> (String) -> String {
	return f1
}

print(f3(p: "yes")("no")) // p is no

函数可以返回多个值,函数是可以嵌套的,也就是函数里内可以定义函数,函数内定义的函数可以访问自己作用域外函数内的变量。inout 表示的是输入输出参数,函数可以在函数内改变输入输出参数。defer 标识的代码块会在函数返回之前执行。

reduce

reduce 可以将迭代中返回的结果用于下个迭代中,并,还能让你设个初始值。

let a1 = ["a", "b", "c", "call my name.", "get it?"]
let a2 = a1.reduce("Hey u,", { partialResult, s in
    // partialResult 是前面返回的值,s 是遍历到当前的值
    partialResult + " \(s)"
})

print(a2) // Hey u, a b c call my name. get it?

字典 [:]

字典是无序集合,键值对应。

var d1 = [
    "k1": "v1",
    "k2": "v2"
]
d1["k3"] = "v3"
d1["k4"] = nil

print(d1) // ["k2": "v2", "k3": "v3", "k1": "v1"]

for (k, v) in d1 {
    print("key is \(k), value is \(v)")
}
/*
 key is k1, value is v1
 key is k2, value is v2
 key is k3, value is v3
 */
 
if d1.isEmpty == false {
    print(d1.count) // 3
}

// mapValues
let d2 = d1.mapValues {
    $0 + "_new"
}
print(d2) // ["k2": "v2_new", "k3": "v3_new", "k1": "v1_new"]

// 对字典的值或键进行分组
let d3 = Dictionary(grouping: d1.values) {
    $0.count
}
print(d3) // [2: ["v1", "v2", "v3"]]

// 从字典中取值,如果键对应无值,则使用通过 default 指定的默认值
d1["k5", default: "whatever"] += "."
print(d1["k5"] ?? "") // whatever.
let v1 = d1["k3", default: "whatever"]
print(v1) // v3

数字 Int, Float

数字的类型有 Int、Float 和 Double

// Int
let i1 = 100
let i2 = 22
print(i1 / i2) // 向下取整得 4

// Float
let f1: Float = 100.0
let f2: Float = 22.0
print(f1 / f2) // 4.5454545

// Double
let d1: Double = 100.0
let d2: Double = 22.0
print(d1 / d2) // 4.545454545454546

// 字面量
print(Int(0b10101)) // 0b 开头是二进制 
print(Int(0x00afff)) // 0x 开头是十六进制
print(2.5e4) // 2.5x10^4 十进制用 e
print(0xAp2) // 10*2^2  十六进制用 p
print(2_000_000) // 2000000

处理数字有 floor、ceil、round。floor 是向下取整,只取整数部分;cell 是向上取整,只要有不为零的小数,整数就加1;round 是四舍五入。

方法

enum E: String {
    case one, two, three
    func showRawValue() {
        print(rawValue)
    }
}

let e = E.three
e.showRawValue() // three

// 可变的实例方法,使用 mutating 标记
struct S {
    var p: String
    mutating func addFullStopForP() {
        p += "."
    }
}
var s = S(p: "hi")
s.addFullStopForP()
print(s.p)

// 类方法
class C {
    class func cf() {
        print("类方法")
    }
}

static和class关键字修饰的方法类似 OC 的类方法。static 可以修饰存储属性,而 class 不能;class 修饰的方法可以继承,而 static 不能。在协议中需用 static 来修饰。

闭包

闭包也可以叫做 lambda,是匿名函数,对应 OC 的 block。

let a1 = [1,3,2].sorted(by: { (l: Int, r: Int) -> Bool in
    return l < r
})
// 如果闭包是唯一的参数并在表达式最后可以使用结尾闭包语法,写法简化为
let a2 = [1,3,2].sorted { (l: Int, r: Int) -> Bool in
	return l < r
}
// 已知类型可以省略
let a3 = [1,3,2].sorted { l, r in
	return l < r
}
// 通过位置来使用闭包的参数,最后简化如下:
let a4 = [1,3,2].sorted { $0 < $1 }

函数也是闭包的一种,函数的参数也可以是闭包。@escaping 表示逃逸闭包,逃逸闭包是可以在函数返回之后继续调用的。@autoclosure 表示自动闭包,可以用来省略花括号。

小册子动态

动态

欢迎你的内容分享和留言,请发到 议题里,也欢迎你的 PR :) 。

  • 22.01.03 发布2.0:新动态支持提醒,包括博客RSS、开发者、好库和探索库
  • 21.11.16 发布1.0:Swift 指南语法速查完成

资源

Done

  • 开发者动态、仓库动态、议题列表、议题页、语法速查
  • 网络请求重试、网络异常处理
  • 开发者和仓库动态更新提醒(本地对比判断更新)
  • 完善开发者事件不同类型的区分处理

Todo

  • 特性内容、专题内容、SwiftUI 和 Combine 内容完善
  • 离线版
  • 一键提醒全部已读
  • 小册子汇报自动生成

当前在用开发工具速链

规范

参考:

多用静态特性。swift 在编译期间所做的优化比 OC 要多,这是由于他的静态派发、泛型特化、写时复制这些静态特性决定的。另外通过 final 和 private 这样的表示可将动态特性转化为静态方式,编译开启 WMO 可以自动推导出哪些动态派发可转化为静态派发。

如何避免崩溃?

  • 字典:用结构体替代
  • Any:可用泛型或关联关联类型替代
  • as? :少用 AnyObject,多用泛型或不透明类型
  • !:要少用

好的实践?

  • 少用继承,多用 protocol
  • 多用 extension 对自己代码进行管理

单例

struct S {
    static let shared = S()
    private init() {
        // 防止实例初始化
    }
}

数据-特性

WwogICAgewogICAgICAgICJuYW1lIjoi5Z+656GA5bqTIiwKICAgICAgICAiaWQiOjIyMDEyMDEwMTIsCiAgICAgICAgImlzc3VlcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIyMDEyMDEwMTIsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLml7bpl7QiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTIwCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjIwMTIwMTAxNywKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuagvOW8j+WMliIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxMjEKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMjAxMjAxMDE4LAogICAgICAgICAgICAgICAgInRpdGxlIjoi5bqm6YeP5YC8IiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjEyMgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIyMDEyMDEwMTksCiAgICAgICAgICAgICAgICAidGl0bGUiOiJEYXRhIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjEyMwogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIyMDEyMDEwMjAsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLmlofku7YiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTI0CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjIwMTIwMTAyMSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IlNjYW5uZXIiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTI1CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjIwMTIwMTAyMiwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IkF0dHJpYnV0ZVN0cmluZyIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxMjYKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMjAxMjAxMDIzLAogICAgICAgICAgICAgICAgInRpdGxlIjoi6ZqP5py6IiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjEyNwogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIyMDEyMDE5MTEsCiAgICAgICAgICAgICAgICAidGl0bGUiOiJVc2VyRGVmYXVsdHMiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTI4CiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi5qih5byPIiwKICAgICAgICAiaWQiOjIxMTEyMzEzNDAsCiAgICAgICAgImlzc3VlcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMzEzNDIsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLljZXkvosiLAogICAgICAgICAgICAgICAgIm51bWJlciI6NDgKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLns7vnu58iLAogICAgICAgICJpZCI6MjExMTIzMTM0MSwKICAgICAgICAiaXNzdWVzIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMjEwMTA1NSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6Iuezu+e7n+WIpOaWrSIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxMDYKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjMxMzQ0LAogICAgICAgICAgICAgICAgInRpdGxlIjoi54mI5pys5YW85a65IiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjQ5CiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoiQ29kYWJsZSIsCiAgICAgICAgImlkIjoyMTExMjMxNDEzLAogICAgICAgICJpc3N1ZXMiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjMxNDE0LAogICAgICAgICAgICAgICAgInRpdGxlIjoiSlNPTiDmsqHmnIkgaWQg5a2X5q61IiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjUzCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi572R57ucIiwKICAgICAgICAiaWQiOjIxMTEyNjE4NDUsCiAgICAgICAgImlzc3VlcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyNjE4NDYsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLnvZHnu5znirbmgIHmo4Dmn6UiLAogICAgICAgICAgICAgICAgIm51bWJlciI6ODkKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLliqjnlLsiLAogICAgICAgICJpZCI6MjExMjAyMTUxOSwKICAgICAgICAiaXNzdWVzIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMjAyMTUyMCwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuW4g+WxgOWKqOeUuyIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjo5MwogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuWuieWFqCIsCiAgICAgICAgImlkIjoyMjAxMjAxOTE0LAogICAgICAgICJpc3N1ZXMiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMjAxMjAxOTEyLAogICAgICAgICAgICAgICAgInRpdGxlIjoiS2V5Y2hhaW4iLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTI5CiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi5bel56iLIiwKICAgICAgICAiaWQiOjIyMDEyMDE5MTUsCiAgICAgICAgImlzc3VlcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIyMDEyMDE5MTMsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLnqIvluo/lhaXlj6PngrkiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTMwCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9Cl0K

数据-仓库动态

WwogICAgewogICAgICAgICJuYW1lIjoi5a6Y5pa5IiwKICAgICAgICAiaWQiOjIxMTExMTE5NDgsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6ImFwcGxlL3N3aWZ0IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJhcHBsZS9zd2lmdC1ldm9sdXRpb24iLAogICAgICAgICAgICAgICAgImRlcyI6IuaPkOahiCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoibGx2bS9sbHZtLXByb2plY3QiLAogICAgICAgICAgICAgICAgImRlcyI6Iue8luivkeWZqCIKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLmlrDpspzkuosiLAogICAgICAgICJpZCI6MjExMTEyMTU0NywKICAgICAgICAicmVwb3MiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiU3dpZnRPbGREcml2ZXIvaU9TLVdlZWtseSIsCiAgICAgICAgICAgICAgICAiZGVzIjoi6ICB5Y+45py6IGlPUyDlkajmiqUiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Im1hdHRlb2NyaXBwYS9hd2Vzb21lLXN3aWZ0IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJLd2FpQXBwVGVhbS9Td2lmdFBhbXBobGV0QXBwIiwKICAgICAgICAgICAgICAgICJkZXMiOiLmiLTpk63nmoQgU3dpZnQg5bCP5YaM5a2QIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuWwgeijheaYk+eUqOWKn+iDvSIsCiAgICAgICAgImlkIjoyMTExMjMxMTM3LAogICAgICAgICJyZXBvcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJTd2lmdGVyU3dpZnQvU3dpZnRlclN3aWZ0IiwKICAgICAgICAgICAgICAgICJkZXMiOiJIYW5keSBTd2lmdCBleHRlbnNpb25zIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6Iue9kee7nCIsCiAgICAgICAgImlkIjoyMTExMTIxMDUzLAogICAgICAgICJyZXBvcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJBbGFtb2ZpcmUvQWxhbW9maXJlIgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJzb2NrZXRpby9zb2NrZXQuaW8tY2xpZW50LXN3aWZ0IgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuWbvueJhyIsCiAgICAgICAgImlkIjoyMTExMTIyMDEwLAogICAgICAgICJyZXBvcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJvbmV2Y2F0L0tpbmdmaXNoZXIiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6ImtlYW4vTnVrZSIKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLmloflrZflpITnkIYiLAogICAgICAgICJpZCI6MjExMTE3MTk1OCwKICAgICAgICAicmVwb3MiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiZ29uemFsZXpyZWFsL01hcmtkb3duVUkiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi5Yqo55S7IiwKICAgICAgICAiaWQiOjIxMTExMTE5NDYsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6InJlY2hlcnN0L2thdnNvZnQtc3dpZnR1aS1hbmltYXRpb25zIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuaMgeS5heWMluWtmOWCqCIsCiAgICAgICAgImlkIjoyMTExMjMxMzA4LAogICAgICAgICJyZXBvcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJzdGVwaGVuY2VsaXMvU1FMaXRlLnN3aWZ0IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJncm91ZS9HUkRCLnN3aWZ0IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJyZWFsbS9yZWFsbS1jb2NvYSIKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLnvJbnqIvojIPlvI8iLAogICAgICAgICJpZCI6MjExMTIzMTEyMCwKICAgICAgICAicmVwb3MiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiUmVhY3RpdmVYL1J4U3dpZnQiLAogICAgICAgICAgICAgICAgImRlcyI6IuWHveaVsOWTjeW6lOW8j+e8lueoiyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoicG9pbnRmcmVlY28vc3dpZnQtY29tcG9zYWJsZS1hcmNoaXRlY3R1cmUiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Im9ubXl3YXkxMzMvYXdlc29tZS1pb3MtYXJjaGl0ZWN0dXJlIgogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLot6/nlLEiLAogICAgICAgICJpZCI6MjExMTE3MTQwOCwKICAgICAgICAicmVwb3MiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoicG9pbnRmcmVlY28vc3dpZnR1aS1uYXZpZ2F0aW9uIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IumdmeaAgeajgOafpSIsCiAgICAgICAgImlkIjoyMTExMjMxMTE3LAogICAgICAgICJyZXBvcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJyZWFsbS9Td2lmdExpbnQiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi57O757uf6IO95YqbIiwKICAgICAgICAiaWQiOjIxMTEyMzExMjIsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Imtpc2hpa2F3YWthdHN1bWkvS2V5Y2hhaW5BY2Nlc3MiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi5o6l5Y+jIiwKICAgICAgICAiaWQiOjIxMTEyMTIxMzMsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Ik9BdXRoU3dpZnQvT0F1dGhTd2lmdCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoicDIvT0F1dGgyIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6Im1hY09T56iL5bqPIiwKICAgICAgICAiaWQiOjIxMTExMjEwNDYsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6InNlcmhpaS1sb25kYXIvb3Blbi1zb3VyY2UtbWFjLW9zLWFwcHMiLAogICAgICAgICAgICAgICAgImRlcyI6IuW8gOa6kCBtYWNPUyDnqIvluo/lkIjpm4YiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6IlJhbmNoZXJvLVNvZnR3YXJlL05ldE5ld3NXaXJlIgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJvdmVydGFrZS9UZWxlZ3JhbVN3aWZ0IgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuaAp+iDveWSjOW3peeoi+aehOW7uiIsCiAgICAgICAgImlkIjoyMTEyMjQxNzUwLAogICAgICAgICJyZXBvcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJ0dWlzdC90dWlzdCIsCiAgICAgICAgICAgICAgICAiZGVzIjoi5Yib5bu65ZKM57u05oqkIFhjb2RlIHByb2plY3RzIOaWh+S7tiIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoic3dpZnQtc2VydmVyL3ZzY29kZS1zd2lmdCIsCiAgICAgICAgICAgICAgICAiZGVzIjoiVlNDb2RlIOeahCBTd2lmdCDmianlsZUiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi5Zu+5b2iIiwKICAgICAgICAiaWQiOjIyMDEwNTE4MzYsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6IndpbGxkYWxlL1N3aWZ0VUlDaGFydHMiLAogICAgICAgICAgICAgICAgImRlcyI6IueUqOS6jlN3aWZ0VUnnmoTlm77ooajnu5jlm77lupMiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi6Z+z6KeG6aKRIiwKICAgICAgICAiaWQiOjIxMTEyNDEyMDgsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6ImlpbmEvaWluYSIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoic2hvZ280NDA1L0hhaXNoaW5LaXQuc3dpZnQiLAogICAgICAgICAgICAgICAgImRlcyI6IlJUTVAsIEhMUyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiQXVkaW9LaXQvQXVkaW9LaXQiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi5pyN5Yqh5ZmoIiwKICAgICAgICAiaWQiOjIxMTIwNzE4MjYsCiAgICAgICAgInJlcG9zIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6InZhcG9yL3ZhcG9yIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuW+heWIhuexuyIsCiAgICAgICAgImlkIjoyMTExMTIyMzEwLAogICAgICAgICJyZXBvcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJTd2lmdEdHVGVhbS90aGUtc3dpZnQtcHJvZ3JhbW1pbmctbGFuZ3VhZ2UtaW4tY2hpbmVzZSIsCiAgICAgICAgICAgICAgICAiZGVzIjoi5Lit5paH54mIIEFwcGxlIOWumOaWuSBTd2lmdCDmlZnnqIsiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9Cl0K

Guard guard, guard let

更好地处理异常情况

// guard
func f1(p: String) -> String {
    guard p.isEmpty != true else {
        return "Empty string."
    }
    return "String \(p) is not empty."
}

print(f1(p: "")) // Empty string.
print(f1(p: "lemon")) // String lemon is not empty.

// guard let
func f2(p1: String?) -> String {
    guard let p2 = p1 else {
        return "Nil."
    }
    return "String \(p2) is not nil."
}

print(f2(p1: nil)) // Nil.
print(f2(p1: "lemon")) // String lemon is not nil.

版本兼容

// 版本
@available(iOS 15, *)
func f() {

}

// 版本检查
if #available(iOS 15, macOS 12, *) {
    f()
} else {
    // nothing happen
}

变量 let, var

变量是可变的,使用 var 修饰,常量是不可变的,使用 let 修饰。类、结构体和枚举里的变量是属性。

var v1:String = "hi" // 标注类型
var v2 = "类型推导"
let l1 = "标题" // 常量

class a {
	let p1 = 3
	var p2: Int {
		p1 * 3
	}
}

属性没有 set 可以省略 get,如果有 set 需加 get。变量设置前通过 willSet 访问到,变量设置后通过 didSet 访问。

map

map 可以依次处理数组中元素,并返回一个处理后的新数组。

let a1 = ["a", "b", "c"]
let a2 = a1.map {
    "\($0)2"
}
print(a2) // ["a2", "b2", "c2"]

使用 compactMap 可以过滤 nil 的元素。flatMap 会将多个数组合成一个数组返回。

访问控制

在 Xcode 里的 target 就是模块,使用 import 可导入模块。模块内包含源文件,每个源文件里可以有多个类、结构体、枚举和函数等多种类型。访问级别可以通过一些关键字描述,分为如下几种:

  • open:在模块外可以调用和继承。
  • public:在模块外可调用不可继承,open 只适用类和类成员。
  • internal:默认级别,模块内可跨源文件调用,模块外不可调用。
  • fileprivate:只能在源文件内访问。
  • private:只能在所在的作用域内访问。

重写继承类的成员,可以设置成员比父类的这个成员更高的访问级别。Setter 的级别可以低于对应的 Getter 的级别,比如设置 Setter 访问级别为 private,可以在属性使用 private(set) 来修饰。

While while, repeat-while

// while
var i1 = 10
while i1 > 0 {
    print("positive even number \(i1)")
    i1 -= 2
}

// repeat while
var i2 = 10
repeat {
    print("positive even number \(i2)")
    i2 -= 2
} while i2 > 0

使用 break 结束遍历,使用 continue 跳过当前作用域,继续下个循环

打印 print("")

控制台打印值

print("hi")
let i = 14
print(i)
print("9月\(i)是小柠檬的生日")

三元 _ ? _ : _

简化 if else 写法

// if else
func f1(p: Int) {
    if p > 0 {
        print("positive number")
    } else {
        print("negative number")
    }
}

// 三元
func f2(p: Int) {
    p > 0 ? print("positive number") : print("negative number")
}

f1(p: 1)
f2(p: 1)

filter

根据指定条件返回

let a1 = ["a", "b", "c", "call my name"]
let a2 = a1.filter {
    $0.prefix(1) == "c"
}
print(a2) // ["c", "call my name"]

赋值 =, +=. -=, *=, /=

let i1 = 1
var i2 = i1
i2 = 2
print(i2) // 2

i2 += 1
print(i2) // 3

i2 -= 2
print(i2) // 1

i2 *= 10
print(i2) // 10

i2 /= 2
print(i2) // 5

枚举

Swift的枚举有类的一些特性,比如计算属性、实例方法、扩展、遵循协议等等。

enum E1:String, CaseIterable {
    case e1, e2 = "12"
}

// 关联值
enum E2 {
    case e1([String])
    case e2(Int)
}
let e1 = E2.e1(["one","two"])
let e2 = E2.e2(3)

switch e1 {
case .e1(let array):
    print(array)
case .e2(let int):
    print(int)
}
print(e2)

// 原始值
print(E1.e1.rawValue)

// 遵循 CaseIterable 协议可迭代
for ie in E1.allCases {
    print("show \(ie)")
}

// 递归枚举
enum RE {
    case v(String)
    indirect case node(l:RE, r:RE)
}

let lNode = RE.v("left")
let rNode = RE.v("right")
let pNode = RE.node(l: lNode, r: rNode)

switch pNode {
case .v(let string):
    print(string)
case .node(let l, let r):
    print(l,r)
    switch l {
    case .v(let string):
        print(string)
    case .node(let l, let r):
        print(l, r)
    }
    switch r {
    case .v(let string):
        print(string)
    case .node(let l, let r):
        print(l, r)
    }
}

数据-专题

WwogICAgewogICAgICAgICJuYW1lIjoi6KeE6IyDIiwKICAgICAgICAiaWQiOjIxMTEyMzEzNTEsCiAgICAgICAgImlzc3VlcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMzEzNTIsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLms6jmhI/kuovpobkiLAogICAgICAgICAgICAgICAgIm51bWJlciI6NTAKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLotYTmlpnmjqjojZAiLAogICAgICAgICJpZCI6MjExMjA3MTcxMywKICAgICAgICAiaXNzdWVzIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMjA3MTcxNCwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuS5puWNlSIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxMDMKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLkuInmlrnlupPkvb/nlKgiLAogICAgICAgICJpZCI6MjExMjAyMTI1NCwKICAgICAgICAiaXNzdWVzIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMjAyMTI1NywKICAgICAgICAgICAgICAgICJ0aXRsZSI6IlNRTGl0ZS5zd2lmdCDnmoTkvb/nlKgiLAogICAgICAgICAgICAgICAgIm51bWJlciI6OTkKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiJtYWNPUyIsCiAgICAgICAgImlkIjoyMTExMjMxMzUzLAogICAgICAgICJpc3N1ZXMiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjMxMzU0LAogICAgICAgICAgICAgICAgInRpdGxlIjoi6IyD5L6LIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjUxCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIzMTM1NywKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuS4ieagj+e7k+aehCIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjo1MgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfQogICAgCl0K

泛型

泛型可以减少重复代码,是一种抽象的表达方式。where 关键字可以对泛型做约束。

func fn<T>(p: T) -> [T] {
    var r = [T]()
    r.append(p)
    return r
}
print(fn(p: "one"))

// 结构体
struct S1<T> {
    var arr = [T]()
    mutating func add(_ p: T) {
        arr.append(p)
    }
}

var s1 = S1(arr: ["zero"])
s1.add("one")
s1.add("two")
print(s1.arr) // ["zero", "one", "two"]

关联类型

protocol pc {
    associatedtype T
    mutating func add(_ p: T)
}

struct S2: pc {
    typealias T = String // 类型推导,可省略
    var strs = [String]()
    mutating func add(_ p: String) {
        strs.append(p)
    }
}

泛型适用于嵌套类型

struct S3<T> {
    struct S4 {
        var p: T
    }
    
    var p1: T
    var p2: S4
}

let s2 = S3(p1: 1, p2: S3.S4(p: 3))
let s3 = S3(p1: "one", p2: S3.S4(p: "three"))
print(s2,s3)

逻辑 !, &&, !!

let i1 = -1
let i2 = 2

if i1 != i2 && (i1 < 0 || i2 < 0) {
    print("i1 and i2 not equal, and one of them is negative number.")
}

Sets Set<Int>

Set 是无序集合,元素唯一

let s0: Set<Int> = [2, 4]
let s1: Set = [2, 10, 6, 4, 8]
let s2: Set = [7, 3, 5, 1, 9, 10]

let s3 = s1.union(s2) // 合集
let s4 = s1.intersection(s2) // 交集
let s5 = s1.subtracting(s2) // 非交集部分
let s6 = s1.symmetricDifference(s2) // 非交集的合集
print(s3) // [4, 2, 1, 7, 3, 10, 8, 9, 6, 5]
print(s4) // [10]
print(s5) // [8, 4, 2, 6]
print(s6) // [9, 1, 3, 4, 5, 2, 6, 8, 7]

// s0 是否被 s1 包含
print(s0.isSubset(of: s1)) // true
// s1 是否包含了 s0
print(s1.isSuperset(of: s0)) // true

let s7: Set = [3, 5]
// s0 和 s7 是否有交集
print(s0.isDisjoint(with: s7)) // true

// 可变 Set
var s8: Set = ["one", "two"]
s8.insert("three")
s8.remove("one")
print(s8) // ["two", "three"]

注释 //

// 单行注释
/*
多行注释第一行。
多行注释第二行。
*/ 
// MARK: 会在 minimap 上展示
// TODO: 待做
// FIXME: 待修复

运算符

位运算符

let i1: UInt8 = 0b00001111
let i2 = ~i1 // Bitwise NOT Operator(按位取反运算符),取反

let i3: UInt8 = 0b00111111
let i4 = i1 & i3 // Bitwise AND Operator(按位与运算符),都为1才是1
let i5 = i1 | i3 // Bitwise OR Operator(按位或运算符),有一个1就是1
let i6 = i1 ^ i3 // Bitwise XOR Operator(按位异或运算符),不同为1,相同为0

print(i1,i2,i3,i4,i5,i6)

// << 按位左移,>> 按位右移
let i7 = i1 << 1
let i8 = i1 >> 2
print(i7,i8)

溢出运算符,有 &+、&- 和 &*

var i1 = Int.max
print(i1) // 9223372036854775807
i1 = i1 &+ 1
print(i1) // -9223372036854775808
i1 = i1 &+ 10
print(i1) // -9223372036854775798

var i2 = UInt.max
i2 = i2 &+ 1
print(i2) // 0

运算符函数包括前缀运算符、后缀运算符、复合赋值运算符以及等价运算符。另,还可以自定义运算符,新的运算符要用 operator 关键字进行定义,同时要指定 prefix、infix 或者 postfix 修饰符。

数据-开发者动态

WwogICAgewogICAgICAgICJuYW1lIjoiU3dpZnTlrpjmlrkiLAogICAgICAgICJpZCI6MjExMTE2MTI1NSwKICAgICAgICAidXNlcnMiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoidGtyZW1lbmVrIiwKICAgICAgICAgICAgICAgICJkZXMiOiJTd2lmdCBkaXJlY3RvciIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiRG91Z0dyZWdvciIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoibWlrZWFzaCIsCiAgICAgICAgICAgICAgICAiZGVzIjogIkZyaWRheSBRJkEiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi56S+5Yy6IiwKICAgICAgICAiaWQiOjIxMTExNDEwNTMsCiAgICAgICAgInVzZXJzIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Im9uZXZjYXQiLAogICAgICAgICAgICAgICAgImRlcyI6IuWWteelniIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiRGlhblFLIiwKICAgICAgICAgICAgICAgICJkZXMiOiLpnZvpnZIgLSBTd2lmdEdH57+76K+R57uEIgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJrZWFuIiwKICAgICAgICAgICAgICAgICJkZXMiOiJOdWtl44CBUHVsc2UiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6InN0ZXBoZW5jZWxpcyIsCiAgICAgICAgICAgICAgICAiZGVzIjoiUG9pbnQtRnJlZSAmIFNRTGl0ZS5zd2lmdCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiaWJpcmVtZSIsCiAgICAgICAgICAgICAgICAiZGVzIjoiWVlEUyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoibWF0dHQiLAogICAgICAgICAgICAgICAgImRlcyI6Ik5TSGlwc3RlciIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoic2luZHJlc29yaHVzIgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJldGhhbmh1YW5nMTMiLAogICAgICAgICAgICAgICAgImRlcyI6IjEzIC0gW3dlYWsgc2VsZl3mkq3lrqIiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Ikt5bGUtWWUiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Im1pbmcxMDE2IiwKICAgICAgICAgICAgICAgICJkZXMiOiLmiLTpk60iCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Im14Y2wiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6ImxremhhbyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiaW5zaWRlZ3VpIgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJqb2hubm8xOTYyIiwKICAgICAgICAgICAgICAgICJkZXMiOiJJbmplY3Rpb25JSUkiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6IndpZ2dpbmciLAogICAgICAgICAgICAgICAgImRlcyI6IkJhY2sgdG8gdGhlIE1hYyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiRGltaWxsaWFuIiwKICAgICAgICAgICAgICAgICJkZXMiOiJNb3ZpZVN3aWZ0VUkiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6ImtyenlzenRvZnphYmxvY2tpIiwKICAgICAgICAgICAgICAgICJkZXMiOiLlhYPnvJbnqIsgU291cmNlcnkiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Im9ubXl3YXkxMzMiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6InBvZmF0IiwKICAgICAgICAgICAgICAgICJkZXMiOiJQb2ZhdCAtIFt3ZWFrIHNlbGZd5pKt5a6iIgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiJtZWNpZCIsCiAgICAgICAgICAgICAgICAiZGVzIjoiU3dpZnQgd2l0aCBNYWppZCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiaGViZXJ0aWFsbWVpZGEiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Imt5bGVmIiwKICAgICAgICAgICAgICAgICJkZXMiOiJDb21tYW5kZXIiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6Impvc2hhYmVyIiwKICAgICAgICAgICAgICAgICJkZXMiOiJhdCBHaXRIdWIiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6ImFzaGZ1cnJvdyIsCiAgICAgICAgICAgICAgICAiZGVzIjoiTW95YSIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoiamVzc2VzcXVpcmVzIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfQpdCg==

sorted

排序

// 类型遵循 Comparable
let a1 = ["a", "b", "c", "call my name.", "get it?"]
let a2 = a1.sorted()
let a3 = a1.sorted(by: >)
let a4 = a1.sorted(by: <)

print(a2) // Hey u, a b c call my name. get it?
print(a3) // ["get it?", "call my name.", "c", "b", "a"]
print(a4) // ["a", "b", "c", "call my name.", "get it?"]

// 类型不遵循 Comparable
struct S {
    var s: String
    var i: Int
}
let a5 = [S(s: "a", i: 0), S(s: "b", i: 1), S(s: "c", i: 2)]
let a6 = a5
    .sorted { l, r in
        l.i > r.i
    }
    .map {
        $0.i
    }

print(a6) // [2, 1, 0]

布尔数 Bool

布尔数有 true 和 false 两种值,还有一个能够切换这两个值的 toggle 方法。

var b = false
b.toggle() // true
b.toggle() // false

继承

类能继承另一个类,继承它的方法、属性等。

// 类继承
class C1 {
    var p1: String
    var cp1: String {
        get {
            return p1 + " like ATM"
        }
        set {
            p1 = p1 + newValue
        }
    }
    init(p1: String) {
        self.p1 = p1
    }
    func sayHi() {
        print("Hi! \(p1)")
    }
}

class C2: C1 {
    var p2: String
    init(p2: String) {
        self.p2 = p2
        super.init(p1: p2 + "'s father")
    }
}

C2(p2: "Lemon").sayHi() // Hi! Lemon's father

// 重写父类方法
class C3: C2 {
    override func sayHi() {
        print("Hi! \(p2)")
    }
}

C3(p2: "Lemon").sayHi() // Hi! Lemon

// 重写计算属性
class C4: C1 {
    override var cp1: String {
        get {
            return p1 + " like Out of the blade"
        }
        set {
            p1 = p1 + newValue
        }
    }
}

print(C1(p1: "Lemon").cp1) // Lemon like ATM
print(C4(p1: "Lemon").cp1) // Lemon like Out of the blade

通过 final 关键字可以防止类被继承,final 还可以用于属性和方法。使用 super 关键字指代父类。

Nil-coalescing ??

简化 if let else 写法

// if else
func f1(p: Int?) {
    if let i = p {
        print("p have value is \(i)")
    } else {
        print("p is nil, use defalut value")
    }
}

// 使用 ??
func f2(p: Int?) {
    let i = p ?? 0
    print("p is \(i)")
}

结构体

结构体是值类型,可以定义属性、方法、构造器、下标操作。结构体使用扩展来扩展功能,遵循协议。

struct S {
    var p1: String = ""
    var p2: Int
}

extension S {
    func f() -> String {
        return p1 + String(p2)
    }
}

var s = S(p2: 1)
s.p1 = "1"
print(s.f()) // 11

字符串

let s1 = "Hi! This is a string. Cool?"

/// 转义符 \n 表示换行。
/// 其它转义字符有 \0 空字符)、\t 水平制表符 、\n 换行符、\r 回车符
let s2 = "Hi!\nThis is a string. Cool?"

// 多行
let s3 = """
Hi!
This is a string.
Cool?
"""

// 长度
print(s3.count)
print(s3.isEmpty)

// 拼接
print(s3 + "\nSure!")

// 字符串中插入变量
let i = 1
print("Today is good day, double \(i)\(i)!")

/// 遍历字符串
/// 输出:
/// o
/// n
/// e
for c in "one" {
	print(c)
}

// 查找
print(s3.lowercased().contains("cool")) // true

// 替换
let s4 = "one is two"
let newS4 = s4.replacingOccurrences(of: "two", with: "one")
print(newS4)

// 删除空格和换行
let s5 = " Simple line. \n\n  "
print(s5.trimmingCharacters(in: .whitespacesAndNewlines))

// 切割成数组
let s6 = "one/two/three"
let a1 = s6.components(separatedBy: "/") // 继承自 NSString 的接口
print(a1) // ["one", "two", "three"]

let a2 = s6.split(separator: "/")
print(a2) // ["one", "two", "three"] 属于切片,性能较 components 更好

// 判断是否是某种类型
let c1: Character = "🤔"
print(c1.isASCII) // false
print(c1.isSymbol) // true
print(c1.isLetter) // false
print(c1.isNumber) // false
print(c1.isUppercase) // false

// 字符串和 Data 互转
let data = Data("hi".utf8)
let s7 = String(decoding: data, as: UTF8.self)
print(s7) // hi

// 字符串可以当作集合来用。
let revered = s7.reversed()
print(String(revered))

Unicode、Character 和 SubString 等内容参见官方字符串文档:Strings and Characters — The Swift Programming Language (Swift 5.1)

字符串字面符号可以参看《String literals in Swift》。

If • If let • If case let

// if
let s = "hi"
if s.isEmpty {
    print("String is Empty")
} else {
    print("String is \(s)")
}

// 三元条件
s.isEmpty ? print("String is Empty again") : print("String is \(s) again")

// if let-else
func f(s: String?) {
    if let s1 = s {
        print("s1 is \(s1)")
    } else {
        print("s1 is nothing")
    }
    // nil-coalescing
    let s2 = s ?? "nothing"
    print("s2 is \(s2)")
}
f(s: "something")
f(s: nil)

// if case let
enum E {
    case c1(String)
    case c2([String])
    
    func des() {
        switch self {
        case .c1(let string):
            print(string)
        case .c2(let array):
            print(array)
        }
    }
}

E.c1("enum c1").des()
E.c2(["one", "two", "three"]).des()

计算符 +, -, *, /, %

let i1 = 1
let i2 = i1
print((i1 + i2 - 1) * 10 / 2 % 3) // 2
print("i" + "1") // i1

// 一元运算符
print(-i1) // -1

范围 a…b

简化的值范围表达方式。

// 封闭范围
for i in 0...10 {
    print(i)
}

// 半开范围
for i in 0..<10 {
    print(i)
}

恒等 ===, !==

恒等返回是否引用了相同实例。

class C {
    var p: String
    init(p: String) {
        self.p = p
    }
}

let c1 = C(p: "one")
let c2 = C(p: "one")
let c3 = c1

print(c1 === c2) // false
print(c1 === c3) // true
print(c1 !== c2) // true

Switch

func f1(pa: String, t:(String, Int)) {
    var p1 = 0
    var p2 = 10
    switch pa {
    case "one":
        p1 = 1
    case "two":
        p1 = 2
        fallthrough // 继续到下个 case 中
    default:
        p2 = 0
    }
    print("p1 is \(p1)")
    print("p2 is \(p2)")
    
    // 元组
    switch t {
    case ("0", 0):
        print("zero")
    case ("1", 1):
        print("one")
    default:
        print("no")
    }
}

f1(pa: "two", t:("1", 1))
/*
 p1 is 2
 p2 is 0
 one
 */

// 枚举
enum E {
    case one, two, three, unknown(String)
}

func f2(pa: E) {
    var p: String
    switch pa {
    case .one:
        p = "1"
    case .two:
        p = "2"
    case .three:
        p = "3"
    case let .unknown(u) where Int(u) ?? 0 > 0 : // 枚举关联值,使用 where 增加条件
        p = u
    case .unknown(_):
        p = "negative number"
    }
    print(p)
}

f2(pa: E.one) // 1
f2(pa: E.unknown("10")) // 10
f2(pa: E.unknown("-10")) // negative number

数据-语法速查

WwogICAgewogICAgICAgICJuYW1lIjoi5Z+656GAIiwKICAgICAgICAiaWQiOjIxMTExNTE2MjUsCiAgICAgICAgImlzc3VlcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNTE2MjcsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLlj5jph48gbGV0LCB2YXIiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNTE4MTQsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLmiZPljbAgcHJpbnQoXCJcIikiLAogICAgICAgICAgICAgICAgIm51bWJlciI6NAogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNTE4MzMsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLms6jph4ogLy8iLAogICAgICAgICAgICAgICAgIm51bWJlciI6NQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNTE4NTAsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLlj6/pgIkgPywgISIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjo2CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTE2MTMxOSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IumXreWMhSIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjo3CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTE2MTQzMywKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuWHveaVsCBmdW5jIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjgKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMTYxNTQ4LAogICAgICAgICAgICAgICAgInRpdGxlIjoi6K6/6Zeu5o6n5Yi2IiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjkKICAgICAgICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuWfuuehgOexu+WeiyIsCiAgICAgICAgImlkIjoyMTExMTUxNjI2LAogICAgICAgICJpc3N1ZXMiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMTUxNjMwLAogICAgICAgICAgICAgICAgInRpdGxlIjoi5pWw5a2XIEludCwgRmxvYXQiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MwogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNjE1NTMsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLluIPlsJTmlbAgQm9vbCIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxMAogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNjE2NTAsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLlhYPnu4QgKGEsIGIsIGMpIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjExCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTE2MTc0MiwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuWtl+espuS4siIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxMgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNjE4MzMsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLmnprkuL4iLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTMKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMTYyMTAwLAogICAgICAgICAgICAgICAgInRpdGxlIjoi5rOb5Z6LIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjE0CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTE3MTQxMiwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuS4jemAj+aYjuexu+WeiyIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxNQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNzE0NDIsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLnsbvlnovovazmjaIiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTYKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLnsbvlkoznu5PmnoTkvZMiLAogICAgICAgICJpZCI6MjExMTE3MjAzMCwKICAgICAgICAiaXNzdWVzIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTE3MjAzMSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuexuyIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoxNwogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTExNzIwMzIsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLnu5PmnoTkvZMiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MTgKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjIxNzQyLAogICAgICAgICAgICAgICAgInRpdGxlIjoi5bGe5oCnIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjIyCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTc0MywKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuaWueazlSIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoyMwogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMjE3NDQsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLnu6fmib8iLAogICAgICAgICAgICAgICAgIm51bWJlciI6MjQKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICAgIm5hbWUiOiLlh73mlbDlvI8iLAogICAgICAgICJpZCI6MjExMTIyMTc0NSwKICAgICAgICAiaXNzdWVzIjpbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTc0NiwKICAgICAgICAgICAgICAgICJ0aXRsZSI6Im1hcCIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoyNQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMjE5MjQsCiAgICAgICAgICAgICAgICAidGl0bGUiOiJmaWx0ZXIiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MjYKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjIxOTI1LAogICAgICAgICAgICAgICAgInRpdGxlIjoicmVkdWNlIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjI3CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTkyNiwKICAgICAgICAgICAgICAgICJ0aXRsZSI6InNvcnRlZCIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjoyOAogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuaOp+WItua1gSIsCiAgICAgICAgImlkIjoyMTExMjIxOTI5LAogICAgICAgICJpc3N1ZXMiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjIxOTI3LAogICAgICAgICAgICAgICAgInRpdGxlIjoiSWYg4oCiIElmIGxldCDigKIgSWYgY2FzZSBsZXQiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MjkKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjIxOTMxLAogICAgICAgICAgICAgICAgInRpdGxlIjoiR3VhcmQgZ3VhcmQsIGd1YXJkIGxldCIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjozMgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMjE5MzIsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLpgY3ljoYgRm9yLWluIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjMzCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTkzNCwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IldoaWxlIHdoaWxlLCByZXBlYXQtd2hpbGUiLAogICAgICAgICAgICAgICAgIm51bWJlciI6MzQKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjIxOTM4LAogICAgICAgICAgICAgICAgInRpdGxlIjoiU3dpdGNoIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjM1CiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJuYW1lIjoi6ZuG5ZCIIiwKICAgICAgICAiaWQiOjIxMTEyMjE5NDAsCiAgICAgICAgImlzc3VlcyI6WwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMjE5MzksCiAgICAgICAgICAgICAgICAidGl0bGUiOiLmlbDnu4QgWzEsIDIsIDNdIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjM2CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTk0MSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IlNldHMgU2V0PEludD4iLAogICAgICAgICAgICAgICAgIm51bWJlciI6MzcKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjIxOTQyLAogICAgICAgICAgICAgICAgInRpdGxlIjoi5a2X5YW4IFs6XSIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjozOAogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAibmFtZSI6IuaTjeS9nOespiIsCiAgICAgICAgImlkIjoyMTExMjIxOTQ0LAogICAgICAgICJpc3N1ZXMiOlsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjoyMTExMjIxOTQzLAogICAgICAgICAgICAgICAgInRpdGxlIjoi6LWL5YC8ID0sICs9LiAtPSwgKj0sIC89IiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjM5CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTk0NSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6Iuiuoeeul+espiArLCAtLCAqLCAvLCAlIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjQwCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTk0NiwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuavlOi+g+i/kOeul+espiA9PSwgPiIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjo0MQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMjE5NDcsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLkuInlhYMgXyA/IF8gOiBfIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjQyCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTk0OCwKICAgICAgICAgICAgICAgICJ0aXRsZSI6Ik5pbC1jb2FsZXNjaW5nID8/IiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjQzCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTk0OSwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuiMg+WbtCBh4oCmYiIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjo0NAogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMjE5NTEsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLpgLvovpEgISwgJiYsICEhIiwKICAgICAgICAgICAgICAgICJudW1iZXIiOjQ1CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJpZCI6MjExMTIyMTk1MiwKICAgICAgICAgICAgICAgICJ0aXRsZSI6IuaBkuetiSA9PT0sICE9PSIsCiAgICAgICAgICAgICAgICAibnVtYmVyIjo0NgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOjIxMTEyMjE5NTMsCiAgICAgICAgICAgICAgICAidGl0bGUiOiLov5DnrpfnrKYiLAogICAgICAgICAgICAgICAgIm51bWJlciI6NDcKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0KXQ==

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.