• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

DarielChen/iOSTips: 记录iOS(Swift)开发中的一些知识点、小技巧

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

DarielChen/iOSTips

开源软件地址:

https://github.com/DarielChen/iOSTips

开源编程语言:

Swift 99.6%

开源软件介绍:

iOSTips(๑•̀ㅂ•́)و✧

Language: Swift 5.0 Platform: iOS 12

1.SwiftTips

记录iOS开发中的一些知识点

目录

1.常用的几个高阶函数
2.高阶函数扩展
3.优雅的判断多个值中是否包含某一个值
4.Hashable、Equatable和Comparable协议
5.可变参数函数
6.where关键字
7.switch中判断枚举类型,尽量避免使用default
8.iOS9之后全局动态修改StatusBar样式
9.使用面向协议实现app的主题功能
10.swift中多继承的实现
11.华丽的TableView刷新动效
12.实现一个不基于Runtime的KVO
13.实现多重代理
14.自动检查控制器是否被销毁
15.向控制器中注入代码
16.给Extension添加存储属性
17.用闭包实现按钮的链式点击事件
18.用闭包实现手势的链式监听事件
19.用闭包实现通知的监听事件
20.AppDelegate解耦
21.常见的编译器诊断指令
22.最后执行的defer代码块
23.定义全局常量
24.使用Codable协议解析JSON
25.dispatch_once替代方案
26.被废弃的+load()和+initialize()
27.交换方法 Method Swizzling
28.获取View的指定子视图
29.线程安全: 互斥锁和自旋锁(10种)
30.可选类型扩展
31.更明了的异常处理封装
32.关键字static和class的区别
33.在字典中用KeyPaths取值
34.给UIView顶部添加圆角
35.使用系统自带气泡弹框
36.给UILabel添加内边距
37.给UIViewController添加静态Cell
38.简化使用UserDefaults
39.给TabBar上的按钮添加动画
40.给UICollectionView的Cell添加左滑删除
41.基于NSLayoutAnchor的轻量级AutoLayout扩展
42.简化复用Cell的代码
43.正则表达式的封装
44.自定义带动画效果的模态框
45.利用取色盘获取颜色
46.第三方库的依赖隔离
47.给App的某个功能添加快捷方式
48.给UITableView添加空白页
49.线程保活的封装
50.GCD定时器
51.命名空间及应用
52.数据绑定的封装
53.基于CSS样式的富文本
54.阴影视差效果的封装
55.使用协调器模式管理控制器
56.判断字符串是否为空
57.避免将字符串硬编码在代码中
58.恢复非正常终止的应用状态
59.清晰的错误处理类型Result
60.插件化子控制器
61.ExpressibleBy协议集:通过字面量实例化对象
62.插件化TableView
63.自定义底部弹层控制器
64.UIAlertController的封装
65.自定义控制器构造方法
66.性能调优之像素对齐
67.可以做与运算的结构体

2.XcodeTips

记录使用Xcode工具的一些小技巧

1.生成对外暴露的属性和方法
2.显示Storyboard中控件之间的距离
3.重命名当前文件中的方法名或变量名
4.Storyboard中视图只覆盖不被添加
5.锁定Storyboard中控件的约束
6.多重光标操作
7.断点对象预览
8.Storyboard解耦
9.获取app的启动日志
10.模拟器录屏
11.AutoLayout约束错误声音提示

1.常用的几个高阶函数

函数式编程在swift中有着广泛的应用,下面列出了几个常用的高阶函数.

1. sorted

常用来对数组进行排序.顺便感受下函数式编程的多种姿势.

1. 使用sort进行排序,不省略任何类型
let intArr = [13, 45, 27, 80, 22, 53]

let sortOneArr = intArr.sorted { (a: Int, b: Int) -> Bool in
    return a < b
}
// [13, 22, 27, 45, 53, 80]
2. 编译器可以自动推断出返回类型,所以可以省略
let sortTwoArr = intArr.sorted { (a: Int, b: Int) in
    return a < b
}
// [13, 22, 27, 45, 53, 80]
3. 编译器可以自动推断出参数类型,所以可以省略
let sortThreeArr = intArr.sorted { (a, b) in
    return a < b
}
// [13, 22, 27, 45, 53, 80]
4. 编译器可以自动推断出参数个数,所以可以用$0,$1替代
let sortFourArr = intArr.sorted {
    return $0 < $1
}
// [13, 22, 27, 45, 53, 80]
5. 如果闭包中的函数体只有一行,且需要有返回值,return可以省略
let sortFiveArr = intArr.sorted {
    $0 < $1
}
// [13, 22, 27, 45, 53, 80]
6. 最简化: 可以直接传入函数<
let sortSixArr = intArr.sorted(by: <)
// [13, 22, 27, 45, 53, 80]

2. map和compactMap

1. map: 对数组中每个元素做一次处理.
let mapArr = intArr.map { $0 * $0 }
// [169, 2025, 729, 6400, 484, 2809]
2. compactMap: 和map类似,但可以过滤掉nil,还可以对可选类型进行解包.
let optionalArr = [nil, 4, 12, 7, Optional(3), 9]
let compactMapArr = optionalArr.compactMap { $0 }
// [4, 12, 7, 3, 9]

3. filter: 将符合条件的元素重新组合成一个数组

let evenArr = intArr.filter { $0 % 2 == 0 }
// [80, 22]

4. reduce: 将数组中的元素合并成一个

// 组合成一个字符串
let stringArr = ["1", "2", "3", "*", "a"]
let allStr = stringArr.reduce("") { $0 + $1 }
// 123*a

// 求和
let sum = intArr.reduce(0) { $0 + $1 }
// 240

5. 高阶函数可以进行链式调用.比如,求一个数组中偶数的平方和

let chainArr = [4, 3, 5, 8, 6, 2, 4, 7]

let resultArr = chainArr.filter {
                            $0 % 2 == 0
                        }.map {
                            $0 * $0
                        }.reduce(0) {
                            $0 + $1
                        }
// 136

⬆️ 返回目录

2.高阶函数扩展

1. map函数的实现原理

extension Sequence {
    
    // 可以将一些公共功能注释为@inlinable,给编译器提供优化跨模块边界的泛型代码的选项
    @inlinable
    public func customMap<T>(
        _ transform: (Element) throws -> T
        ) rethrows -> [T] {
        let initialCapacity = underestimatedCount
        var result = ContiguousArray<T>()
        
        // 因为知道当前元素个数,所以一次性为数组申请完内存,避免重复申请
        result.reserveCapacity(initialCapacity)
        
        // 获取所有元素
        var iterator = self.makeIterator()
        
        // 将元素通过参数函数处理后添加到数组中
        for _ in 0..<initialCapacity {
            result.append(try transform(iterator.next()!))
        }
        // 如果还有剩下的元素,添加进去
        while let element = iterator.next() {
            result.append(try transform(element))
        }
        return Array(result)
    }
}

map的实现无非就是创建一个空数组,通过for循环遍历将每个元素通过传入的函数处理后添加到空数组中,只不过swift的实现更加高效一点.

关于其余相关高阶函数的实现:Sequence.swift

2. 关于数组中用到的其他的一些高阶函数

class Pet {
    let type: String
    let age: Int
    
    init(type: String, age: Int) {
        self.type = type
        self.age = age
    }
}

var pets = [
            Pet(type: "dog", age: 5),
            Pet(type: "cat", age: 3),
            Pet(type: "sheep", age: 1),
            Pet(type: "pig", age: 2),
            Pet(type: "cat", age: 3),
            ]
1. 遍历所有元素
pets.forEach { p in
   print(p.type)
}
2. 是否包含满足条件的元素
let cc = pets.contains { $0.type == "cat" }
3. 第一次出现满足条件的元素的位置
let firstIndex = pets.firstIndex { $0.age == 3 }
// 1
4. 最后一次出现满足条件的元素的位置
let lastIndex = pets.lastIndex { $0.age == 3 }
// 4
5. 根据年龄从大到小进行排序
let sortArr = pets.sorted { $0.age < $1.age }
6. 获取age大于3的元素
let arr1 = pets.prefix { $0.age > 3 }
// [{type "dog", age 5}]
7. 获取age大于3的取反的元素
let arr2 = pets.drop { $0.age > 3 }
// [{type "cat", age 3}, {type "sheep", age 1}, {type "pig", age 2}, {type "cat", age 3}]
8. 将字符串转化为数组
let line = "BLANCHE:   I don't want realism. I want magic!"

let wordArr = line.split(whereSeparator: { $0 == " " })
// ["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]

⬆️ 返回目录

3.优雅的判断多个值中是否包含某一个值

我们最常用的方式

let string = "One"

if string == "One" || string == "Two" || string == "Three" {
    print("One")
}

这种方式是可以,但可阅读性不够,那有啥好的方式呢?

1. 我们可以利用contains:

if ["One", "Two", "Three"].contains(where: { $0 == "One"}) {
	print("One")
}

2. 自己手动实现一个any

使用:
if string == any(of: "One", "Two", "Three") {
    print("One")
}
实现:
func any<T: Equatable>(of values: T...) -> EquatableValueSequence<T> {
    return EquatableValueSequence(values: values)
}

struct EquatableValueSequence<T: Equatable> {
    static func ==(lhs: EquatableValueSequence<T>, rhs: T) -> Bool {
        return lhs.values.contains(rhs)
    }
    
    static func ==(lhs: T, rhs: EquatableValueSequence<T>) -> Bool {
        return rhs == lhs
    }
    
    fileprivate let values: [T]
}

这样做的前提是any中传入的值需要实现Equatable协议.

⬆️ 返回目录

4. Hashable、Equatable和Comparable协议

1. Hashable

实现Hashable协议的方法后我们可以根据hashValue方法来获取该对象的哈希值.
字典中的value的存储就是根据key的hashValue,所以所有字典中的key都要实现Hashable协议.

class Animal: Hashable {
    
    var hashValue: Int {
        return self.type.hashValue ^ self.age.hashValue
    }
    
    let type: String
    let age: Int
    
    init(type: String, age: Int) {
        self.type = type
        self.age = age
    }
}

let a1 = Animal(type: "Cat", age: 3)
a1.hashValue
// 哈希值

2. Equatable协议

实现Equatable协议后,就可以用==符号来判断两个对象是否相等了.

class Animal: Equatable, Hashable {
    
    static func == (lhs: Animal, rhs: Animal) -> Bool {
        if lhs.type == rhs.type && lhs.age == rhs.age{
            return true
        }else {
            return false
        }
    }
        
    let type: String
    let age: Int
    
    init(type: String, age: Int) {
        self.type = type
        self.age = age
    }
}

let a1 = Animal(type: "Cat", age: 3)
let a2 = Animal(type: "Cat", age: 4)

a1 == a2
// false

3. Comparable协议

基于Equatable基础上的Comparable类型,实现相关的方法后可以使用<<=>=> 等符号进行比较.


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap