Skip to content

roadfire/NiceThings

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NiceThings

Build Status

A collection of extensions and methods to make Swift and iOS even better

Inspired by Soroush Khanlou's talk, You Deserve Nice Things, at #Pragma Conference 2017.

Load a view from a nib

To load a view from a nib, don't use this:

let view = Bundle.main.loadNibNamed("YourView", owner: self, options: nil)?.first as? YourView

Instead, use this:

let view = YourView().loadNib()

Just grab UIView+loadNib.swift to make loading nibs super easy.

Thanks to Matt Lorentz for contributing this!

Dequeue table view cells

To dequeue a table view cell, don't use this:

dequeueReusableCell(withIdentifier identifier: String)

Instead, use this:

dequeueReusableCell(withIdentifier identifier: String, for indexPath: IndexPath)

Why? Look closely at the documentation for each, and check out the Return Value. On the second, it says:

A UITableViewCell object with the associated reuse identifier. This method always returns a valid cell.

This is nicer than checking for nil and instantiating a new cell.

Show Build Durations in Xcode

Because sometimes you want to time your build without xcodebuild. Just run this command in your Terminal:

defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

The Result type

The Result monad is a better way to handle operations that return one type on success and another on failure. It replaces code like this:

let completion = { (model: Model?, error: Error?) in
    switch (model, error) {
    case (.some(_), .none):
        print("Success! We got our object.")
    case (.none, .some(_)):
        print(error)
    case (.none, .none):
        print("This shouldn't happen.")
    case (.some, .some):
        print("This shouldn't happen either.")
    }
}

Into this:

let completion = { (result: Result<Model, Error>) in
    switch (result) {
    case .success(let model):
        print("Success! We got our object back")
    case .failure(let error):
        print("The function failed, but in style!")
    }
}

XCTBlockExpectation

XCTBlockExpectation turns this test case:

func test_XCTNSPredicateExpectation_should_be_replaced_with_XCTBlockExpectation() {
    var moveAlong = false
    let predicate = NSPredicate(block: { _,_ in moveAlong == true })
    let expectation = XCTNSPredicateExpectation(predicate: predicate, object: nil)
            
    DispatchQueue.global().asyncAfter(deadline: .now() + 0.05) {
        moveAlong = true
    }
            
    wait(for: [expectation], timeout: 2)
}

Into this:

func test_XCTBlockExpectation() {
    var moveAlong = false
    let expectation = XCTBlockExpectation { moveAlong == true }
    
    DispatchQueue.global().asyncAfter(deadline: .now() + 0.05) {
        moveAlong = true
    }
    
    wait(for: [expectation], timeout: 2)
}

XCTBlockExpectation is more concise; it's also a zillion times faster than XCTNSPredicateExpectation. For some reason, Apple's XCTNSPredicateExpectation only seems to evaluate the block every second. This is insanely slow, especially if you have even a modest suite of async tests (100 async tests == 100+ seconds to complete). XCTBlockExpectation returns immediately when the block condition is met, making it way faster than XCTNSPredicateExpectation.

About

A collection of extensions and methods to make Swift and iOS even better

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages