Tino又想吃肉了

swift笔记

Word count: 1.1kReading time: 4 min
2021/03/15

学习swift中的一些记录

swift

常用的几个协议

在编写一个协议时,定义只读属性不要使用let,而是使用var并设置为只有get方法
使用协议的方法时,注意要在方法里使用[weak self]

Hashable : 可哈希化

  • Hashable继承于Equatable协议

  • 在标准库中,大部分基本类型都是遵循Hashable协议的,如Int、String等

  • 使用DictionarySet等数据结构时,要求作为Key的类型要实现Hashable协议

  • 在swift4.2之后,如果一个struct中包含的数据类型是基本类型,那么在使它遵循Hashable时编译器会自动为它生成一组==hash(into:)函数。

    1
    2
    3
    4
    5
    //如果想自己实现hash函数,大多数情况下这样就可以
    func hash(into hasher: inout Hasher) {
    hasher.combine(xxx)
    hasher.combine(xxx)
    }

Codable : 可以转解码

  • Codable 实际上是由Encodable & Decodable 组成
  • 遵循Codable协议的对象会自动实现Encodable & Decodable
  • Decodable协议定义了一个初始化函数:init(from decoder: Decoder) throws
  • Encodable协议定义了一个方法:func encode(to encoder: Encoder) throws
  • 使用遵循Codinkey协议的一个enum可以自定义要解析的键值名
  • Codable的主要使用场景是将JSON数据解析为模型数据,需要将要解析的内容设置成可选型,否则如果JSON中某数据为空的话将会解析失败。
  • 解析数据时只需要使用一个JSONDecoder实例,调用它的decode的方法就可以实现解析。如let student = try JSONDecoder().decode(Student.self,from: json)

Equatable : 可比较

  • 基本操作类型默认实现了Equatable
  • 要让自定义类型实现Equatable的话,可以使用extension,在extension中遵循Equatable协议,并且实现需要的例如==等方法
  • Comparable协议类似

Identifiable

  • 为类型确定一个唯一标识符
  • 实现Identifiable协议的类型可以在For等循环中迭代
  • 需要var id : Int

@propertyWrapper

1.处理属性赋值时的值

  • 实现一个可以裁剪掉字符串空格的属性修饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@propertyWrapper
struct Trimmed {
private var value = String()

var wrappedValue : String{
get { value }
set {
value = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
}
}

init(wrappedValue : String){
self.wrappedValue = wrappedValue
}
}

2.保证某个属性的值满足一定条件

  • 在swift和oc中,调用URL的字符串初始化方法,如果字符串中含有如中文的非法字符,则会初始化失败,URL会返回nil
  • 这时就可以用一个@propertyWrapper修饰变量,使它在赋值时自动转换成合法的字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@propertyWrapper
struct Trimmed {
private var value = String()

var wrappedValue : String{
get { value }
set {
//可以用于字符串去中文
value = newValue.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
//可以用于字符串去首尾空格
//value = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
}
}

init(wrappedValue : String){
self.wrappedValue = wrappedValue
}
}

泛型

泛型是swift中的一个重要特性,使用泛型可以减少重复代码的编写,同时提高代码的通用型。结合where关键词可以提高可靠性。

1.在设计一个交换两个实例值的方法时,如果不使用泛型,将需要重复实现各个类型的方法。
如:

1
2
3
4
5
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}

2.使用泛型后,用占位符<T>代替具体的参数类型,达到一个方法可以传入多个类型的参数的目的。
如:

1
2
3
4
5
func exchange<T>(_ lhs: inout T, _ rhs: inout T) where T:Comparable{
let temp = lhs
lhs = rhs
rhs = temp
}

其中,inout关键词使得函数可以修改传入参数的值,where语句限定了方法参数的类型需要实现Comparable协议,可以自行做其他的限定。<T>仅起到占位符的作用,swift编译器不会去寻找名为T的类型,而是会自动推断出参数的类型。

关联类型

1.与泛型的作用类似,关联类型让开发者不用在第一时间指定具体的类型。但关联类型是在用协议上的。

2.在定义一个协议时,如果我们使用关联类型,形如:

1
2
3
4
5
6
protocol Container {
associatedtype ItemType
mutating func append(_ item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}

那么,Container协议可以作为任何类型的容器,只需要在实现协议时指定时便可。

3.给关联类型添加约束,只需要 associatedtype ItemType : xxx

CATALOG
  1. 1. swift
    1. 1.0.1. 常用的几个协议
    2. 1.0.2. @propertyWrapper
    3. 1.0.3. 泛型
    4. 1.0.4. 关联类型