Swift

变量常量与基本类型

// 常量let pi = 3.14// 变量var i = 1, j = 2// 显式变量类型var url: String = "www.baidu.com"// 整型 取决于机器字长print(Int.max)// 无符号整型print(UInt.max)// 8位整型print(Int8.max)// 浮点数let x: Float = 3.1415926let y: Double = 3.155645print(x, y)// 不支持隐式转换print(x+Float(y))// 元组var property: (String, Int, (Int, Int, Int)) = ("cxk", 18, (35, 35, 35))print(property)print(property.0)print(property.1)// 元组的比较print((1,2,3) < (3,2,1))// 解构let (name, age, quake) = property// 解构忽略部分属性let (name1, age1, _) = propertyprint(name, age, quake)// 命名元组属性var point: (x: Int, y: Int) = (1,2)var point1 = (x:1, y: 2)print("the point: \(point), point1: \(point1)")

运算符

基本的数值逻辑运算符操作跟 Java 一样, 但在 Swift3 之后 ++ -- 已被废弃

=== 与 !== 用来比较对象的引用

常量的首次赋值

let i: Intvar condition = falseif condition {    i = 1}else {    i = 2}

范围运算符

let a = 0..<10 // 前闭后开(0-9)print(a)// 前闭后闭(1-10)for index in 1...10 {    print(index)    // 循环里的index是常量    // index += 1}

控制流

循环

// 忽略下标for _ in 1...10 {    print("gogogo")}
var i = 1// i的后面一定要有空格while i <= 10 {    print(i)    i += 2}
var j = 1repeat {    print(j)    j += 2}while(j <= 10)

选择

// 每条case之间不用加breakvar rank = "a"switch rank {// 同时case多个条件case "a", "A":    print("jn")case "b":    print("d")default:    print("defa")// 空语句//default:break//default:()}// switch与范围switch 5 {case 1...5:    print("1-5")case 6...10:    print("6-10")default:()}// switch与元组let response = (200, "OK")switch response {case(200, "OK"):    print("done")case(200, "GOON"):    print("continue")default:()}// 在case中解构变量switch (0,0) {case(let x, 0):    print("x is \(x)")case (0, let y):    print("y is \(y)")default:()}// 继续往下执行switch 5 {case 5:    print("5")    // 不会判断下面的case是否满足条件 无脑执行    fallthroughcase 6:    print("6")default:()}

控制转移

// 跳出多重循环outter:for index in 1...10{    for index1 in 1...10 {        if (index == 3 && index1 == 3) {                print("i got go")                break outter        }    }}

where

// where类似于SQL中的where 是一种条件限定switch (3,3){case let(x,y) where x == y:    print("x == y")case let(x,y):    ()}for case let index in 1...10 where index % 3 == 0 {    print(index)}

guard

// 防御式编程的语义化// 只有满足条件才不会进入代码块guard num >= 1 else {    print("stop")    exit(0)}

字符串

基础

// 判断是否是空字符串print(str.isEmpty)// 插值表达式print("name: \(str)")// 字符串拼接 转义字符等同类C语言

char与unicode

// 显式声明单个字符(底层采用unicode存储)let single: Character = "中"let single1: Character = "🐶"// 遍历字符for c in "中文大萨达🇨🇳" {    print(c)}// 字符串是可变的str.append("jntm")print(str)// 字符串长度print(str.count)

索引

// 字符串索引// [startIndex, endIndedx)var s = "我如果付费"// 需要根据startIndex 或者endIndex 计算print(s[s.index(s.startIndex, offsetBy: 2)]) // 果 在第一个索引往后的2个print(s[s.index(before: s.endIndex)]) // 费 在最后一个索引之前的一个

方法

print(s.uppercased())print(s.lowercased())print(s.capitalized) // 将每个单词转为首字母大写print(s.contains("如果"))print(s.hasPrefix("我 "))print(s.hasSuffix("费"))

NSString

print(NSString(format: "%.2f", 1.0 / 3.0) as String)// 截取print(NSString("微分去问问").substring(with: NSMakeRange(1, 3)))// 替换两边的字符print(NSString("-a-").trimmingCharacters(in: CharacterSet(charactersIn: "-")))

可选型

var responseCode : Int? = 404var responseMessage: String? = "success"responseCode = nilvar code: Int! = 4let a  = code // 此时a的类型是Int?let b: Int = code // 可以转为Int

解包

// 强制解包print(responseCode!)// 在判断中解包if let responseCode = responseCode {    // 这里出现了变量遮蔽    print(responseCode)}// 同时判断解包多个if let responseCode = responseCode,   let responseMessage = responseMessage {    print(responseCode, responseMessage)}

可选型链

if let responseMessage = responseMessage {    print(responseMessage.uppercased)}// 等同于print(responseMessage?.uppercased)// 如果是 nil 则 message 的值 为 message nulllet message = responseMessage ?? "message null"

在类库中的使用

// 类型转换 如果转换失败 就返回 nilif let age = Int("18"), age <= 18 {    print(age)}

隐式可选型

// 一般用在类中 初始化时为空 当初始化完成 保证对外提供的不为 nilvar a: String! = nil// a = "hello"// 执行错误print(a + "dsds")

数组

声明

var nums = [0,1,2,3]// 指定类型var strings: [String] = ["0","2", "a"]// 空数组var es : Array<Int> = []var es1 = [Int]()// 5个元素初始值 全为5var allZeros = [Int](repeating: 5, count: 5)

基本操作

print(allZeros.count)print(allZeros.isEmpty)// 数组越界会有运行异常print(allZeros[3])print(allZeros.first!, allZeros.last!)print(nums.min()!, nums.max()!)// 子数组 1,2,3print(nums[1..<4])print(nums.contains(3))print(nums.firstIndex(of: 3)!)// for-eachfor number in nums {    print(number)}// 带下标的for-eachfor (index, item) in strings.enumerated() {    print(index, item)}// 值比较print(nums == [0,1,2,3])

修改

es.append("jntm")// 添加两个元素到数组里面es += ["cxk", "juki"]// 插入后位于索引2es.insert("ctrl", at: 2)es.removeLast()es.removeFirst()// 删除指定下标es.remove(at: 1)es.removeAll()nums[0] = 3// 区间设置值nums[0...2] = [9,9,9]// 两边长度可以不一致nums[0...2] = [7]

NSArray

// 可以承载不同数据类型var na: NSArray = [1, "hello", 3]

集合

字典

var dict: [String: String] = ["name": "cxk", "age": "18"]var dict1: Dictionary<String, String> = [:]print(dict["name"]!)print(Array(dict.keys))print(Array(dict.values))for key in dict.keys {    print(dict[key]!)}for (key, value) in dict {    print(key, value)}print(dict == ["name": "cxk", "age": "18"])// 更新dict["name"] = "jntm"// 这个方法会返回其之前的值dict.updateValue("jntm", forKey: "name")// 删除dict["name"] = nildict.removeValue(forKey: "name")dict.removeAll()

Set

// 声明var set : Set<String> = ["a", "b" , "c"]for i in set {    print(i)}print(set == ["b", "c", "a"])set.insert("aa")set.remove("c")// 集合运算print(set.union(["a","aa"]))print(set.intersection(["a", "aa"]))print(set.subtracting(["a", "aa"]))print(set.symmetricDifference(["a", "aa"]))

函数

定义

// 有参数有返回值func say(name: String, age: Int) -> String {    return "jntm \(name) - \(age)"}// 无参数无返回值func say() {    print( "ctrl")}// 返回多个值func request() -> (message: String, code: Int) {    return ("not found", 404)}// 调用时 多个参数必须使用 形参: 实参 的形式print(say(name: "cxk", age: 18))

外内部参数名

// 外部与内部参数名func request(url getUrl: String) {    print(getUrl)}request(url: "http://baidu.com")// 忽略外部参数名func request(_ url: String, _ method: String) {}request("baidu.com", "get")

默认参数、可变参数

// 可变参数不像其他语言 可以不放在最后 可变参数本质上也是一个数组func request(url: String, method: String = "get", params: String ...){}request(url: "baidu.com", params: "sds", "dfsds")

引用参数

// 默认参数值和可变参数// 可变参数不像其他语言 可以不放在最后 可变参数本质上也是一个数组func request(url: String, method: String = "get", params: String ...){}request(url: "baidu.com", params: "sds", "dfsds")// 形参默认都是不可变的// 使用 inout 关键字 相当于一个指针func request(url: inout String){    url = "google.com"}var u = "dsds"request(url: &u)print(u)

函数式编程

func submit(runnable: () -> ()) {    runnable()}func print(){    print("running")}// 第一种调用submit(runnable: print)// 第二种调用submit {    print("hhh")}// 传递一个参数func submit(consumer: (String) -> ()){    consumer("ikun")}submit { params in    print(params)}// 函数式编程三大操作print([1,2,3].map{ v in v + 1})print([1,2,3].filter{ v in v % 2 == 0})print([1,2,3].reduce(10, {x, y in x + y}))// 返回函数类型func getFuture() -> () -> () {    return {        print("this is future")    }}getFuture()()// 函数嵌套func execute(){    func innerFunc(){        print("hello world")    }    innerFunc()}execute()

闭包

var res = [1, 2, 3].sorted(by: { (a: Int, b: Int) -> Bool in    return a > b})print(res)// 化简print([1,2,3].sorted(by: {a, b in a > b}))// 默认命名print([1, 2, 3].sorted(by: {$0 > $1}))// 大于号本身是一个函数print([1,2,3].sorted(by: >))// 结尾闭包 最后一个参数是闭包的话 可以使用这种语法print([1,2,3].sorted{ a, b in a > b})print([1,2,3].map{v in String(v)})// 内容捕获var num = 700print([1,2,3].sorted{a , b in abs(a-num) < abs(b-num)})// @autoclosure 自动将值封装成匿名函数func test(f: @autoclosure () -> String) -> String {    return f()}test(f: "test")

枚举

enum Color: String {    case Red = "红色",Yellow = "黄色",Blue = "蓝色"}let color: Color = .Blueswitch color {case .Blue:    print(color.rawValue)case .Yellow:    print(color.rawValue)case .Red:    print(color.rawValue)}// 使用rawValue获取枚举值print(Color(rawValue: "红色")!)// 关联值enum Status {    case Success(message: String, code: Int)    case Error(String)}let result = Status.Success(message: "done", code: 200)switch result {case let .Success(message, _):    print("sucess \(message)")case .Error:    print("error")}// 可选型的本质就是使用了关联值的枚举let name: String? = Optional.some("jntm")switch name {case let .some(name):    print(name)case .none:    print("is nil")}

结构体

struct Location {    // 这里var跟let的区别在于是否可变    var x = 0,y: Int = 0    var z: Int = 0        init() {}    init(x: Int, y: Int, z: Int) {}    init(x: Int, y: Int) {        self.x = x        self.y = y    }    // 可失败的构造函数 返回nil    init?(x: Int) {        guard x <= 100 else {            return nil        }        self.x = x    }        func distance() -> Int {        return x - y    }    // 如果不加mutating这个关键字 这个方法就没法修改结构体    mutating func setX(x: Int) {        self.x += 1    }}var home = Location(x: 1, y: 2, z: 3)// 如果里面的字段有默认值 在这里的构造可以传参var empty = Location()print(Location(x: 4, y: 3))print(home.x)print(Location(x:101) ?? -1)home.x = 2print(home.distance())// 结构体和枚举是值类型var p1 = Location(x: 1, y: 2)var p2 = p1p1.x = 3print(p2.x == 1)

class Person {    static var popilation: Int = 700_0000_0000    var name: String    var age: Int {        // 属性观察器 需要注意的是不会在init阶段被调用        // 将要赋值        willSet {            if newValue > 200 {                print("太太老")            }        }        // 已经赋值了        didSet {            if age == 18 {                print("貌美如花")            }            if age > 100 {                print("太老了")                age = oldValue            }        }    }    // 计算属性    var nameAndAge: String {        get{            return name + "," + String(age)        }        set(nameAndAge) {            self.name = nameAndAge.components(separatedBy: ",")[0]            self.age = Int(nameAndAge.components(separatedBy: ",")[1])!        }    }    var bithYear: Int {        return 2022 - self.age    }        // 延迟属性 首次访问时会被计算后缓存下来    lazy var firstDate: Date = {        return Date()    }()        init(name: String, age: Int) {        self.name = name        self.age = age    }    init?(nameAndAge: String) {        if !nameAndAge.contains(",") {            return nil        }        self.name = nameAndAge.components(separatedBy: ",")[0]        self.age = Int(nameAndAge.components(separatedBy: ",")[1])!    }            // 类型方法    static func populationBalanced() -> Bool {        return popilation <= 7000_0000_0000    }}// 类创建的对象是引用类型let cxk = Person(name: "cxk", age: 18)print(cxk.age)print(Person(nameAndAge: "cxk,18")!.age)// cxk本身如果是常量 但里面的成员是变量 则可以修改 不像结构体cxk.age = 22// 继承class Student: Person {    var grade = 12    // 重载构造器    // 使用required关键字来强制子类必须重写该构造函数    required init(grade: Int) {        // 在super.init之前 不能做self初始化之外的操作        // self.eat()        super.init(name: "cxk", age: 17)        self.grade = grade    }    // 便利构造函数 通过一定逻辑调用其他构造函数初始化    // 便利构造器无法调用super.init    // 如果子类实现了父类所有的指定构造函数,则自动继承父类的所有便利构造函数    convenience init(){        self.init(name: "jntm", age: 22)    }    // 重写构造器    override init(name: String, age: Int) {        super.init(name: name, age: age)        self.name = name        self.age = age    }    // 重写属性    override var bithYear: Int {        return 2023 - self.age    }    // 重写方法    override func eat() {        print("student eat")    }}// 禁止再继承final class SuperPerson: Person{}let student = Student(grade: 12)print(student.nameAndAge)// 多态let persons: [Person] = [SuperPerson(nameAndAge: "s1,14")!, Student(grade: 18), Person(nameAndAge: "s1,32")!]

访问控制:

运算符重载

// 自定义运算符需要声明 postfix prefix infixinfix operator |||struct ReversedList {    var data: [Int] = [1,2,3,4,5]        // 重载下标运算符    subscript(index: Int) -> Int? {        get {            data[data.count - index - 1]        }        set {            if let newValue = newValue {                data[data.count - index - 1] = newValue            }        }    }    // 多维下标    subscript(index1: Int, index2: Int) -> Int {        return data[index1] + index2    }        // 算术运算符重载    static func + (left: ReversedList, right: ReversedList) -> ReversedList {        return ReversedList(data: left.data + right.data)    }    static func + (left: ReversedList, right: Int) -> ReversedList {        var left = left        for i in 0..<left.data.count {            left.data[i] += right        }        return left    }    static func += (left: inout ReversedList, right: Int) {        left = left + right    }    prefix static func - (left: ReversedList) -> ReversedList {        return ReversedList(data: left.data.map {-$0})    }        // 比较运算符重载    static func == (left: ReversedList, right: ReversedList) -> Bool {        guard left.data.count == right.data.count else {            return false        }        for i in 0..<left.data.count {            if (left.data[i] != right.data[i]) {                return false            }        }        return true    }    static func < (left: ReversedList, right: ReversedList) -> Bool {        for i in 0..<left.data.count {            if left.data[i] >= right.data[i] {                return false            }        }        return true    }        // 自定义运算符 /,=,-,+,!,*,%,<,>,&,|,^,~    static func ||| (left: ReversedList, right: ReversedList) -> ReversedList {        var left = left        for i in 0..<left.data.count {            left.data[i] = left.data[i] % right.data[i]        }        return left            }}

扩展

extension String {    // 如果扩展类的构造方法 则构造方法必须是便利构造方法    init(by: String) {        self.init(by.uppercased())    }        // 扩展的属性只能是计算型属性    var length: Int {        self.count    }        func firstChar() -> Character {        return self[self.startIndex]    }        // 嵌套类型    struct Range {}}let range : String.Range? = nil

泛型

// 泛型函数func swap<T>(a: inout T, b: inout T) {    (a,b) = (b,a)}var a = "123"var b = "321"swap(a: &a, b: &b)print(a,b)// 泛型类型struct ArrayList<T> {    var data: [T] = []        mutating func add(e: T) {        data += [e]    }}var list = ArrayList<String>()list.add(e: "123")print(list)

协议

protocol Runnable {        // 协议的属性    var threadName: String {get set}        // 协议的方法    func run()}struct Task: Runnable {    var threadName = "test"    func run() {        print("running")    }    }// 只有类才能实现该协议protocol Future: AnyObject {}class MyFuture: Future{}// 如果既需要继承有需要协议 则继承类要放在协议的前面class Callable: NSObject, Future {}// 类型别名typealias Length = Intlet length: Length = 123// 类型参数化protocol WeightCalacuable {    associatedtype WightType    var weight: WightType {get}}class Phone: WeightCalacuable {    typealias WightType = Double    var weight = 0.114}class Boat: WeightCalacuable {    typealias WightType = Int    var weight = 100_0000}

标准库的常用协议:Equatable, Comparable, CustomStringCovertible

面向协议编程

// 扩展协议protocol Callable: Runnable{    func call() -> Int    }// 协议的默认实现extension Callable {    func run() {        let _ = self.call()    }}// 限定扩展:只有同时实现Callable和WeightCalacuable才应用extension Callable where Self: WeightCalacuable {    func run() {        print("calc run")    }}struct Computer: Callable, WeightCalacuable {    var weight: Int    func call() -> Int {        return 0    }        typealias WightType = Int    var threadName: String    }Computer(weight: 1, threadName: "test").run()// 协议聚合:同时实现两种协议的参数才被接受func run(computeable: Callable & CustomStringConvertible){}// 泛型约束func topOne<T: Comparable & CustomStringConvertible>(seq: [T]) -> T {    let ans = seq.sorted()[0]    print(ans.description)    return ans}print(topOne(seq: [67,6,4,23,45,2,1]))// 协议的可选方法@objc protocol Service {    @objc optional func start()}class UserService: Service{}let service: Service = UserService()if let start = service.start {    start()}

错误处理

enum RuntimeError: Error{    case NetWorkError(String)    case ReadTimeOutError}func main(a: Int) throws -> Void {    // 函数执行结束后才会执行    defer {        print("finally2 execute")    }    defer {        print("finally1 execute")    }    if a == 1 {        throw RuntimeError.NetWorkError("unknow host")    }}// 强制忽略异常 发生异常程序就会崩try! main(a:2)// 忽略异常 发生异常不会蹦try? main(a: 1)do {    try main(a: 1)}catch RuntimeError.NetWorkError(let e) {    print("error", e)}catch let e as RuntimeError {    print(e)}catch {    print("unknow error")}// 使用Nerver代表异常情况func errorHandle() -> Never {    print("!!!")    fatalError()}var aaa = 1guard aaa != 1 else {    errorHandle()}

内存管理

class Pet {    var owner: Person?    init(owner: Person) {        self.owner = owner    }    deinit{        print("pet clean")    }}class Person {    // 没有加weak时会出现相互引用导致内存泄漏 加了weak后不会增加pet的引用数    // weak要求类型是可选型并且是var的 如果不满足这个条件 需要使用unowned    // 但unowned有一定的风险 如果一个unowned被回收后被使用 则会发生致命错误    weak var pet: Pet?    init() {        pet = Pet(owner: self)    }    deinit {        print("person clean")    }}// swift 使用引用计数var p: Person? = Person()p = nil

对于闭包循环引用 可以使用 [unoned xxx] 的方式来声明闭包内的变量为弱引用

类型检查与转换

class Animal{}class Duck: Animal{}class Dog: Animal{}let dog: Animal = Dog()// 类型检查print(dog is Dog)// 尝试强制转型 失败返回nilprint((dog as? Dog)!)

Any > AnyObject > NSObject