Swiftpack.co - EricRabil/Swexy as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by EricRabil.
EricRabil/Swexy 1.0.12
Foundation extensions I always write in projects
⭐️ 0
🕓 3 weeks ago
iOS macOS watchOS tvOS
.package(url: "https://github.com/EricRabil/Swexy.git", from: "1.0.12")

Swexy

Swift, but Sexy.

Motivation

Swift Foundation leaves a lot to be desired. You often have to write tons and tons of boilerplate, and don't get me started on the Codable system.

Swexy includes common extension patterns I find myself writing across projects, and I hope others can find value in them.

Current Extensions

  • KeyPath-based reducing into dictionaries, with support for compactMap-style omission of optional keys/values ([(abc: 123, def: "ghi")].dictionary(keyedBy: \.def, valuedBy: \.abc))
  • Sorting an array by a KeyPath ([Person].sorted(usingKey: .age, by: >), [Person].sorted(usingKey: .age, withDefaultValue: 0, by: >)
  • Flatten a collection of collections into an array of its elements (Collection.flatten())
  • Anonymous Coding

Anonymous Coding

Sometimes – no, not sometimes, many times – you run into data structures that either cannot be made codable because they reside in another module, or require significant boilerplate to write codable conformance for.

Swexy adds two new methods:

public extension JSONEncoder {
    func encode(_ cb: @escaping (Encoder) throws -> ()) throws -> Data
}
public extension JSONDecoder {
    func decode<P>(data: Data, _ cb: @escaping (Decoder) throws -> P) throws -> P
}

These allow you to quickly encode and decode datatypes without hacking in extensions. For instance, you cannot conform an external structure to a protocol, so making it codable requires some wrappers that get a bit hairy.

Here's an example:

Somewhere in another module

struct MyArbitraryUncodableStruct {
    let aBool: Bool
    let aInt: Int
}

Your code

let instance = MyArbitraryUncodableStruct(aBool: true, aInt: 54)

enum UncodableCodingKeys: CodingKey {
    case aBool, aInt
}
    
let data = try JSONEncoder().encode { encoder in
    var container = encoder.container(keyedBy: UncodableCodingKeys.self)
    
    try container.encode(instance.aBool, forKey: .aBool)
    try container.encode(instance.aInt, forKey: .aInt)
}

let parsed = try JSONDecoder().decode(data: data) { decoder -> MyArbitraryUncodableStruct in
    let container = try decoder.container(keyedBy: UncodableCodingKeys.self)
    
    return MyArbitraryUncodableStruct(
        aBool: try container.decode(Bool.self, forKey: .aBool),
        aInt: try container.decode(Int.self, forKey: .aInt)
    )
}

print(data)
print(String(decoding: data, as: UTF8.self))
print(parsed.aBool)
print(parsed.aInt)

It should be noted that this should be avoided wherever possible, but I personally prefer it over writing messy coding systems for things like associated-value enums.

GitHub

link
Stars: 0
Last commit: 3 weeks ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Release Notes

Added an Atomic property wrapper
3 weeks ago

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics