Acheron 是一组用于开发 iOS 应用程序的实用工具集合。
您可以使用 SPM 将 Acheron 集成到您的项目中。您可以将以下内容添加到您的依赖项中:
.package(url: "https://github.com/aepryus/Acheron.git", from: "1.1.0"),
或者从 Xcode 中转到File/Add Packages
并输入 URL:https://github.com/aepryus/Acheron.git
。
一个轻量级的线程安全无 SQL ORM。
一组轻量级的扩展和便捷方法,用于以编程方式布局 iOS 屏幕。它在使多个屏幕尺寸看起来相同方面特别有用。
Pen 是一组工具,可以简化 UIKit 中字体的使用。主要地,它是一个不可变对象 'Pen',它封装了所有的字体“属性”;使其易于定义和访问。可以通过 clone() 方法创建略微调整过的新 Pen。它还包括许多 Apple 类的扩展,允许直接与它们一起使用 Pen。
用法
let greenPen: Pen = Pen(font: UIFont(name: "ChicagoFLF", size: 19)!, color: UIColor.green.tint(0.7), alignment: .right)
let whitePen: Pen = greenPen.clone(color: .white)
let attString = NSMutableAttributedString()
attString.append("This is GREEN", pen: greenPen)
attString.append("This is WHITE", pen: whitePen)
let label = UILabel()
label.pen = greenPen
NSString("Hello, White Pen").draw(at: .zero, pen: whitePen)
NSString("Hello, Green Pen").draw(at: .zero, withAttributes: greenPen.attributes)
RGB 是一组工具,可以轻松获取颜色的色调、阴影和明暗度,或混合两种完全不同的颜色。它包括 RGB 类,该类将颜色转换为可以进行数学操作的向量。它还包括 UIColor 的扩展,使这些操作可以直接对 UIColor 本身进行。
用法
let lightBlue = UIColor.blue.tint(0.5)
let greyGreen = UIColor.green.tone(0.5)
let transparentPink = UIColor.red.tint(0.5).alpha(0.5)
let blueRGB = RGB(uiColor: .blue)
let redRGB = RGB(uiColor: .red)
let purpleRGB = (blueRGB + redRGB) * 0.5
let purpleRGB2 = blueRGB.blend(rgb: redRGB, percent: 0.5)
用于创建可展开表格视图的类和委托。
一个使表格数据易于显示的视图。
AepImage 是一种非常轻量级的异步图像加载和缓存工具,它嵌入到 UIImageView 中,但也可以直接从 UIImage 上的静态方法中使用。该工具确保正确处理位于 UITableViews 上的 UIImageView。它不包含磁盘缓存。
用法
imageView.loadImage(url: "https://aepryus.com/resources/aexels01s.png")
imageView.loadImage(url: "https://aepryus.com/resources/Force3.jpg", placeholder: tempImage) {
print("Image Loaded")
}
UIImage.loadImage(url: "https://aepryus.com/resources/tnEvolizer1.jpg") { (image: UIImage) in
print("already loaded")
} willLoad: {
print("will load")
} finishedLoading: { (image: UIImage) in
print("finished loading")
}
Pond and Pebbles 是一个异步控制流系统,可以极大地帮助解开复杂的异步任务,如应用程序初始化。通过 BackgroundPond,它还可以更容易地在应用程序关闭后完成异步任务。
用法
class BootPond: Pond {
lazy var needNotMigrate: Pebble = {/*...*/}()
lazy var migrate: Pebble = {/*...*/}
lazy var ping: Pebble = {
pebble(name: "Ping") { (complete: @escaping (Bool) -> ()) in
Pequod.ping { complete(true) }
failure: { complete(false) }
}
}()
lazy var loadOTID: Pebble = {
pebble(name: "Load OTID") { (complete: @escaping (Bool) -> ()) in
complete(Pequod.loadOTID() && Pequod.loadExpired())
}
}()
lazy var loadUser: Pebble = {
pebble(name: "Load User") { (complete: (Bool) -> ()) in
complete(Pequod.loadUser())
}
}()
lazy var loadToken: Pebble = {
pebble(name: "Load Token") { (complete: (Bool) -> ()) in
complete(Pequod.loadToken())
}
}()
lazy var isLocallySubscribed: Pebble = {/*...*/}()
lazy var isRemotelySubscribed: Pebble = {/*...*/}()
lazy var receiptValidation: Pebble = {/*...*/}()
lazy var userLogin: Pebble = {/*...*/}()
lazy var otidLogin: Pebble = {/*...*/}()
lazy var showOffline: Pebble = {/*...*/}()
lazy var showSubscribe: Pebble = {/*...*/}()
lazy var showSignUp: Pebble = {/*...*/}()
lazy var queryCloud: Pebble = {/*...*/}()
lazy var startOovium: Pebble = {/*...*/}()
lazy var invalid: Pebble = {/*...*/}()
// Init ============================================================================================
override init() {
super.init()
loadOTID.ready = { true }
loadToken.ready = { true }
loadUser.ready = { true }
needNotMigrate.ready = { true }
ping.ready = { true }
queryCloud.ready = { true }
migrate.ready = { self.needNotMigrate.failed }
isLocallySubscribed.ready = { self.loadToken.succeeded }
isRemotelySubscribed.ready = {
self.ping.succeeded
&& self.isLocallySubscribed.failed
}
userLogin.ready = {
self.ping.succeeded
&& self.loadToken.failed
&& self.loadUser.succeeded
}
receiptValidation.ready = {
self.ping.succeeded
&& self.loadToken.failed
&& self.loadOTID.failed
&& (self.loadUser.failed || self.userLogin.failed)
}
otidLogin.ready = {
self.ping.succeeded
&& self.loadToken.failed
&& (self.loadOTID.succeeded || self.receiptValidation.succeeded)
&& (self.loadUser.failed || self.userLogin.failed)
}
showOffline.ready = {
self.ping.failed
&& self.loadToken.failed
}
showSubscribe.ready = {
self.ping.succeeded
&& (self.receiptValidation.failed || self.isRemotelySubscribed.failed)
}
showSignUp.ready = {
self.ping.succeeded
&& self.loadToken.succeeded
&& self.loadOTID.succeeded
&& (self.isLocallySubscribed.succeeded || self.isRemotelySubscribed.succeeded)
&& self.loadUser.failed
}
startOovium.ready = {
self.loadToken.succeeded
&& self.loadOTID.succeeded
&& (self.loadUser.succeeded || self.ping.failed)
&& (self.isLocallySubscribed.succeeded || self.isRemotelySubscribed.succeeded)
&& (self.needNotMigrate.succeeded || self.migrate.succeeded)
&& self.queryCloud.succeeded
}
invalid.ready = {
self.loadToken.succeeded
&& self.loadOTID.failed
}
}
}
class ExitPond: BackgroundPond {
lazy var saveAether: Pebble = {
pebble(name: "Save Aether") { (complete: @escaping (Bool) -> ()) in
Oovium.aetherView.saveAether { (success: Bool) in
complete(success)
}
}
}()
init() {
super.init { print("ExitPond timed out without completing.") }
saveAether.ready = { true }
}
}
class OoviumDelegate: UIResponder, UIApplicationDelegate {
let bootPond: BootPond = BootPond()
let exitPond: ExitPond = ExitPond()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
bootPond.start()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
exitPond.start()
}
}
它还包括为各种异步路径编写测试的机制
XCTAssert(pond.test(shouldSucceed: [
pond.needNotMigrate,
pond.ping,
pond.queryCloud,
pond.showSubscribe,
], shouldFail: [
pond.loadOTID,
pond.loadUser,
pond.loadToken,
pond.receiptValidation,
]))
用法
let button: UIButton = UIButton()
button.addAction {
print("Hello, Acheron")
}