Skip to content

Instantly share code, notes, and snippets.

View bnickel's full-sized avatar

Brian Nickel bnickel

View GitHub Profile
@bnickel
bnickel / RestorationDefender.swift
Last active January 12, 2023 09:47
A few friendly methods to help you detect state restoration problems in your non-storyboard apps.
// USAGE:
// Call RestorationDefender.printViewControllerClassesThatAreProbablyNotRestorable() to print a list of view controllers that will probably not return from state restoration.
// Call RestorationDefender.crashWhenViewControllersDoNotImplementStateRestoration() to crash your app when a view controller appears without setting restorationIdentifier and restorationClass.
// Call RestorationDefender.shoutWhenViewControllersDoNotImplementStateRestoration() to print a big message when a view controller appears without setting restorationIdentifier and restorationClass.
import Foundation
private func objc_getClassList() -> [AnyClass] {
let expectedClassCount = objc_getClassList(nil, 0)
var allClasses = UnsafeMutablePointer<AnyClass?>.alloc(Int(expectedClassCount))
@bnickel
bnickel / Queue Playground.swift
Last active June 23, 2020 16:33
Swift retry operation playground
import Foundation
protocol Completable {
func addCompletionOperation(on queue: OperationQueue, complete: @escaping (Self) -> Void) -> Operation
}
extension Completable where Self: Operation {
func addCompletionOperation(on queue: OperationQueue, complete: @escaping (Self) -> Void) -> Operation {
let completionOperation = BlockOperation {
@bnickel
bnickel / SEUIChildManagingViewController.swift
Created April 12, 2019 19:55
A three panel view controller used by Stack Exchange.app (currently unmaintained). On a wide iPad, this would allow a collapsed sliver menu, a left navigation panel and a right detail panel to live side-by-side. As width shrunk, the delegate would let you combine the left and right panel, as well as hide the sliver menu completely (accessible by…
//
// SEUIChildManagingViewController.swift
// ThreePanelSplitViewController
//
// Created by Brian Nickel on 6/21/17.
// Copyright © 2017 Brian Nickel. All rights reserved.
//
import UIKit
@bnickel
bnickel / Comment reloading and expansion.swift
Created February 12, 2019 21:54
Using a general purpose diff tool to handle complex table view transitions
fileprivate func replaceAndExpandComments(_ comments:[SEAPIComment], includeUpdates:Bool) {
let originalComments = displayedComments
let changes = compare(original: displayedComments.map({ $0.commentId }), modified: comments.map({ $0.commentId }))
self.comments = comments
self.displayedComments = comments
var changedIndexPaths:[IndexPath] = []
var deletedIndexPaths:[IndexPath] = []
@bnickel
bnickel / SEUIEnlargedTapRadiusCollectionView.h
Created September 14, 2018 18:25
Enlarges the tap radius of small UICollectionViews
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface SEUIEnlargedTapRadiusCollectionView : UICollectionView
@property (nonatomic, assign) IBInspectable CGFloat enlargedTapRadius;
@end
@bnickel
bnickel / SETableViewBatchUpdate.h
Created June 21, 2018 19:04
A class that lets you schedule a bunch of batch updates to UITableView and then perform them all at once or not, with a callback on completion.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SETableViewBatchUpdate : NSObject
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithTableView:(UITableView *)tableView NS_DESIGNATED_INITIALIZER;
- (void)runAnimated:(BOOL)animated completion:(void (^ _Nullable)())completion;
@property (nonatomic, assign, readonly) BOOL hasUpdates;
@end
@bnickel
bnickel / SEPrankster.h
Last active June 11, 2018 17:09
Randomly change the font size while running your app.
@import UIKit;
@interface SEPrankster: NSObject
@property (class, readonly) SEPrankster *sharedPrankser;
- (void)setUpFontRandomness:(BOOL)run;
- (void)setFontCategory:(UIContentSizeCategory)category;
@end
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
@bnickel
bnickel / Keychain.playground
Created February 23, 2015 22:43
Application passwords in Swift using function overloading
import Security
import Foundation
// MARK: - Redefining boilerplate code
func SecKeychainOpen(path:String) -> SecKeychainRef? {
var keychain:Unmanaged<SecKeychainRef>? = nil
if SecKeychainOpen((path as NSString).UTF8String, &keychain) == errSecSuccess {
return keychain?.takeRetainedValue()
@bnickel
bnickel / DelayedAddition.swift
Created June 29, 2017 23:48
Functions that delay adding views to a navigation controller until they are removed from their parent view controllers.
func eventuallyAdd(_ viewControllers: [UIViewController], to navigationController: UINavigationController) {
if canAdd(viewControllers, to: navigationController) {
navigationController.viewControllers += viewControllers
} else {
// SHOW PLACEHOLDER CONTENT HERE IF NEEDED
DispatchQueue.main.async {
eventuallyAdd(viewControllers, to: navigationController)
}