Skip to content

Instantly share code, notes, and snippets.

View Winchariot's full-sized avatar

Jim G Winchariot

  • Austin, TX
View GitHub Profile
@Winchariot
Winchariot / iPhoneModel.swift
Created October 22, 2019 19:57
Determine iPhone model... ish
//Phone model is not provided officially by any Cocoa API.
//It can be narrowed down to a few different models by checking the screen dimensions, but this shouldn't be relied upon
// and should NEVER drive any business logic.
//A good use for such knowledge is for something like error logging.
//https://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
static var iPhoneModel: String? {
guard UIDevice().userInterfaceIdiom == .phone else { return nil }
switch UIScreen.main.nativeBounds.height {
case 1136:
@Winchariot
Winchariot / .gitignore
Last active October 8, 2019 18:52
iOS template gitignore
#if using Cocoapods
Pods/
#if using bundler to manage Cocoapods version
.bundle
vendor/
.DS_Store
.idea
*.swp
@Winchariot
Winchariot / KeyboardAccessoryView.swift
Last active November 22, 2023 14:26
UIToolbar with a right-aligned "Done" button, for use as a keyboard accessory view
lazy var accessoryToolbarWithDoneButton: UIToolbar = {
let toolbar = UIToolbar(frame: CGRect.zero)
//only needs to be flexible in the dimension(s) you want it to be
//https://stackoverflow.com/questions/31822504/how-can-i-increase-the-height-of-an-inputaccessoryview
toolbar.autoresizingMask = [.flexibleWidth, .flexibleHeight]
let leftSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(keyboardDoneButtonTapped(_:)))
toolbar.items = [leftSpace, doneButton]
@Winchariot
Winchariot / CompositeViewController.swift
Created September 27, 2019 16:46
VC Containment / Child View Controller hierarchy
import UIKit
//I represent a screen in my app that is relatively complicated. Suppose I'm a sort of scrollable activity feed in a financial app;
// I may have sections for balances, alerts, recent activity, credit score, a financial checkup quiz, etc.
// Separating those sections into their own child VCs is great for splitting up the workload and separating the code.
// Then I, the parent VC, can easily compose my feed using any subset of these child VCs and in any order using view controller containment.
class CompositeViewController: UIViewController {
private let scrollView: UIView?
@Winchariot
Winchariot / ValueMaker.swift
Created September 27, 2019 16:16
Generic interface to service that can return many different types
//I am some 3P service. I can be asked for many different types of values.
class ValueMaker {
static func makeBool() -> Bool { return true }
static func makeInt() -> Int { return 3 }
}
//I am a 1P abstraction over that service.
// I want to save effort in the rest of my codebase by exposing 1 func for getting values,
// instead of needing a different func for each possible type our 3P service can vend. So I use a func with a generic return type.
func genericMaker<T: TypeEmittedByOur3PService>() -> T? {
@Winchariot
Winchariot / String+Extensions.swift
Created December 18, 2017 16:17
Encode String for URL param or request body
//Both implementations thanks to https://useyourloaf.com/blog/how-to-percent-encode-a-url-string/
//Upgraded/cleaned up for Swift 4
Extension String {
func percentEncodedForRFC3986() -> String? {
let unreserved = "-._~/?"
var allowed = CharacterSet.alphanumerics
allowed.insert(charactersIn: unreserved)
return self.addingPercentEncoding(withAllowedCharacters: allowed)
}
@Winchariot
Winchariot / String+Extensions.swift
Created December 18, 2017 16:06
Validate nonempty string
extension String {
//Validate both that a string is nonempty and that it contains something besides whitespace.
// Useful for driving things like enabling a submit button only when a user has entered (meaningful) text
var isVisuallyEmpty: Bool {
return self.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
}
@Winchariot
Winchariot / QuestionnaireFeedback.swift
Created December 14, 2017 16:05
Encodable enum with associated values - single value container
//Encoding an enum with associated values is super simple.
enum Answer {
case rating(Int)
case freetextResponse(String)
}
extension Answer: Encodable {
@Winchariot
Winchariot / QuestionnaireFeedback.swift
Last active December 14, 2017 16:06
Encodable enum with associated values - keyed container
enum QuestionnaireFeedback {
case numeric(Int)
case text(String)
}
extension QuestionnaireFeedback: Encodable {
enum CodableKeys: String, CodingKey {
case numeric
case text
}
@Winchariot
Winchariot / CodableType.swift
Created December 12, 2017 15:53
Codable types
//It is generally nicest to make the variables in your codable types optional, so your decoding can still succeed
// even if the JSON is missing 1 or more fields
struct MyCodableType: Codable {
var myVar1: String?
var myVar2: [Bool]?
var myVar3: SomeOtherCodableType?
//A CodingKeys enum is required if your variable names don't match the JSON names, case-sensitive.
// The cases here should match your clientside variable names, and the associated values should match the JSON