您是否发现本身没法理解框架或库,并但愿您能看到源代码?Apple没有共享源代码,UIKit
但若是您正在努力理解的方法是Swift标准库的一部分,那么您很幸运。git
Apple在公共GitHub存储库中发布Swift编程语言的源代码,包括标准库:github
您可能会发如今GitHub上浏览存储库已足以快速查看但我喜欢克隆并下载本地副本:编程
$ mkdir swift-source
$ cd swift-source/
$ git clone https://github.com/apple/swift.git
Cloning into 'swift'...
remote: Enumerating objects: 915646, done.
remote: Total 915646 (delta 0), reused 0 (delta 0), pack-reused 915646
Receiving objects: 100% (915646/915646), 415.74 MiB | 6.42 MiB/s, done.
Resolving deltas: 100% (742664/742664), done.
Checking out files: 100% (16802/16802), done.
复制代码
您能够将swift
文件夹放入Xcode项目中进行浏览,但这会使个人Mac旋转沙滩球几分钟。我更喜欢用BBEdit打开文件夹,它既快又有更好的多文件搜索工具。swift
您将在core
子目录中找到标准库的源代码:bash
$ cd swift/stdlib/public/core
复制代码
值得花时间浏览源代码。我发现它有很好的记录和信息。让咱们看一个源代码有助于咱们理解的示例。app
String
我最近写了关于在Swift中测试空字符串的文章。在那篇文章中,我声称你应该使用isEmpty
而不是count
避免迭代整个字符串。一位读者问我这是否是真的?个人说法来自String
文件:框架
要检查字符串是否为空,请使用其isEmpty属性,而不是将其中一个视图的长度与0进行比较。与isEmpty不一样,计算视图的count属性须要迭代字符串的元素。dom
咱们能比信任文档更好吗?咱们可使用标准库源代码来查看字符串的工做方式isEmpty
和count
工做方式吗?编程语言
在标准库源代码中查找的位置并不老是很明显。搜索core
目录最终会带您到正确的地方,但也能够带走一些兔子洞。有一个String.swift
文件,但它不包含任何一个isEmpty
或count
。工具
回想一下个人Swift String备忘单,您可能还记得Swift 4将字符串的默认视图设置为一组字符。目录中有一个StringCharacterView.swift
文件core
扩展String
为采用BidirectionalCollection
协议:
// StringCharacterView.swift
extension String: BidirectionalCollection {
复制代码
在StringCharacterView
没有定义isEmpty
,但咱们发现count
:
public var count: Int {
return distance(from: startIndex, to: endIndex)
}
复制代码
该distance
方法调用咱们仍须要查找的内部方法,但它是一个开始:
public func distance(from start: Index, to end: Index) -> IndexDistance {
return _distance(from: start, to: end)
}
复制代码
双向集合扩展了集合,以在集合上添加向后遍历:
// BidirectionalCollection.swift
public protocol BidirectionalCollection: Collection
where SubSequence: BidirectionalCollection, Indices:
BidirectionalCollection {
复制代码
这是咱们找到实现的地方,_distance
而且能够看到它对集合进行迭代(向前或向后):
internal func _distance(from start: Index, to end: Index) -> Int {
var start = start
var count = 0
if start < end {
while start != end {
count += 1
formIndex(after: &start)
}
}
else if start > end {
while start != end {
count -= 1
formIndex(before: &start)
}
}
return count
}
复制代码
让咱们继续前进,看看可否找到isEmpty
。
该Collection
协议的基础上Sequence
,并增长了startIndex
和endIndex
朋友与咱们共同的属性isEmpty
和count
:
// Collection.swift (details omitted)
public protocol Collection: Sequence {
var startIndex: Index { get }
var endIndex: Index { get }
var isEmpty: Bool { get }
var count: Int { get }
复制代码
源代码中的注释为咱们提供了更多提示:
对于不符合的集合
RandomAccessCollection
,访问该count
属性会迭代集合的元素。
由于count
有这个警告:
复杂性:O(1)若是集合符合
RandomAccessCollection
; 不然,O(n),其中n是集合的长度。
评论确认了咱们的理解,String
但也告诉咱们为何会这样。重要的是该系列是否符合RandomAccessCollection
。相似的类型Array
容许随机访问,但String
不容许。有关完整列表,请参阅RandomAccessCollection。
在Collection.swift
文件的下方,咱们找到了一个协议扩展,它最终为咱们提供了如下的默认实现isEmpty
:
public var isEmpty: Bool {
return startIndex == endIndex
}
复制代码
因此对于a String
,咱们最好isEmpty
不要使用而不是count
。