Skip to content

Instantly share code, notes, and snippets.

View IanKeen's full-sized avatar

Ian Keen IanKeen

View GitHub Profile
IanKeen / gist:596d79c0c7719790d5af
Created August 13, 2015 15:46
Example of displaying an NSDate in different timezones
NSDate *date = [NSDate date];
NSTimeZone *timeZoneCST = [NSTimeZone timeZoneWithAbbreviation:@"CST"];
NSTimeZone *timeZoneEST = [NSTimeZone timeZoneWithAbbreviation:@"EST"];
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterShortStyle;
formatter.timeZone = [NSTimeZone systemTimeZone];
IanKeen / gist:f585650b48040dec7d37
Created September 15, 2015 16:14
Don't let your UIViewController think for itself...

Don't let your UIViewController think for itself...

Last time I showed you one strategy for trimming the fat from our view controller by seperating out protocols. In part 2 of this 3 part series we are going to use an architecture known as MVVM to dumb down our view controller. View controllers are usually filled with business rules, this is a problem for a number of reasons, two of which being:

  • It makes the code harder to reason about; let the view controller worry about appearance and the business objects worry about the logic, we don't want them thinking for themselves ;)
  • It makes your view controller bloated; business rules don't belong in your view controller


MVVM stands for Model View ViewModel and is just a way of describing how to break up your interface, business rules and data so that they flow together in a logical, but seperated, way.

This is what that flow looks like

IanKeen / gist:5b832230a51bc2295f02
Created September 15, 2015 16:15
Make your UIViewController Awesynchronous!

Make your UIViewController Awesynchronous!

Welcome back for the conclusion of this 3 part series! In part 1 we learnt how to slim down our view controllers to a manageable size. In part 2 we learnt how to strip out all the non-ui related logic. This time we are going to focus solely on the UITableView and how we can properly handle multiple asynchronous operations in its cells for maximum performance!

As always we will be starting with our project from last time.

What's making our table's scrolling so bad?

Our current implementation is very bad... our UITableViewCells are performing an expensive operation, and on the main thread no less!

The following code is currently in the setup method of our cell:

IanKeen / gist:a772cbef81884680a501
Last active September 6, 2016 02:47
Put your UIViewcontroller on a diet

Put your UIViewcontroller on a diet

I hate to say it but our view controllers have gotten fat, and it's our fault! We feed them protocol after protocol, business rule after business rule. They don't know any better and they just gobble them all up...

This will be a 3 part "Tune up your table view" series in which we will take an old fat view controller, slim it down with some refactoring, freshen it up with some MVVM and then make it fly with some better asynchronous operation management!

In part 1 using refactoring and a couple of Interface Builder tricks hopefully I can provide some motivation to start your journey towards getting your view controllers back in fighting shape!

The current state of things...

UITableViews are pretty integral to most iOS apps so I'm going to use it as an example of how to change a 'fat' view controller into a 'slim' one.

IanKeen / KeyValueStorable.swift
Last active November 1, 2015 18:38
A protocol I like to use in my apps anywhere something like NSUserDefaults or KeyChain is normally used... allows for easy swapping of implementation. Also provided is StringDictionary() which can be used when testing
protocol KeyValueStorable {
subscript (key: String) -> AnyObject? { get set }
mutating func removeAll() -> Void
extension NSUserDefaults: KeyValueStorable {
subscript (key: String) -> AnyObject? {
get { return self.objectForKey(key) }
set { self.setObject(newValue, forKey: key) }
IanKeen / DictionaryConvertable.swift
Last active August 3, 2017 16:18
Protocol to handle conversions between Models (class or struct based) and Dictionaries. Model to Dictionary has a default implementation provided for simple 1:1 Models
protocol DictionaryConvertable {
static func fromDictionary(dictionary: [String: AnyObject]) throws -> Self
func toDictionary() -> [String: AnyObject]
protocol DictionaryValueType {
func dictionaryValue() -> AnyObject?
extension Optional: DictionaryValueType {
func dictionaryValue() -> AnyObject? {
IanKeen / ObjectOutput.swift
Created October 5, 2015 21:01
A 'alternative' way to print out dictionaries and arrays in Swift if you don't like the default output
* Usage: toString(object)
public func toString(object: AnyObject) -> String {
return toString(any: object, indent: 0)
private func indented(count: Int, string: String) -> String {
IanKeen / NSTimer+Closure.swift
Last active March 6, 2019 16:59
Simple NSTimer extension to support closures
extension NSTimer {
private class TimerClosure {
private let closure: (NSTimer) -> Void
init(closure: (NSTimer) -> Void) { self.closure = closure }
@objc func selector(timer: NSTimer) { self.closure(timer) }
static func scheduledTimerWithTimeInterval(ti: NSTimeInterval, closure aClosure: (NSTimer) -> Void, userInfo: AnyObject?, repeats yesOrNo: Bool) -> NSTimer {
let wrapped = TimerClosure(closure: aClosure)
return NSTimer.scheduledTimerWithTimeInterval(ti, target: wrapped, selector: "selector:", userInfo: userInfo, repeats: yesOrNo)
IanKeen / String+componentsSeparatedByStrings.swift
Created November 17, 2015 08:36
String extension to allow splitting a string by multiple components/tokens
extension String {
func componentsSeparatedByStrings(separators: [String]) -> [String] {
return separators.reduce([self]) { result, separator in
return result.flatMap { $0.componentsSeparatedByString(separator) }
.map { $0.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) }
/* Usage */
IanKeen / NSCoder+Extensions.swift
Last active September 28, 2021 03:46
A couple of extensions to make working with NSCoding a little nicer using generics
extension NSCoder {
func encode(key: String, value: AnyObject?) {
self.encodeObject(value, forKey: key)
func decode<T>(key: String) -> T? {
return self.decodeObjectForKey(key) as? T
extension NSCoding {
func encode() -> NSData {