Skip to content

Instantly share code, notes, and snippets.

View aidaan's full-sized avatar

Aidan Dysart aidaan

View GitHub Profile
import Foundation
extension NSObject {
/// A publisher for observing key-value changes when static swift KeyPaths are not available, such as when observing
/// `UserDefaults`. With this publisher only a `String` based keypath is required.
///
/// Since this does not use static typed keypaths, we can not ensure that the value received from KVO is the type we
/// expect. So values that can not be converted to the expected value are ignored.
public struct StringKeyPathObservingPublisher<Value>: Publisher {
public typealias Output = Value
@aidaan
aidaan / SectionTitledDiffableDataSource.swift
Created May 3, 2020 22:51
A UITableViewDiffableDataSource subclass with support for section titles
import UIKit
open class SectionTitledDiffableDataSource<SectionIdentifierType, ItemIdentifierType>: UITableViewDiffableDataSource<SectionIdentifierType, ItemIdentifierType>
where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable {
public typealias SectionTitleProvider = (UITableView, SectionIdentifierType) -> String?
open var sectionTitleProvider: SectionTitleProvider?
open var useSectionIndex: Bool = false
@aidaan
aidaan / CATransaction+Closure.swift
Created February 10, 2019 22:32
Closure based CATransaction API
import UIKit
// I'm not sure how useful this is, but swift allows for a somewhat elegant closure base API for CATransation.
// Each argument if optional, so it can be omitted unless necessary. It's a little weird having the completion
// block come before the actions block, but this way the actions block can make sure of trailing closure syntax.
extension CATransaction {
static func transaction(duration: CFTimeInterval? = nil,
timingFunction: CAMediaTimingFunction? = nil,
disableActions: Bool? = nil,
completion: (() -> Void)? = nil,
@aidaan
aidaan / KeyedDecodingContainer+Extensions.swift
Last active September 23, 2018 15:08
Some useful extensions to KeyedDecodingContainer
extension KeyedDecodingContainer {
/// Some poorly designed APIs return JSON where the type is enclosed in quotes, which means it is interpreted as a String.
/// These two methods will attempt to decode the supplied type conforming to LosslessStringConvertible by first decoding the String
/// and then converting to the supplied type.
func decodeFromString<T>(_ type: T.Type, forKey key: K) throws -> T where T : LosslessStringConvertible {
let string = try decode(String.self, forKey: key)
guard let value = T(string) else {
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "decodeFromString failed")
}