{"id":17259802,"url":"https://github.com/harley-xk/comet","last_synced_at":"2025-07-19T10:12:33.375Z","repository":{"id":56906385,"uuid":"73058335","full_name":"Harley-xk/Comet","owner":"Harley-xk","description":"iOS 项目的 Swift 基础库，提供常用组件、便利方法等。支持 Swift 3.x、Swift 4.x，iOS 8.0+","archived":false,"fork":false,"pushed_at":"2020-10-10T06:02:15.000Z","size":1142,"stargazers_count":51,"open_issues_count":0,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-13T04:20:17.021Z","etag":null,"topics":["base-library","components","swift","utils"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Harley-xk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-07T08:40:10.000Z","updated_at":"2023-11-12T23:36:04.000Z","dependencies_parsed_at":"2022-08-21T03:50:10.553Z","dependency_job_id":null,"html_url":"https://github.com/Harley-xk/Comet","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harley-xk%2FComet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harley-xk%2FComet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harley-xk%2FComet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Harley-xk%2FComet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Harley-xk","download_url":"https://codeload.github.com/Harley-xk/Comet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248831355,"owners_count":21168456,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["base-library","components","swift","utils"],"created_at":"2024-10-15T07:46:12.140Z","updated_at":"2025-04-14T06:23:48.581Z","avatar_url":"https://github.com/Harley-xk.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ![Comet](Images/img_0.png) Comet\n\n[![CI Status](http://img.shields.io/travis/Harley-xk/Comet.svg?style=flat)](https://travis-ci.org/Harley-xk/Comet)\n[![Version](https://img.shields.io/cocoapods/v/Comet.svg?style=flat)](http://cocoapods.org/pods/Comet)\n[![Language](https://img.shields.io/badge/language-Swift%204-orange.svg)](https://swift.org)\n[![codebeat badge](https://codebeat.co/badges/f5e29594-b882-4f7f-af50-c36407efab7f)](https://codebeat.co/projects/github-com-harley-xk-comet-master)\n[![License](https://img.shields.io/cocoapods/l/Comet.svg?style=flat)](http://cocoapods.org/pods/Comet)\n[![Platform](https://img.shields.io/cocoapods/p/Comet.svg?style=flat)](http://cocoapods.org/pods/Comet)\n\niOS 项目的 Swift 基础库，提供大量常用组件、便利方法等。支持 **Swift 3.0+**。\n1.0.0 起支持 Swift 4.x，需要支持 Swift 3.x 请使用 0.7.5 版本。\n1.5.0 起支持 Swift 4.2， 需要支持 Swift 4.0/4.1 请指定 1.4.1 版本。\n\n## 安装\n\n### 支持 CocoaPods 安装：\n\n```ruby\n# for swift 4.2\npod 'Comet'\n# for swift 4.0/4.1\npod 'Comet', :git =\u003e 'https://github.com/Harley-xk/Comet.git, :tag=\u003e1.4.1'\n# for swift 3.1/3.2\npod 'Comet', :git =\u003e 'https://github.com/Harley-xk/Comet.git, :tag=\u003e0.7.5'\n```\n\n### 支持 Swift Package Manager\n\n将 Comet 添加到 Package.swift 的 dependencies 中：\n\n```swift\ndependencies: [\n   // ...\n   .package(url: \"https://github.com/Harley-xk/Comet.git\", .upToNextMinor(from: \"1.6.0\")),\n   // ...\n],\n```\n\n## API 清单\n\n### 工具类\n\n#### 1. KeyboardPlacehoder —— 键盘占位符\n\n键盘输入是几乎每个 App 都要涉及到的内容，当输入框获得焦点，虚拟键盘弹出时，需要动态调整界面 UI 布局以适应新的界面尺寸。一般做法是通过在视图控制器中监听键盘的弹出隐藏等事件通知，根据不同的状态进行 UI 调整处理。当有多个甚至大量的界面需要处理内容输入时，需要在每个视图控制器中实现几乎相同的代码逻辑，繁琐又耗时。**键盘占位符**就是专门用来应对这个问题的。\n\n原理：\n\n**键盘占位符**就是键盘弹出后在实际试图中的映射。开发时只需要将占位符添加到任意视图中，设置其他视图的相对位置；当键盘弹出或者收起（任意键盘尺寸、位置发生改变）时，占位符将会自动调整自身的高度，保证实际尺寸和位置与键盘在占位符父视图中的投影相一致。\n\n_*键盘占位符相比于原来的键盘管理器更加方便使用，推荐使用新的占位符方式处理键盘事件，键盘管理器后期将会被废除*_\n\n#### ~~2. HairLine —— 极细的线？（已废除）~~\n\n#### 3. Path —— 路径\n\n文件读写是大多数 App 或多或少需要涉及的内容，路径类主要用于快速获取设备的各种文件及文件夹路径。 **Path** 类的本质是对路径字符串的封装，在此基础上提供额外的简便操作方法。详细可以查看 **Path** 类的方法注释\n\n#### 4. CollectionGrouper\n\n1.6 新增 `CollectionGrouper` 集合分组工具类，可以对集合进行指定元素属性进行分组，也可以通过自定义分组规则实现自定义分组，详细参考 “Grouper Sample” 实例。\n\n#### ~~4. PinyinIndexer —— 拼音索引器（即将废除）~~\n\n**_即将废除，新增的 `CollectionGrouper` 可以实现拼音分组需求以及更多其他自定义需求，专门的拼音索引器会在将来移除_**\n\n遇到列表类需求时（比如联系人列表），往往需要将列表的内容按照拼音首字母进行索引排序，这是一个简单但又繁琐的工作，因此**拼音索引器**诞生了。\n\n用法：\n\n1. 创建需要进行索引的对象数组。~~因为索引器在获取属性时使用了 **_KVC_** 的方式来获取对象对应属性的值，因此要求数据对象必须是 NSObject 的子类。~~\n\n   0.5 及以上版本更新使用协议来实现，不再要求继承 NSObject，参见第 5 点。\n\n2. 创建拼音索引器，构造函数需要两个参数：**_对象数组_** 和索引所依据的 **_属性键值_**。\n3. 索引器创建时会直接进行索引任务，对大量数据进行索引时考虑到性能问题，不建议在主线程处理。\n4. 索引器创建完成后，可以通过 **_indexedObjects_** 和 **_indexedTitles_** 属性获得索引的结果\n\n   - **_indexedObjects_** 是一个二维数组，其中是根据索引顺序排序好的对象数组\n   - **_indexedTitles_** 是索引后的拼音首字母的数组\n\n5. 0.5.0 更新：使用协议的方式代替 KVC，解除了数据对象必须为 NSObject 子类的限制。使用时，声明数据类实现`PinyinIndexable`协议，然后通过`var valueToPinyin: String { get }`这个协议方法，返回需要转换为拼音的属性即可。\n\n#### 5. TaskRecorder —— 任务记录器\n\nApp 的基本功能就是执行各种任务，比如网络任务。正常情况下，发起的任务都能执行完毕并返回结果。在某些情况下，任务并不能或者没有必要执行完毕。比如在一个视图控制器中发起了一个网络请求来获取数据，以显示在当前界面上；但是在请求执行完毕之前，用户操作退出了该界面，此时往往没有必要再继续执行这个请求，因此需要程序作出处理，取消这个网络任务的执行。当一个界面中的网络任务较多时，手动处理这些逻辑就会变得繁琐且容易出错。\n通过任务记录器可以将发起的任务关联到某个对象，并且在这个对象被销毁时，任务纪录器会将所有已纪录并且还没有执行完毕的任务都取消并销毁。\n\n用法：\n\n1. 需要被纪录的任务都必须实现 _TaskProtocol_ 协议，只需要实现一个简单的 _cancel_ 方法\n2. 对需要关联的对象调用 _record(task:)_ 方法，并将需要纪录的任务作为参数传入，就会自动创建一个记录器并关联到该对象\n3. 对象销毁时记录器会自动执行逻辑，对未完成的任务调用 _cancel_ 方法并将其销毁\n\n#### 6. Utils —— 通用工具类\n\n主要提供一些设备相关的工具方法，例如获取设备型号、系统版本、拨打电话等。详情参见 **Utils** 类的方法注释\n\n### 扩展\n\n#### 1. Date —— 日期类扩展\n\n日期类扩展提供快速操作日期的一些方法：\n\n1. **通过日期字符串创建日期对象**\n\n   ```swift\n   public init?(string: String, format: String = \"yyyy-MM-dd HH:mm:ss\", timeZone: TimeZone = TimeZone.current)\n   ```\n\n   _string_ - 日期字符串\n\n   _format_ - 日期的格式，默认为\"yyyy-MM-dd HH:mm:ss\"\n\n   _timeZone_ - 时区，默认为设备当前设置的时区\n\n   _将 local 参数替换为 timeZone_\n\n2) **将日期转换为指定格式的字符串**\n\n   ```swift\n   public func string(format: String = \"yyyy-MM-dd HH:mm:ss\", timeZone: TimeZone = TimeZone.current) -\u003e String\n   ```\n\n   _format_ - 指定的字符串格式\n\n   _timeZone_ - 时区，默认为设备当前设置的时区\n\n   _将 local 参数替换为 timeZone_\n\n3) **日期计算**\n\n   ```swift\n   public func add(_ value: Int, _ unit: DateUnit) -\u003e Date\n   ```\n\n   返回当前日期加上指定单位值之后的日期，会自动进位或减位\n\n   例如：10 月 30 日加上两天后会变成 11 月 1 日\n\n   _value_ - 对应单位的值\n\n   _unit_ - 计算的单位\n\n4) **日期设定**\n\n   ```swift\n   public func set(_ unit: DateUnit, to value: Int) -\u003e Date\n   ```\n\n   将指定单位设置为指定的值，返回修改后的新日期\n\n   如果设置的值大于当前单位的最大值或者小于最小值，会自动进位或减位\n\n   _unit_ - 设置的单位\n\n   _value_ - 设置的值\n\n5) **忽略精确时间（时／分／秒）的日期**\n\n   ```swift\n   public var withoutTime: Date\n   ```\n\n   有时候进行日期计算需要以天为最小单位，忽略具体的时间。该属性可以获取该日期当天零点的时间对象\n\n6) **获取指定日期组件的值**\n\n   ```swift\n   public func unit(_ unit: DateUnit) -\u003e Int\n   ```\n\n   通过设置单位，可以获取某个日期的年、月、日等单个单位的值\n\n7) **一周中的时间**\n\n   ```swift\n   public var weekday: Int\n   ```\n\n   获取某个日期是一周中的第几天，即周几\n\n   **注：周日为一周的第一天，从 0 开始，周一为 1，依此类推**\n\n#### 2. String —— 字符串扩展\n\n1.  **拼音**\n\n    ```swift\n    public func pinyin(_ type: PinyinType = .normal) -\u003e String\n    ```\n\n    获取指定类型的拼音\n\n    - normal - 默认不带声调的全拼\n\n    - withTone - 带声调的全拼\n\n    - firstLetter - 拼音首字母\n\n2.  **Base64 编码／解码**\n    `swift public var base64Decode: String? public var base64Encode: String?`\n\n3.  **RegEx 正则表达式**\n\n    ```swift\n    /// 常用正则表达式\n    // 邮箱\n    public var regex_email: String\n    // 电话号码\n    public var regex_phone: String\n    // 手机号码\n    public var regex_mobile: String\n\n    /// 判断是否匹配正则表达式\n    public func match(regex: String) -\u003e Bool\n    /// 判断是否是邮箱\n    public var isEmail: Bool\n    /// 判断是否是电话号码\n    public var isPhone: Bool\n    /// 判断是否是手机号码\n    public var isMobile: Bool\n    /// 同时验证电话和手机\n    public var isPhoneOrMobile: Bool\n    ```\n\n4.  **URL**\n\n        \t```swift\n        \t// URL 编码\n        \tpublic var URLEncode: String?\n        \t// URL 解码\n\n    public var URLDecode: String?\n\n    ```\n\n    ```\n\n5.  **计算大小**\n\n    ```swift\n    public func width(limitToHeight height: CGFloat, font: UIFont) -\u003e CGFloat\n    public func height(limitToWidth width: CGFloat, font: UIFont) -\u003e CGFloat\n    public func size(limitToSize size: CGSize, font: UIFont) -\u003e CGSize\n    ```\n\n    根据限定的高或者宽度，计算另一项的值\n\n#### 3. UIColor\n\n1. **16 进制颜色**\n\n   ```swift\n   public convenience init?(hex: String, alpha: CGFloat = 1)\n   ```\n\n   用 16 进制颜色代码创建 UIColor 对象，字符串可以是 0xaaaaaa、#aaaaaa、aaaaaa 三种格式中的任何一种\n\n#### 4. UIResponder\n\n1.  **解除任何第一响应者**\n\n        \t```swift\n\n    public class func resignAnyFirstResponder()\n\n    ```\n    通过该方法可以不需要指定任何对象，直接将当前任何处于第一响应者状态的控件解除该状态\n\n    ```\n\n2.  **在 IB 中设置 - 解除第一响应者**\n\n        \t```swift\n\n    @IBAction public func autoResignFirstResponder()\n\n    ```\n    在 IB 中，将特定事件指派到 FirstResponder 上的 _autoResignFirstResponder_ 方法，可以在事件触发后解除当前第一响应者状态的操作，如图：\n\n     \u003cimg src=\"Images/img_1.png\" width=\"430\" height=\"400\"\u003e\n    ```\n\n3)  **在 IB 中设置 - 指定第一响应者**\n\n        \t```swift\n\n    @IBAction public func autoBecomFirstResponder()\n\n    ```\n    在 IB 中，将特定事件指派到输入框的 _autoBecomFirstResponder_ 方法，可以在事件触发后使指定控件成为第一响应者，如图：\n    \u003cimg src=\"Images/img_2.png\" width=\"430\" height=\"345\"\u003e\n    ```\n\n#### 5. UIView\n\n1.  **在 IB 中快速设置属性**\n\n        \t```swift\n\n    @IBInspectable var cornerRadius: CGFloat // 边角半径\n    @IBInspectable var borderWidth: CGFloat // 边框宽度\n    @IBInspectable var borderColor: UIColor? // 边框颜色\n\n    ```\n    这些声明实现了直接在 IB 中设置 UIView 相关属性的功能：\n\n        \t\u003cimg src=\"Images/img_3.png\" width=\"265\" height=\"220\"\u003e\n    ```\n\n#### 6. UIStoryboard\n\n1. **获取 Storyboard**\n   `swift // 获取创建项目时自动创建的 Main Stroyboard public class var main: UIStoryboard // 根据名称从 MainBundle 中创建 Storyboard public convenience init(_ name: String = \"Main\") {`\n2. **创建视图控制器**\n\n   ```swift\n   public func create\u003cT: UIViewController\u003e(identifier: String? = nil) -\u003e T\n   ```\n\n   该方法可以从 Storyboard 创建指定的视图控制器实例，_identifier_ 为 IB 中设置的视图控制器 ID。\n\n   _identifier_ 可以省略，此时要求 IB 中设置的 ID 为 视图控制器的类名，此时写法如下：\n\n   ```swift\n   let controller = UIStoryboard(\"Auth\").create() as LoginViewController\n   ```\n\n3. **入口视图控制器**\n\n   ```swift\n   public var initial: UIViewController?\n   `\n   例\n\n   ```\n\n#### 7. GCD 扩展\n\n扩展几个 GCD 方法以更方便地调用 GCD 的延迟函数\n\n```swift\npublic func asyncAfter(delay: DispatchTimeInterval, execute work: @escaping @convention(block) () -\u003e Swift.Void)\n\npublic func asyncAfter(delay seconds: TimeInterval, execute work: @escaping @convention(block) () -\u003e Swift.Void)\n\npublic func asyncAfter(delay: DispatchTimeInterval, execute: DispatchWorkItem)\n\npublic func asyncAfter(delay seconds: TimeInterval, execute: DispatchWorkItem)\n```\n\n示例：\n\n```swift\nDispatchQueue.global().asyncAfter(delay: 2) {\n\tprint(\"延迟两秒执行\")\n}\n\nDispatchQueue.global().asyncAfter(delay: .nanoseconds(2)) {\n\tprint(\"延迟两纳秒执行\")\n}\n```\n\n#### 8. KVO \u0026 闭包\n\nKVO 是 Foundation 框架强大的功能之一，但是由于不支持闭包，导致实现起来比较繁琐。注册和实际处理的代码需要写在不同的地方，对于一些轻量级的逻辑来说并不十分友好。\n\n通过 NSObject+KVOHandler 扩展，可以在注册 KVO 观察者时直接提供一个闭包来实现了。比如下面的代码实现了观察 ScrollView 的 contentOffset 的变化，可以比较一下原来的实现方式和闭包形式的实现方式。\n\n原来的实现：\n\n```swift\noverride func viewDidLoad() {\n    super.viewDidLoad()\n\n    scrollView.addObserver(self, forKeyPath: \"contentOffset\", context: nil)\n}\n\noverride func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {\n    if keyPath == \"contentOffset\" {\n        // Do something\n    }\n}\n```\n\n使用闭包实现：\n\n```swift\noverride func viewDidLoad() {\n    super.viewDidLoad()\n\n    scrollView.addObserver(for: \"contentOffset\") { (_, _, _) in\n        // Do something\n    }\n}\n```\n\n### 移除\n\n1. 移除 MD5 编码、RC4 加密等相关内容。推荐使用更加成熟的加密框架： [CryptoSwift](https://github.com/krzyzanowskim/CryptoSwift)，支持更广泛的加密协议。\n2. 移除 HKUserDefaults。RC4 属于已过时的加密方式，随着 RC4 加密的移除将 KUserDefaults 一并移除了，有加密需求推荐使用更成熟的第三方加密框架。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharley-xk%2Fcomet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharley-xk%2Fcomet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharley-xk%2Fcomet/lists"}