This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if using Cocoapods | |
Pods/ | |
#if using bundler to manage Cocoapods version | |
.bundle | |
vendor/ | |
.DS_Store | |
.idea | |
*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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? { |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Encoding an enum with associated values is super simple. | |
enum Answer { | |
case rating(Int) | |
case freetextResponse(String) | |
} | |
extension Answer: Encodable { | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum QuestionnaireFeedback { | |
case numeric(Int) | |
case text(String) | |
} | |
extension QuestionnaireFeedback: Encodable { | |
enum CodableKeys: String, CodingKey { | |
case numeric | |
case text | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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 |
NewerOlder