Skip to content

Instantly share code, notes, and snippets.

View JohnSundell's full-sized avatar

John Sundell JohnSundell

View GitHub Profile
@JohnSundell
JohnSundell / Autoclosure.swift
Created January 19, 2017 15:00
Simple Dictionary extension to avoid the if let-dance when retrieving values
extension Dictionary {
mutating func value(for key: Key, orAdd closure: @autoclosure () -> Value) -> Value {
if let value = self[key] {
return value
}
let value = closure()
self[key] = value
return value
}
@JohnSundell
JohnSundell / TestingMemoryManagement.swift
Created January 25, 2017 11:15
Sample on how you can easily test your memory management in Swift
class Cache<T> {
private lazy var objects = [String : T]()
func object(forKey key: String) -> T? {
return objects[key]
}
func addObject(_ object: T, forKey key: String) {
objects[key] = object
}
@JohnSundell
JohnSundell / WrappingSingletons.swift
Last active October 26, 2017 18:23
This is a great technique if you need to interact with singleton-based APIs but still have great testability
import UIKit
// Create a protocol that defines what APIs that you need from the singleton
protocol Application {
func open(url: URL)
}
// Make the singleton-based class conform to your protocol
extension UIApplication: Application {
func open(url: URL) {
@JohnSundell
JohnSundell / Perform.swift
Last active December 21, 2019 14:43
A function that enables you to easily wrap throwing APIs, to provide a custom error
/**
* Perform a throwing expression, and throw a custom error in case the expression threw
*
* - parameter expression: The expression to execute
* - parameter error: The custom error to throw instead of the expression's error
* - throws: The given error
* - returns: The return value of the given expression
*/
func perform<T>(_ expression: @autoclosure () throws -> T, orThrow errorExpression: @autoclosure () -> Error) throws -> T {
do {
@JohnSundell
JohnSundell / AssertThrowsError.swift
Created February 19, 2017 13:36
A function that asserts that an expression throws a given error
/**
* Copyright (c) John Sundell 2017
* Licensed under the MIT license
*/
import Foundation
import XCTest
/**
* Assert that an expression throws a given error
@JohnSundell
JohnSundell / OnboardingManager.swift
Last active May 21, 2020 08:19
An example of using #function for user defaults properties, and a test that guards against property name changes
import UIKit
class OnboardingManager {
private let userDefaults: UserDefaults
init(userDefaults: UserDefaults = .standard) {
self.userDefaults = userDefaults
}
func presentOnboardingControllerIfNeeded(in viewController: UIViewController) {
func loadSearchData(matching query: String) throws -> Data {
let urlString = "https://my.api.com/search?q=\(query)"
guard let url = URL(string: urlString) else {
throw SearchError.invalidQuery(query)
}
return try Data(contentsOf: url)
}
func loadSearchData(matching query: String) throws -> Data {
let urlString = "https://my.api.com/search?q=\(query)"
guard let url = URL(string: urlString) else {
throw SearchError.invalidQuery(query)
}
do {
return try Data(contentsOf: url)
} catch {
func perform<T>(_ expression: @autoclosure () throws -> T,
orThrow error: Error) throws -> T {
do {
return try expression()
} catch {
throw error
}
}
func loadSearchData(matching query: String) throws -> Data {
let urlString = "https://my.api.com/search?q=\(query)"
guard let url = URL(string: urlString) else {
throw SearchError.invalidQuery(query)
}
return try perform(Data(contentsOf: url),
orThrow: SearchError.dataLoadingFailed(url))
}