创建: 2018/03/09
完成: 2018/03/10
更新: 2018/04/19 修改小标题 [扩张的定义与使用协议] -> [通过扩张来采用协议]
更新: 2018/09/18 标题里增加英文方面自己快速找到 [Swift4 扩张, 集合] -> [Swift4 扩张(Extenstion), 集合(Set)]
扩张的声明与定义 | |||||||||||||||||||||||||||||||||||||||||||||
扩张的概要 | 可以对类, 构造体(系统固有的数据类型都算), 枚举型, 协议进行扩张 extension 型名: 协议 { // 协议可省略, 顺序随意 构造函数 // 顺序随意 属性定义 // 除计算型实例属性 方法定义 其他定义 // 嵌套型, 索引等 }
● 可以增加以下新定义 (●) 计算型属性, 计算型和容纳型静态属性(类属性) 即除容纳型实例属性外的属性 (●) 实例方法, 静态方法(类犯法) (●) 构造函数 (●) 索引subscript (●) 嵌套型声明(嵌套型在扩张定义内部用) ● 不可增加计算型实例属性, 属性监听器({willset didset}) | ||||||||||||||||||||||||||||||||||||||||||||
系统固有型的扩张例 |
extension String { //下标数字1 static var zeroUnder: String { return "\u{2080}" } }
| ||||||||||||||||||||||||||||||||||||||||||||
扩张的定义与构造函数 | 扩张与构造函数 ● 构造体: 扩张定义的构造函数不会使构造体的默认构造函数和全项目构造函数无效 ● 类 扩张只能定义简易构造函数(带convenience), 不能定义指定构造函数 不能定义析构函数
| ||||||||||||||||||||||||||||||||||||||||||||
扩张定义与继承的注意 | ● 扩张的东西都自带final 无法被子类重载 ● 不能用扩张去重载父类属性/方法
| ||||||||||||||||||||||||||||||||||||||||||||
通过扩张来采用协议 | |||||||||||||||||||||||||||||||||||||||||||||
使用扩张来采用协议 |
class ExtensionSampleClass { // 什么都没有的空类 } protocol ExtensionSampleProtocol { // 只含一个字符串变量的协议 var sampleString: String { get } } extension ExtensionSampleClass: ExtensionSampleProtocol { // 用扩张采用协议 var sampleString: String { return "ExtensionSampleClass" } } ● 同时采用多个时用,隔开 extension SampleDataType: Protocol1, Protocol2, ... { // 多个用,隔开 ... }
| ||||||||||||||||||||||||||||||||||||||||||||
型内已有一部分/全部不定义 | 型内已有要采用的协议的一部分或全部定义时, 扩张里只需要补充缺少的. 不能改写型定义里已存在的 //内部已有一部分或全部实现 class ExtensionSampleClass2 { // 类里有sampleData var sampleData: Int = 0 } protocol ExtensionSampleProtocol2 { // 含sampleString和sampleData的协议 var sampleString: String { get } var sampleData: Int { get } } extension ExtensionSampleClass2: ExtensionSampleProtocol2 { // 只需要实现sampleString即可 var sampleString: String { return "ExtensionSampleClass" } }
| ||||||||||||||||||||||||||||||||||||||||||||
协议的扩张 | |||||||||||||||||||||||||||||||||||||||||||||
协议的扩张 | ● 可以写方法, 计算型属性, 索引subscript ● 不可以写协议里的那种声明, 和容纳型实例/静态变量 ● 主要只要协议里东西的实现, 做默认实现 ● 改写默认实现不需要override | ||||||||||||||||||||||||||||||||||||||||||||
标准库的协议已有的扩张 | 例 public protocol Equatable { // 可等协议 static func == (lhs: Self, rhs: Self) -> Bool } extension Equatable { // 扩张, 这样只需要实现==即可 public static func != (lhs: Self, rhs: Self) -> Bool { return !(lhs == rhs) } }
| ||||||||||||||||||||||||||||||||||||||||||||
协议扩张时对型附加条件 | 对协议扩张时才能附加条件 ● 可附加的条件: 附属型: 协议 表示附属型必须采用指定协议 附属型 == 型 附属型必须是指定的型(可以是typealias后的) protocol SampleProtocol { // 样本协议 associatedtype Element // 附属型 ... } extension SampleProtocol where Element: CustomStringConvertable // 附属型Element必须采用CustomStringConvertable { ... } extension SampleProtocol where Element == String { // 附属型Element必须是String型 ... }
| ||||||||||||||||||||||||||||||||||||||||||||
协议扩张的多重继承 | ● 同时采用多个协议时不能有重名属性或方法 ● 相当于其他语言的mixin, trait | ||||||||||||||||||||||||||||||||||||||||||||
集合与协议 | |||||||||||||||||||||||||||||||||||||||||||||
通过哈希值实现高速搜索 | ● 集合和数组类似, 但不能有重复 ● 集合用于不需要重复元素或者需要使用集合运算的情况 ● 采用Hashable协议 public protocol Hashable: Equatable { // 继承Equatable, 需要实现== public var hashValue: Int { get } }
| ||||||||||||||||||||||||||||||||||||||||||||
集合的声明与初始化 | 声明 var s: Set<类型> 初始化, 用数组, 有重复元素自动清除多余的 let setSample: Set<String> = ["a", "a", "b"] print("setSample.count = \(setSample.count)") // 2 也可以用init Set<Int>.init() // [] Set<Int>.init(0..<8) // Set<T>.init(sequence: Sequence)
| ||||||||||||||||||||||||||||||||||||||||||||
元素的获取 | 和数组, 哈希表, 字符串一样采用Collection(继承Sequence) 参照: 传送门 | ||||||||||||||||||||||||||||||||||||||||||||
集合运算 | 前提: 元素同型 ● 采用SetAlgebra(继承Equatable, ExpressibleByArrayLiteral) ● 主要构造函数
● 主要属性
● 主要方法 S: sequence, 集合, 数组, 范围等 T: Set<T>的T
| ||||||||||||||||||||||||||||||||||||||||||||
OptionSet协议 | OptionSet协议 protocol OptionSet: SetAlgebra, RawRepresentation { // SetAlgebra(继承Equatable, ExpressibleByArrayLiteral) // RawRepresentable协议带有rawValue, init?(rawValue:) associatedtype Element = Self init(rawValue: Self.RawValue) } RawRepresentable协议 protocol RawRepresentable { associatedtype RawValue init?(rawValue: Self.RawValue) public var rawValue: Self.RawValue { get } }
OptionSet的扩张(一部分) extension OptionSet { public func union(_ other: Self) -> Self { var r: Self = Self(rawValue: self.rawValue) // 生成self的copy r.formUnion(other) // 生成和集合, 并集, 存在于SetAlgebra协议 return r } public func intersection(_ other: Self) -> Self { ... // 省略, 和union一样 } } extension OptionSet where Element == Self { // OptionSet内部associatedtype Element = Self, 所以这里默认成立 public func contains(_ member: Self) -> Bool { return self.isSuperset(of: member) } @discardable public mutating func remove(_ member: Element) -> Element? { let r = isSuperset(of: member) ? Optional(Member) : nil self.subtract(member) // 存在于SetAlgebra协议 return r } } extension OptionSet where RawValue: FixedWidthInteger { // Int, UInt等采用FixedWidthInteger, 可以进行位运算 public init() { self.init(rawValue: 0) } public mutating func formUnion(_ other: Self) { self = Self(rawValue: self.rawValue | other.rawValue) } public mutating func formIntersection(_ other: Self) { self = Self(rawValue: self.rawValue & other.rawValue) } }
● 要想使用默认实现, 只需定义RawValue型为Int, UInt等 并放一个rawValue属性 ● 不带任何选项的实例推荐用[]来生成 ● 用法: 放置选项, 相当于C, ObjC的比特列放置选项 可以去查看是否包含某选项, 是否包含某些选项等 struct SampleOptionSet: OptionSet { // 例, 四个选项optionA, B, C, D typealias RawValue = UInt let rawValue: UInt static let optionA: SampleOptionSet = SampleOptionSet.init(rawValue: 1 << 0) static let optionB: SampleOptionSet = SampleOptionSet.init(rawValue: 1 << 1) static let optionC: SampleOptionSet = SampleOptionSet.init(rawValue: 1 << 2) static let optionD: SampleOptionSet = SampleOptionSet.init(rawValue: 1 << 3) }
| ||||||||||||||||||||||||||||||||||||||||||||