Skip to content

Instantly share code, notes, and snippets.

View rnapier's full-sized avatar

Rob Napier rnapier

View GitHub Profile
@rnapier
rnapier / json.swift
Last active January 31, 2024 12:49
Generic JSON Decodable
import Foundation
@dynamicMemberLookup
enum JSON: Codable, CustomStringConvertible {
var description: String {
switch self {
case .string(let string): return "\"\(string)\""
case .number(let double):
if let int = Int(exactly: double) {
return "\(int)"
@rnapier
rnapier / error-propagation.swift
Last active April 27, 2017 14:01 — forked from nicklockwood/error-propagation.swift
Typed error use-case example
// I know you meant it to be exaggerated, but I still think this is the better approach in practice:
enum ClassError: Error {
case propertyNotFound(name: String)
case typeMismatch(propertyName: String)
}
class Foo {
var properties: [(String, Any)] = []
private func validateValue(_ value: Any, for property: String) throws { // Note that I pass the name just for the error; that's ok IMO
public typealias JSON = [String:Any]
public enum JSONInitializableError: Error {
case initializationError(key: String)
}
public protocol JSONInitializable {
associatedtype Key: RawRepresentable
init(with json: JSON) throws
}
@rnapier
rnapier / doOnce.swift
Last active April 20, 2022 16:12
A function that only executes once. Good Swift or over-clever?
// Swift3 gets rid of dispatch_once and recommends replacing it with a lazy global.
// That's very straightforward when dispach_once is used to initialize something, but
// isn't an exact match when you want something to execute once, and then become a noop
// in a thread-safe way.
// The following approach seems completely "correct" and I guess actually a bit elegant,
// if by "elegant" you mean "terse and not immediately obvious to the reader, which makes
// you look very clever."
var doOnce: () -> Void = {
// A value that can be expressed as some Double amount of a unit. In general you should not use
// .doubleUnitValue except for generic algorithms, since this loses what the double represents.
// For example, in a Mass, you would prefer .kilogramValue rather than .doubleUnitValue so that
// it's clear in the code that this is in kg, and not grams or pounds or something else.
protocol DoubleUnit: Comparable {
init(doubleUnitValue: Double)
var doubleUnitValue: Double { get }
}
func == <T: DoubleUnit>(lhs: T, rhs: T) -> Bool {
@rnapier
rnapier / layout.swift
Last active January 7, 2018 18:40
Flow layout using intrinsic size of cells
// FIXME: This seems unnecessary. My cells define an intrinsicContentSize, which I thought would be used by the flow layout
// but this is the only way I've been able to get it to be honored. I feel I'm missing something with auto-sizing cells.
extension TypeGeneratorViewController: NSCollectionViewDelegateFlowLayout {
public func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
let cell = ForwardedProtocolItem()
cell.representedObject = protocols[indexPath.item]
return cell.view.intrinsicContentSize
}
}
@rnapier
rnapier / pointvector.swift
Created September 14, 2016 17:07
Point and vector operations
// Vectors can be inverted
private prefix func - (operand: CGVector) -> CGVector {
return CGVector(dx: -operand.dx, dy: -operand.dy)
}
// Vectors can be added and subtracted
private func + (lhs: CGVector, rhs: CGVector) -> CGVector {
return CGVector(dx: lhs.dx + rhs.dx, dy: lhs.dy + rhs.dy)
}
private func - (lhs: CGVector, rhs: CGVector) -> CGVector {
func tomorrowsDateString(dateString: String) -> String? {
if let date = dateFormatter.date(from: dateString),
let newDate = calendar.date(byAdding: oneDayOffset, to: date) {
return dateFormatter.string(from: newDate)
}
return nil
}
// This is primarily for bridging strong types into and out of Core Data which relies on NSNumber.
protocol NumberConvertible: CustomStringConvertible, Comparable {
init(number: NSNumber)
var numberValue: NSNumber { get }
}
// CustomStringConvertible
extension NumberConvertible {
var description: String { return numberValue.description }
@rnapier
rnapier / random.swift
Last active April 13, 2018 01:11
Random numbers in Swift
import Darwin
extension Integer {
static func makeRandomValue() -> Self {
var result: Self = 0
withUnsafeMutablePointer(&result) { resultPtr in
arc4random_buf(UnsafeMutablePointer(resultPtr), sizeof(Self.self))
}
return result
}