Clicky

Hwee-Boon Yar

Hi, I'm Hwee-Boon Yar

I write, ship and sell software products. iOS/OS X app developer based in Singapore, working remotely. This is my blog.

.

Need to run a code review on your codebase? Hire me

If you accept One-time password (OTP) via SMS/text in your app, there's a nice goodie in UITextInputTraits (which is inherited by UIKeyInput which is in turn inherited by UITextInput) which is adopted by UITextField and UITextView.

In short, you can do:

let textField = UITextField()
textField.textContentType = .oneTimeCode

or

let textView = UITextView()
textView.textContentType = .oneTimeCode

and when you receive the OTP via SMS/text, iOS will automatically show the OTP code in the QuickType bar for a few minutes letting you tap on it to automatically fill it into the textField/textView for you.

This is available since iOS 12. There's a few more types available in UITextContentType such as .password, .newPassword that is quite useful.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Arrays are a common data structure in Swift:

let l = ["alice", "bob", "charlie"]
dump(l[2])

But array subscripting is unchecked, so this will crash at runtime:

dump(l[3])

Here's an extension to add a checked subscripting operator:

extension Array {
    subscript(checked index: UInt) -> Element? {
        if index < count {
            return self[Index(index)]
        } else {
            return nil
        }
    }
}

So you can do:

dump(l[checked: 2])
dump(l[checked: 3])

Since it returns an Optional, you can do:

if let element = l[checked: 2] {
    NSLog("Value: \(element)")
}

Note that the argument is UInt instead of Int or Index so the compiler can check when you pass in a negative index like this:

dump(l[checked: -1])

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes it's handy to put content into UITableView and want it to stretch the full height so that all the content is displayed without scrolling. Especially if you display the UITableView in a vertical UIStackView.

class ViewController: UIViewController {
    private let tableView = UITableView(frame: .zero, style: .plain)
    private var tableViewContentSizeObserver: NSKeyValueObservation?
    lazy private var tableViewHeightConstraint = tableView.heightAnchor.constraint(equalToConstant: 0)

    func init() {
        super.init(nibName: nil, bundle: nil)
        NSLayoutConstraint.activate([
            tableViewHeightConstraint
        ])
        tableView.isScrollEnabled = false
    }

    func foo() {
        tableView.reloadData()
        tableViewContentSizeObserver = tableView.observe(\UITableView.contentSize, options: [.new]) { [weak self] (_, change) in
            guard let strongSelf = self else { return }
            guard let newSize = change.newValue else { return }
            strongSelf.tableViewHeightConstraint.constant = newSize.height
        }
    }
}

That's it. The trick is to set isScrollEnabled to false, and observe the contentSize and use the height to update the constraint.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Do you notice that if the call-in-progress or personal hotspot indicator bar is shown when you launch an app on a iPhone without a notch (i.e. iPhone 8, 8 Plus and earlier as of writing), the launch screen tends to be distorted? I've found that an easy fix is just to disable the status bar at launch with this in your Info.plist:

<key>UIStatusBarHidden</key>
<true/>

Then enable it immediately in your app delegate:

application.isStatusBarHidden = false

Let me know if you know of any other trick to do this.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


As I've done on a few occasions, I also like to drop little nuggets about external tools that aren't specifically for iOS app development, but which can be incredibly useful for.

Check out jq which in the author's own words:

jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text.

It lets you filter and transform JSON.

An example from the tutorial:

$ curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.[] | {message: .commit.message, name: .commit.committer.name}'

The relevant part is:

jq '.[] | {message: .commit.message, name: .commit.committer.name}'

.[] returns each element of the array and pipe them to {message: .commit.message, name: .commit.committer.name}'.

You can count, for example with:

$ curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '. | length'

Install it with:

brew install jq

Have fun!

Edit 20181007: Fix typo for getting length with the help of @dev_jac.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes it's useful to keep a list of weak references to objects, especially to reduce the maintenance work needed to track when they are destroyed if you had kept a strong reference to them instead.

class C {}

This wouldn't work since they keep a strong reference:

class Watcher {
    var objects = [C]()
}

So you can define a WeakRef wrapper class:

class WeakRef<T: AnyObject> {
    weak var object: T?
    init(object: T) {
        self.object = object
    }
}

And this will work as expected:

class Watcher {
    var objects = [WeakRef<C>]()
}

Have fun with it!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I have some guidelines I apply to myself to help reduce cyclic references caused by closures capturing self.

  1. I never explicitly refer to self (as in self.someProperty or self.someFunc()) unless I absolutely have to.
  2. I have a simple rule of thumb, if I see a self. in a closure, I double check to make sure it is necessary. This is because self. in a closure means the closure captures self and holds a strong reference to self. Most of the time, this can lead to cyclic references either now or later. I try my best to avoid them.

Because of (1) above, self. will only appear:

  1. in init() and its variations
  2. when I need to assign to a new local variable in a function and the new local variable has the same name as a function or a property
  3. when closure captures self.

This means I can run grep -R "self\." . and do a quick scan when I suspect a memory leak.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Suppose you have code like this:

func foo() {
    print("foo called")
}

func bar() {
    print("bar called")

    foo()
    //Some more code here.
}

bar()

The output is:

bar called
foo called

All good. Now, during debugging, you want to skip running foo() and all the other code in bar(), so you might add an early return statement like this:

func bar() {
    print("bar called")

    return

    foo()
    //Some more code here.
}

Do you see the problem?

It'll still execute foo() because it will consider return foo() to be a single statement and then skip the rest of the code in bar(). The way to prevent this is to use return; (i.e. end it with a semi-colon) or just comment out the rest of the code.

This is easy to miss and I was bitten by this recently.

PS: The compiler issues a warning for this, but it's easy to miss while debugging and making all sorts of code changes quickly to figure out the problem at hand.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift has strong type checking. Generally, I've found that if you write your Swift apps without using force unwraps, and not deliberately stepping out of Swift's type checking, you end up with an app that hardly crashes. There is 1 exception though. Array random access via index is unchecked:

let a = [1, 2, 3]
print(a[100])

This will crash with:

Fatal error: Index out of range

In this case, Swift code that compiles may still crash. So, either check before accessing (explicitly, or by implementing and using your own checked subscript operator) unless you are sure.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Did you know that you can include underscores (_) and leading zeros (0) in numeric literals for clarity?

i.e.

print(001) //1
print(1_000_000) //1000000
print(1.234_567) //1.234567

Works with numbers written in base-2 and base-10 too:

print(0b1000_0001) //129
print(0xCC_CC_CC) //Grayish, If you encode RGB in 3 bytes

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I'm a big fan of using Swift's strong static typing to reduce bugs, and I recently stumbled upon a library that helps with that.

From the README, imagine you have this defined:

struct User {
  let id: Int
  let email: String
  let address: String
  let subscriptionId: Int?
}

struct Subscription {
  let id: Int
}

func fetchSubscription(byId id: Int) -> Subscription? {
  return subscriptions.first(where: { $0.id == id })
}

Notice that the id properties in both structs and subscriptionId properties are of type Int. This is pretty common. The problem is that Int is a very general type.

And if you call fetchSubscription(byId:) like this, you have introduced a bug:

let subscription = fetchSubscription(byId: user.id)

Strong static typing to the rescue! Tagged provides a simple way to solve it:

import Tagged

struct User {
  let id: Id
  let email: String
  let address: String
  let subscriptionId: Subscription.Id?

  typealias Id = Tagged<User, Int>
}

struct Subscription {
  let id: Id

  typealias Id = Tagged<Subscription, Int>
}

It basically lets you define unique types based off another type (the latter being Int in the example). So you can say that this struct's id and another struct's id property are of different types, despite both of them fundamentally being Int.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you haven't tried CodeRunner, you really ought to. It's basically a macOS app that lets you run code snippets in different languages, include Swift. It doesn't have the fancy features present in Swift Playgrounds and the text editor is quite rudimentary, but despite that, it is really fast to build and run Swift code, so for most built-in non-UI stuff, you can explore Swift code very quickly, e.g. if you wanted to build a DateFormatter and want to experiment with various date formats.

It's really worth checking out. There's a free trial available.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

PS: This is not a paid ad

Like this post? Follow me @hboon on Twitter.

.


Anytime you have some logic in a class which checks 2 or more of its properties to represent a state or condition of some sort, consider wrapping that into an enum.

For example:

class Payment {
    var isFree: Bool
    var price: Int?
    var currency: String?

    init() { //... }

    function send() {
        if isFree {
            //do something
        } else {
            if let price = price, let currency = currency {
                //do something with price + currency
            } else {
                //handle this somehow
            }
        }
    }
}

Change it to:

class Payment {
    enum Type {
        case free
        case paid(price: Int, currency: String)
    }
    var type: Type

    init() { //... }

    function send() {
        switch type {
        case .free:
            //do something
        case .paid(let price, let currency):
            //do something with price + currency
        }
    }
}

The code ends up clearer — being explicit that it's handling 2 states, free and paid — and it's less likely to introduce bugs because the code paths are easier to follow and if you need to do something that depends on the type, the compiler will force you to handle all the possible states (free and paid).

The resulting code can sometimes end up being longer, but it's a worthy trade-off.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Most apps need some kind of backing datastore and sometimes plist(s) are a perfectly fine option. When you need to handle more, structured data, you can consider SQLite, perhaps with a wrapper like FMDB. Alternatively, there is Realm which provides a local database and an optional cloud-sync service.

It's easy to get started, especially if you just want to use it for local storage.

Add it to your Podfile:

pod 'RealmSwift'

Install:

$ pod install --repo-update

Import the framework:

import RealmSwift

Define a class that is backed by Realm:

class Item: Object {
    @objc dynamic var itemId: String = UUID().uuidString
    @objc dynamic var body: String = ""
    @objc dynamic var timestamp: Date = Date()

    override static func primaryKey() -> String? {
        return "itemId"
    }
}

The properties that you want stored in Realm has to be declared with @objc and dynamic.

Create the database instance:

let realm = try! Realm()

Fetch objects:

items = realm.objects(Item.self).sorted(byKeyPath: "timestamp", ascending: false)

Create and save a new object:

try! realm.write {
    realm.add(item)
}

Update an object:

try! realm.write {
    item.body = "Something something"
}

Delete an object:

try! realm.write {
    realm.delete(item)
}

You can define parent-child relationships:

class Parent: Object {
    @objc dynamic var parentId: String = UUID().uuidString
    var items = List<Item>()

    override static func primaryKey() -> String? {
        return "parentId"
    }
}

You can perform schema migrations with a migration block:

config.migrationBlock = { migration, oldSchemaVersion in
    if oldSchemaVersion < 10 {
        migration.enumerateObjects(ofType: Item.className()) { oldObject, newObject in
            guard let oldObject = oldObject else { return }
            guard let newObject = newObject else { return }
            newObject["someChangedVarName"] = oldObject["oldChangedVarName"]
        }
    }

    if oldSchemaVersion < 20 {
        //...
    }
}

It's extremely quick to start and low effort to use for local storage.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I have written about printing out the document directory in #172, but here's a obvious tweak on hindsight, along with updates for current Swift language changes:

#if DEBUG
    let docPath = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).last?.path
    print("docPath: \(docPath)")
#endif

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I'm going to talk about something that Swift doesn't have.

I'm quite a fan of the pipe operator in Elixir where you can do:

"Elixir rocks"
    |> String.upcase()
    |> String.split()

> ["ELIXIR", "ROCKS"]

Swift doesn't provide the pipe operator, but there are multiple implementations floating around that implements it using operator overloading. One of the libraries gives as an example:

let isEven: (Int) -> Bool = { x in x % 2 == 0 }
[1,2,3,4,5]
    .filter(isEven)
    .map({$0 * 3})
    .reduce(0, +)

which can be rewritten with the library's pipe operator as:

let isEven: (Int) -> Bool = { x in x % 2 == 0 }
[1,2,3,4,5]
    |> (filter, isEven)
    |> (map, {$0 * 3})
    |> (reduce, 0, +)

I just want to point out that. The pipe operator in Elixir (and F#) works in a different way. Let's look at an example. With the pipe operator in Elixir, you should be able to rewrite this code:

bar(foo([1, 2, 3, 4].map({ $0 == 2 })))

into:

[1, 2, 3, 4].map({ $0 == 2 })
    |> foo
    |> bar

In other words, you kind of flip the code with nested function calls from right to left to left-to-right, so it's easier to understand without introducing local variables.

Just wanted to clear this up.

PS: Sorry, this issue is very late.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


According to Wikipedia:

currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument.

In Swift 3, currying was removed. But it is still a useful tool. If you still want to use currying, there's a library for that.

Given a function f:

func f(x: Int, y: Int, z: Int)

which you normally call with f(x: 1, y: 2, z: 3), you turn it into a series of functions that you can call in these order with currying:

let f0 = curry(f)
let f1 = f0(1)
let f2 = f1(2)
let result = f2(3)

This is useful, for e.g., because you can create the functions stored in f1, f2 as you process and gather the arguments.

While an alternative is just to store the values of x, y as we gather them in an object, as we write more functional code, currying is a very useful technique.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Did you know that you can set conditions for your breakpoints?

  1. Click at the gutter in Xcode editor on the line of code to set a breakpoint
  2. Ctrl-click the breakpoint and choose Edit Breakpoint
  3. Type in the condition. eg. i == 13

Conditional breakpoints will only break when it matches the condition.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


This is a common pattern:

let someModel = getCurrentModel()
functionThatIsAsynchronousEspeciallyAWebAPICall(model: someModel) { result in
    doSomething(with: result)
}

functionThatIsAsynchronousEspeciallyAWebAPICall() is a function that is asynchronous and sometimes takes a few seconds or more to complete and call its completion handler.

In an app that has user accounts or something similar, this becomes:

let account = getAccount()
functionThatIsAsynchronousEspeciallyAWebAPICall(account: account) { result in
    doSomething(with: result)
}

Depending on how you implement doSomething(with:), this might not always behalf correctly because by the time the completion handler is called, the user might have switched accounts. It's better to include a check that the current account is still the same.

let account = getAccount()
functionThatIsAsynchronousEspeciallyAWebAPICall(account: account) { result in
    let currentAccount = getAccount()
    guard currentAccount.username == account.username else { return }
    doSomething(with: result)
}

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Do you use UITableview without self-sizing cells?

I've found an odd behavior that happens when several conditions are met:

  • not use self-sizing cells
  • the number of rows display is such that it the total content height is slightly more than the table view's height
  • you scroll to the bottom of the table

Sometimes when you call reloadData, the table may scroll so there is a gap at the bottom, below the last cell.

Anecdotally, this seems to be fixed by setting UITableview.estimatedRowHeight to 0.

If you experience this, try it out and let me know.

PS: Sorry, I'm late for this issue

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I discovered SwifterSwift recently. In its own words, it's a "A handy collection of more than 500 native Swift extensions to boost your productivity".

Some examples from https://github.com/SwifterSwift/SwifterSwift/blob/master/Examples/Examples.md:

// Remove duplicates from an array
[1, 2, 3, 1, 3].removeDuplicates() -> [1, 2, 3]

date.hour = 14

"hello world".split(by: " ") -> ["hello", "world"]

"123abc".reverse() -> "cba321"

"Hèllö Wórld!".latinize() -> "Hello World!"

√ 9 -> 3

view.addShadow(ofColor .black, radius: 3, opacity: 0.5)

image.kilobytesSize -> 114

imageView.download(from url, contentMode: .scaleAspectFit, placeHolder: UIImage?)

I'm still not sure if importing such libraries will essentially make you form your own dialect of Swift (maybe that's inevitable with all libraries), but there are definitely some gems in there and since the license is MIT, you can at least cherry pick what you want if you rather not import the entire library. So check it out!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you work with Core Data, you got to check out Core Data Editor. Remember Fred Brooks famous quote:

Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won’t usually need your flowcharts; they’ll be obvious.

It's true. I recently took over a project that uses Core Data and Core Data Editor lets me look at what are the types involved as well as data stored. It has a few handy features like letting you point to your simulator directory and DerivedData directory so that it can automatically list your apps.

As of writing, there's a downloadable release on GitHub.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


For most iOS apps, displaying the right data in the right way is very important. Traditionally, testing this is hard. It gets especially more complicated as your app feature set grows and you no longer know if a change affects another screen(s).

iOSSnapshotTestCase helps with that by letting us write snapshot tests, or what I like to call "screenshot-based asserts". You write tests cases with it, creating or navigating to the desired screen and then take a screenshot with it, comparing that to a reference screenshot which you made earlier.

It's easy to get started.

  1. Add the iOSSnapshotTestCase pod with Cocoapods for your test target, run pod install
  2. In Xcode, go to Product > Schemes > Edit Scheme, choose Test, add these to Environment Variables:

    FB_REFERENCE_IMAGE_DIR = $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/Snapshots/ReferenceImages IMAGE_DIFF_DIR = $(SOURCE_ROOT)$/(PROJECT_NAME)Tests/Snapshots/FailureDiffs

    Make sure that $(PROJECT_NAME)Tests matches your test folder name in your project directory, otherwise tweak the path accordingly.

    The former will be used to store your reference images and the latter the results if they don't match.

  3. Create a test class, but subclass FBSnapshotTestCase instead of XCTestCase.

  4. In the test function, create your view controller/view and call FBSnapshotVerifyView() passing in the view to test
  5. In setUp(), set recordMode to true and run the test case to create and store the reference screenshots in FB_REFERENCE_IMAGE_DIR. You'd want to make sure these screenshots represent how your app should behave.
  6. From now on, run it with recordMode = false to compare against the reference screenshots — until you intentionally change your UI and you would need to update your reference snapshot(s). If a test fails, the result, including the difference will be stored in IMAGE_DIFF_DIR.
  7. You want to add IMAGE_DIFF_DIR to your .gitignore file.

e.g of a test class:

class AnExampleSnapshotTest: FBSnapshotTestCase {
    override func setUp() {
        super.setUp()
        //Set to true only when creating reference snapshots
        //This line should not be checked into version control
        recordMode = true
    }

    func testExample() {
        //TODO create data, set up controller, etc
        let controller = MyViewController()
        //This will create a reference snapshot or compare against one, depending on the value of `recordMode`
        FBSnapshotVerifyView(controller.view)
    }
}

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


We often need to go through elements in a collection, but only operating on elements that fulfill a certain condition. E.g. only if the number is odd:

for i in 1...10 {
    if i % 2 == 0 {
        print(i)
    }
}

Here's another way to do it, using filter():

for i in (1...10).filter({$0 % 2 == 0}) {
    print(i)
}

But this is probably the more idiomatic way to do it in Swift:

for i in 1...10 where i % 2 == 0 {
    print(i)
}

Note that you can use where clauses in a similar manner in other places, such as in switch-case statements.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


You have probably used Implicit Member Expressions without knowing what it's called:

var color: UIColor?
color = .white

i.e. the member of a type can be accessed from an inferred type.

You can access static functions:

foo(i: .createInstance())

Did you know that it works with .init() too?

class C {
    static func foo() -> C {
        return .init()
    }
}
func bar(c: C) {}

bar(c: .init())

Notice the 2 calls to init() above.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Using Auto Layout with UIScrollView is surprisingly simple. You just need to add constraints to the content that will fill the entire scrollview by anchoring to the 4 edges of the scroll view. You don't need to set the content size of the scroll view explicitly. This is because the 4 edges actually refer to the scroll view's content view rather than the scroll view itself.

let scrollView = UIScrollView()
content.translatesAutoresizingMaskIntoConstraints = false

let content = UIView()
//TODO: Set up `content`, adding subviews, etc
content.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(content)

NSLayoutConstraint.activate([
    content.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
    content.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
    content.topAnchor.constraint(equalTo: scrollView.topAnchor),
    content.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),

    //Of course you'll want to layout the scrollview itself. Likely occupying the entire parent
    scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    scrollView.topAnchor.constraint(equalTo: view.topAnchor),
    scrollView.bottomAnchor.constraint(equalTo: footerBar.topAnchor),

    //TODO set up constraints for `content` as you would have if there was no `UIScrollView` involved
])

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


UIWebView is (still) useful for showing web-based documents — such as help or FAQs — in your app. If the document background color and app's background color don't match and aren't white, you might sometimes see the the UIWebView's white background color appear for a split second the first time a document is loaded.

You can't fix this by setting UIWebView's background color, because it is ignored. Here's an easy way to fix this:

Set webview.isOpaque to false and make sure the UIViewController instance holding the UIWebView has the correct background color.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Do you sometimes you want to change the title of a text-only UIButton while it is on the screen and the text flashes? The easiest way to fix that is to use the .custom button type instead of .system.

Here's some playground code to illustrate this:

import UIKit
import PlaygroundSupport

let view = UIView()
view.backgroundColor = .green
view.frame = CGRect(x: 0, y: 0, width: 200, height: 300)
let b = UIButton(type: .system) //Switch to .custom
b.frame = CGRect(x: 10, y: 10, width: 70, height: 24)
b.setTitle("foo", for: .normal)
b.setTitleColor(.red, for: .normal)
view.addSubview(b)

PlaygroundPage.current.liveView = view

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    b.setTitle("bar", for: .normal)
}

Like this post? Follow me @hboon on Twitter.

.


Consider this code:

class S {
    var i: Int
    init(i: Int) {
        self.i = i
    }
}

class C {
    var prop1 = S(i: 0) {
        didSet {
            print("did set prop1, with i: \(prop1.i)")
        }
    }
}

var c = C()
print("i: \(c.prop1.i)")
var p = c.prop1
p.i = 1
print("i: \(c.prop1.i)")
c.prop1.i = 2

It prints:

i: 0
i: 1
i: 2

It prints 0, 1, 2 which is fairly obvious because S is a class — a reference type — so when p is actually a reference to the same instance of S, we are just operating on that same instance.

However, here's something that was surprising to me. What happens if we change S to be a struct? i.e.

Replace:

class {

with:

struct {

The output becomes:

i: 0
i: 0
did set prop1, with i: 2
i: 2

S is now a value type, so naturally, i remains at 0 because p is actually a copy of the struct held by the instance of C. Here's what surprised me though. c.prop1.i = 2 copies the struct, sets the new value of i (to 2) and assigns it back to the instance of C, triggering the didSet observer.

I recently wrote some code where this behavior bit me because I wasn't counting on didSet being triggered.

Beware!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


A common pattern for UI layout is to have a bar at the bottom of the screen like UITabBar. It has a fixed height in most cases, but with the iPhone X, you want it to stretch to the bottom of the screen, outside of the safe area while keeping it's contents (in UITabBar's case, the tab buttons) glued to the top of the bar.

Auto Layout anchors provide a very simple way to wire this up. In your view controller:

let buttonsHeight = 44
footerBar.topAnchor.constraint(equalTo: view.layoutGuide.bottomAnchor, constant: -buttonsHeight),
footerBar.bottomAnchor.constraint(equalTo: view.bottomAnchor),

The trick is to anchor the top and bottom of footerBar.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


This is super handy for implementing rounded corners when performance doesn't matter:

aView.clipsToBounds = true
aView.layer.cornerRadius = 20

But sometimes, maybe the design requires rounding only the top 2 corners. If it's an almost full-screen view, a simple way to do it is to let a view obscure the bottom 2 corners or just make sure it is offscreen (again, if performance is not an issue). But in iOS 11, there's a new property:

var maskedCorners: CACornerMask

This lets you set specific (corners) to mask. Here's some playground code:

import UIKit
import PlaygroundSupport

class VC: UIViewController {
    init() {
        super.init(nibName: nil, bundle: nil)
        view.backgroundColor = .black

        let square = UIView(frame: CGRect(x: 20, y: 20, width: 200, height: 200))
        square.backgroundColor = .white
        square.layer.cornerRadius = 20
        square.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
        view.addSubview(square)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

PlaygroundPage.current.liveView = VC()

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Like most developers, I use git very often. As I'm a lazy developer, I like to shorten the commands that I use frequently, so I have set these up as aliases:

alias ga='git add'
alias gp='git add -p'
alias gs='clear && git status -s'
alias gd='git diff --color'
alias gdc='git diff --cached --color'
alias gdt='git difftool'
alias gc='git commit $1'
alias gca='git commit -a $1'
alias gb='git branch'
alias gl='git log --color'
alias glo='git log --color --pretty=oneline'
alias gt='git tag'
alias gco='git checkout $1'
alias gcp='git cherry-pick $1'
alias gdn='git diff --name-only'
alias gr='git remote'

I get heavy use out of gb, gco, and gdn.

Do you have aliases for git commands that you found particularly useful?

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you build lots of forms — screens powered by table views that either read-only information or allow users to enter data such as names, dates/birthdays — Eureka is worth taking a look.

The README is very good, so I'll just show an example from there:

import Eureka

class MyFormViewController: FormViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        form +++ Section("Section1")
            <<< TextRow(){ row in
                row.title = "Text Row"
                row.placeholder = "Enter text here"
            }
            <<< PhoneRow(){
                $0.title = "Phone Row"
                $0.placeholder = "And numbers here"
            }
        +++ Section("Section2")
            <<< DateRow(){
                $0.title = "Date Row"
                $0.value = Date(timeIntervalSinceReferenceDate: 0)
            }
    }
}

I've found Eureka very handy if your app mostly uses the original look and feel of iOS. If you need to customize the forms UI — while Eureka supports that too, by letting you specify your own custom row and cell classes — I've found it might be a bit more messy than I hoped.

Eureka can be installed via Cocoapods or Carthage.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Wanted to share the updated version of my typical pre-commit hook since 2 years ago. It's better at only picking up additions rather than diffs (additions + removals).

I've also included checks for prints and NSLogs.

Sometimes I work on projects in a team and want to make sure that I don't accidentally check in changes to .xcodeproj, so I have a check for that too.

My commit workflow then includes commenting and uncommenting out section of this pre-commit file while I hit warnings and comparing it with the changes I have in mind. Finally I'll just do a git commit -m "some message" -n (with the additional -n switch) to commit, bypassing the precommit hook.

#!/bin/sh

if git rev-parse --verify HEAD >/dev/null 2>&1; then  
  against=HEAD
else  
  # Initial commit: diff against an empty tree object
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

exec 1>&2

#Workaround for filenames with spaces in them (because for loop breaks use space by default)
SAVEIFS=$IFS
IFS=$(echo "\n\b")

for ENTRY in `git diff-index --cached --name-status $against -- | cut -c1,3-`; do  
  CHANGE=`echo "$ENTRY" | cut -c1`
  FILE=`echo "$ENTRY" | cut -c2-`
  if [ $CHANGE = "A" ] || [ $CHANGE = "M" ]; then
      if [ ${FILE: -26} == ".xcodeproj/project.pbxproj" ]; then
          echo "$FILE" 'contains .xcodeproj/project.pbxproj! Are you sure?'
          IFS=$SAVEIFS
          exit 1
      fi
      if [ ${FILE: -6} == ".swift" ] || [ ${FILE: -2} == ".m" ] || [ ${FILE: -2} == ".h" ]; then
          if git diff --cached --color=always "$FILE" | perl -wlne 'print $1 if /^\e\[32m\+\e\[m\e\[32m(.*)\e\[m$/' | grep -q '\t'; then
              echo "$FILE" 'contains tabs!'
              IFS=$SAVEIFS
              exit 1
          fi
      fi
      if git diff --cached --color=always "$FILE" | perl -wlne 'print $1 if /^\e\[32m\+\e\[m\e\[32m(.*)\e\[m$/' | grep -q 'kkk'; then
          echo "$FILE" 'contains kkk!'
          IFS=$SAVEIFS
          exit 1
      fi
      if git diff --cached --color=always "$FILE" | perl -wlne 'print $1 if /^\e\[32m\+\e\[m\e\[32m(.*)\e\[m$/' | grep -q ' NSLog'; then
          echo "$FILE" 'contains NSLog!'
          IFS=$SAVEIFS
          exit 1
      fi
      if git diff --cached --color=always "$FILE" | perl -wlne 'print $1 if /^\e\[32m\+\e\[m\e\[32m(.*)\e\[m$/' | grep -q ' print'; then
          echo "$FILE" 'contains print!'
          IFS=$SAVEIFS
          exit 1
      fi
      if git diff --cached --color=always "$FILE" | perl -wlne 'print $1 if /^\e\[32m\+\e\[m\e\[32m(.*)\e\[m$/' | grep -q ' dump'; then
          echo "$FILE" 'contains dump!'
          IFS=$SAVEIFS
          exit 1
      fi
      if git diff --cached --color=always "$FILE" | perl -wlne 'print $1 if /^\e\[32m\+\e\[m\e\[32m(.*)\e\[m$/' | grep -q '007'; then
          echo "$FILE" 'contains 007!'
          IFS=$SAVEIFS
          exit 1
      fi
  fi
done

IFS=$SAVEIFS
exit 0

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift is a strongly typed language, so it makes sense when using it to tweak your tools and code to take advantage of type-checking. This week's nugget goes along that line.

The library R.swift automatically generates static references to resources such as font files and image files so that you don't have to refer to them by string. Example from the README:

let icon = UIImage(named: "settings-icon")
let font = UIFont(name: "San Francisco", size: 42)
let color = UIColor(named: "indictator highlight")
let viewController = CustomViewController(nibName: "CustomView", bundle: nil)
let string = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.current, "Arthur Dent")

becomes:

let icon = R.image.settingsIcon()
let font = R.font.sanFrancisco(size: 42)
let color = R.color.indicatorHighlight()
let viewController = CustomViewController(nib: R.nib.customView)
let string = R.string.localizable.welcomeWithName("Arthur Dent")

This avoids the chance of typing a string wrongly and not catching it before submitting a build to the app store.

Installation is simple:

  1. Include the pod (R.swift)
  2. Add a Run Script phase before Compile Sources: "$PODS_ROOT/R.swift/rswift" generate "$SRCROOT"
  3. Add the R.generated.swift file to your project

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you use custom fonts in your apps, it can be a hassle to track and maintain the UIAppFonts key in your Info.plist file, especially as you need to figure out each font name yourself. Here's an excellent timesaver: FontBlaster is a library that programmatically loads custom fonts for you. You just need to do this:

  1. Include the font files in your project like you'd normally do
  2. Include FontBlaster. (Supports Carthage and CocoaPods)
  3. Run FontBlaster.blast()

You no longer need the UIAppFonts key in Info.plist.

I learnt about FontBlaster from Michael Tsai.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Related to #162 Reclaim Disk Space from Xcode Usage, if you run:

$ xcrun simctl delete unavailable

simctl will remove old simulators which your current Xcode (xcode-select -p) cannot use.

If you work with multiple versions of Xcode, you have to be careful. This will probably delete simulators that another version of Xcode can use.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Maybe it's an existing project, or for some other reason you are still using Objective-C, here's a nugget for you:

__auto_type i = @123;
NSLog(@"class: %@", NSStringFromClass([i class]));

const __auto_type j = @123;
j = @1;

That last line will compile with an error:

Cannot assign to variable 'j' with const-qualified type 'NSNumber *__strong const'

Typing _auto_type and const __auto_type looks a little unwieldy, so we can define a few macros:

#define let const __auto_type
#define var __auto_type

and use them instead:

var i = @123;
NSLog(@"class: %@", NSStringFromClass([i class]));

let j = @123;
j = @1; //Compilation error

(Probably more useful to store the macros in a new header file and #import them)

I picked up this tip from @_nb

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Did you know that LLDB includes an REPL?

Set a breakpoint in your Xcode project, say the method that gets run when you hit a button. In the debugger proompt, type repl. i.e.:

(lldb) repl

Then paste this in:

let v = UIView()
v.frame = CGRect(x: 20, y: 20, width: 200, height: 20)
v.backgroundColor = .red
let window = UIApplication.shared.windows[0]
window.rootViewController?.view.addSubview(v)
CATransaction.flush()

Hit enter.

You should see that the new red view appears immediately upon CATransaction.flush() while you are still in the debugger. It is important that you are not breaking in application(_:, didFinishLaunchingWithOptions:) for flush() to "load" your changes immediately.

Type : and hit enter to exit the REPL.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


As a printf debugger, I have a little trick I like to use when logging hierarchy function calls. For example:

struct Node {
    var name: String
    var children = [Node]()

    init(_ name: String) {
        self.name = name
    }
    mutating func addChild(child: Node) {
        children.append(child)
    }
    func printHierarchy() {
        print("\(name)")
        for each in children {
            each.printHierarchy()
        }
    }
}

var root = Node("Topmost")
var n1 = Node("n1")
var n2 = Node("n2")
var n3 = Node("n3")
var n4 = Node("n4")
n3.addChild(child: n4)
n2.addChild(child: n3)
root.addChild(child: n1)
root.addChild(child: n2)

root.printHierarchy()

This prints:

Topmost
n1
n2
n3
n4

which isn't that useful. But if we modify printHierarchy() to add an indent argument with a default value of 0:

func printHierarchy(indent: Int=0) {
    print("\(String(repeating: "  ", count: indent))\(name)")
    for each in children {
        each.printHierarchy(indent: indent + 1)
    }
}

Our output becomes:

Topmost
  n1
  n2
    n3
      n4

This is especially useful when we are logging more information in each node to debug method calls up and down the hierarchy.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you perform your own custom view draw by overriding UIView draw(_:) in your subclass, and you trigger it by calling setNeedsDisplay(_:), it's a performance boost if you restrict drawing to just the dirty rectangle passed to draw(_:):

override func draw(_ rect: CGRect) {
    //Only draw inside rect, and not the entire UIView specified by the `bounds` property
}

On macOS, the functions getRectsBeingDrawn(_:count:) and needsToDraw(_:) can be used to discover whether you want to draw, but they are not available on iOS.

I've found that a simple way the handle this is to set the dirty rect as the clipping region:

override func draw(_ rect: CGRect) {
    let context = UIGraphicsGetCurrentContext()
    context?.saveGState()
    let path = UIBezierPath(rect: rect)
    path.addClip()
    //Perform your drawing in `bounds` here
    context?.restoreGState()
}

I'm recently building an app that involves panning many views that implement custom drawing and just introducing clipping makes the performance improve from being dog slow to buttery smooth.

And if you want to go one step further, you can use the "context" technique I mentioned in #168 to clean up the code:

Implement this:

func withGraphicsContext(block: (CGContext?) -> ()) {
    let context = UIGraphicsGetCurrentContext()
    context?.saveGState()
    block(context)
    context?.restoreGState()
}

And you can rewrite draw(_:):

override func draw(_ rect: CGRect) {
    withGraphicsContext { context in
        let path = UIBezierPath(rect: rect)
        path.addClip()
        //Perform your drawing in `bounds` here
    }
}

There is a technote which mentions:

Each UIView is treated as a single element. When you request a redraw, in part or whole, by calling -setNeedsDisplayInRect: or -setNeedsDisplay:, the entire view will be marked for updates

I did some testing and it seems like the statement is either outdated or wrong. But even if it becomes true in the future, clipping wouldn't break your code. So happy drawing!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In #232 we looked at how we can use Shared Web Credentials to share login information between your iOS app and Safari by reading/writing to the keychain.

There's a new feature in iOS 11 for apps called Password AutoFill. It lets iOS populate your username and password fields with information from the keychain chosen by the user with a single tap. This goes one step further to reduce the friction for users to move from using your website to running your app.

If you have seen this Password AutoFill QuickType bar in an app, it is AutoFill in action:

If you tap the button, it should attempt to authenticate using Touch ID and then show you a list of logins to choose from to fill in to the login form. If the app haven't done anything to enable AutoFill, iOS uses some heuristics to try to make it work.

You might even see some a username appearing in the AutoFill QuickType bar, letting you tap on it to choose it right away.

This is all done automatically by iOS

But if want to be sure AutoFill works correctly and show the correct username to the user in the AutoFill QuickType bar, you can set this up explicitly by:

1) Setting the content type of yoru username and password field:

usernameField.textContentType = .username
passwordField.textContentType = .password

2) Enable the associated domains entitlements in Xcode and set up a site associate file on your website. You would have done this if you have already set up Shared Web Credentials.

If you visit the login screen in your app again, you should notice the AutoFill QuickType bar pop up correctly and the username matching your app should appear.

Here's the WWDC video explaining Password AutoFill if you need more details.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In UIView and its subclasses, there are many properties — such as frame and alpha — that can be animated when they change. i.e. you can do something this and changes will be animated:

UIView.animate(withDuration: 2) {
    self.label.frame = CGRect(x: 150, y: 200, width: 50, height: 20)
    self.button.tintColor = .white
}

Unfortunately, this doesn't work for UILabel's color property. Here's the good news: You can approximate this using transition(with:duration:options:animations:completion:) instead:

UIView.transition(with: label, duration: 2, options: .transitionCrossDissolve, animations: {
    self.label.textColor = .red
}, completion: nil)

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.


I first read about this idea of namespacing using enums in the article Easy Namespacing in Swift by @khanlou.

For example, for my library Zhi,

I have a file which only has these 2 lines to create a "namespace":

public enum Zhi {
}

Then in other files, I can do this to add to the namespace:

public extension Zhi {
    class StyleParser {
        //...
    }
}

As mentioned in the article, a major limitation is it doesn't work for protocols. So this doesn't work:

public extension Zhi {
    protocol P {}
}

But otherwise, using enums as a namespace is a great way to organize your code.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I wrote a library for working with Auto Layout in Swift. It lets you tweak Auto Layout constraints and watch your app update immediately without a rebuild + run cycle. It’s called Zhi.

The library allows you to specify your auto layout constraints in separate .styles files. It supports:

  • Live reloading of Auto Layout constraints as you save the .styles files, without a rebuild + run cycle
  • Apple's Visual Format Language: H:[p(==v2)]|
  • Support an equations-based syntax: v1.width = v2.width + 10

In addition, the .styles files also support:

  • Metrics can be specified
  • Colors — rgb(), rgba() or named colors in UIColor, e.g. red
  • Image filenames
  • Button title and label text
  • Font name, size
  • Dynamic type style names, e.g. callout or caption1
  • and more

This means that you can tweak these properties without rebuilding your app during development.

Refer to the README for installation and usage.

Try it out and let me know what you think.

I created a Patreon page. I have been writing iOS Dev Nuggets for more than 5 years. If you want to support me, visit Patreon and consider pledging.

As usual, any tips or comments are welcomed via email.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In Swift, the lazy keyword changes a property so that it is only calculated when it's accessed. This not only makes it useful for performance reasons, it's also incredibly useful for initializing your class when a non-optional property depends on another property for initialization.

Let's look at an example:

class C {
    var x: UIView
    var y: UIView = {
        var v = UIView()
        x.addSubview(v)
        return v
    }()

    init() {
        x = UIView()
    }
}

This class definition compiles with an error because the value of x is used when computing the value of y:

error: instance member 'x' cannot be used on type 'C'

This wouldn't work even if you change the definition of x to:

var x = UIView()

There's an easy fix — just change y to be lazy:

class C {
    var x: UIView
    lazy var y: UIView = {
        var v = UIView()
        x.addSubview(v)
        return v
    }()

    init() {
        x = UIView()
    }
}

Because lazy properties are only calculated when they are first used — and you don't use them in your initializer before x is initialized, this is a very simple fix.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


When creating iOS app preview videos, it's sometimes useful to where your fingers touches on the screen. This is particularly useful if you have multi-finger gestures involved.

There are several libraries that let you do this, one of them is EUMTouchPointView.

Integrating the library is simple. Instead of creating a UIWindow instance, create a EUMShowTouchWindow instance.

When you run your app, touch indicators will appear.

Remember to exclude the library for your app store submission.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


One of the most common way to reduce coupling when creating a new class is to create a delegate(s) for it. This is a common pattern used in Cocoa (Touch) classes, from simple examples like UIImagePickerController and UIImagePickerControllerDelegate to more complicated examples like UITableView and UITableViewDelegate, and UITableViewDataSource.

You can implement delegates using protocols. e.g.

protocol DelegateOfA {
    func onSomethingHappened()
}

class A {
    var delegate: DelegateOfA?

    init() {}
    func doSomething() {}
}

Use them like this:

class SomeDelegate: DelegateOfA {
    func onSomethingHappened() {
        print("I know something happened")
    }
}

let aDelegate = SomeDelegate()

let a = A()
a.delegate = aDelegate
a.doSomething()

//And this may/will be invoked somehow and fire your delegate methods:
//a.delegate?.onSomethingHappened()

One thing I have done more recently is to use blocks for these delegates:

class A {
    var onSomethingHappened: (()->())?

    init() {}
    func doSomething() {}
}

Use it like this:

let a = A()
a.onSomethingHappened = {
    print("I know something happened")
}
a.doSomething()

//And this may/will be invoked somehow and fire your delegate blocks:
a.onSomethingHappened?()

The overall code is slightly shorter, but more importantly, both the object creation of A and the delegate code are close together, making it easier to read, understand and maintain.

Try it out!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Picked up this tip from @cabel related to sudo:

If you have a Macbook Pro with Touch ID (i.e. Touch Bar) support, you can enable Touch ID for sudo by adding this line as the 1st line after auth sufficient pam_tid.so in the file /etc/pam.d/sudo:

auth sufficient pam_tid.so

If Touch ID prompt doesn't appear until you keyed in the wrong password, chances are you added the line correctly, but not at the top.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes we want a simple confirmation if a line of code has been reached, especially when we need to test on device, untethered. One trick I like to use is to play a system sound:

import AudioToolbox

AudioServicesPlaySystemSound(1109)

Of course, if you are tethered, you can use a breakpoint to play a sound.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you create a struct and have a property that is of the same type, e.g:

struct Node {
    var parent: Node?
    init() { }
}

You get this error:

value type 'Node' cannot have a stored property that recursively contains it

There are a few ways to work around this. One is to use a "box" class:

class Box<T> {
    var value: T
    init(value: T) {
        self.value = value
    }
}

And change your Node struct to:

struct Node {
    var parent: Box<Node>?
    init() { }
}

Alternatively, wrap it with an array:

struct Node {
    var parent = [Node]()
    init() { }
}

But when you see this error, it's also good to reflect on whether you are building your data structure correctly. in this example our struct is called Node, naturally nodes may refer to their parent. But since structs are value types, we are always copying the parent. If we build a tree of nodes, this copying behavior is not what we want. The simpler and probably more correct answer here is to just Node to be a class instead:

class Node {
    var parent: Node?
    init() { }
}

This will remove the error and more importantly, provide the correct semantics.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Often when comparing implementations of the same function, I need to do some simple profiling to compare the total time taken. The simplest approach is to create a Date instance before and after the operation and calculate the difference. These are usually long operations and I want to track progress. This becomes a bit more troublesome when the operation is asynchronous. So I wrote a simple class to help:

import Foundation

class ProgressReporter {
    let startTime = Date()
    var name: String
    var total: Int
    var step: Int

    init(name: String, total: Int = -1, step: Int = 100000) {
        self.name = name
        self.total = total
        self.step = step
        print("\(name.firstUppercased)...")
    }

    func update(current: Int, completion: (()->())? = nil) {
        if current % step == 0 {
            print("Progress \(current)/\(total)")
        }
        if current == total {
            completed()
            completion?()
        }
    }

    func completed() {
        print("Completed")
        print("Time taken to \(name): \(Date().timeIntervalSince(startTime)) secs")
    }
}

extension String {
    var firstUppercased: String {
        guard let first = first else { return "" }
        return String(first).uppercased() + dropFirst()
    }
}

You can use it like this:

func getFileNames(someInput: [String]) {
    let progress = ProgressReporter(name: "get filenames", total: someInput.count)
    var results = [String]()
    for e in results {
        someAsyncOperation(e) {
            progress.update(current: results.count) {
                //do something with results
            }
        }
    }
}

It'll print something like this:

Get filenames
Progress 100000/2000000
Progress 200000/2000000
Progress 300000/2000000
...
Progress 2000000/2000000
Completed
Time taken to get filenames: 100 secs

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Do you sometimes have this need: edit a file or a few files in one application and then switch to another app and want to select those files? E.g. you edit iOS app screenshots in a graphics editor and then want to upload them in Safari.

Then this tip is for you:

  1. File > New Smart Folder
  2. Click This Mac
  3. Click +
  4. Click Kind and change it to Last modified date
  5. Make sure within last is selected
  6. Enter 1 (days)
  7. View > as List
  8. Click the Date Last Opened column header to sort descending
  9. Click Save
  10. Make sure Add to Sidebar is checked
  11. Enter a name (e.g. Recent) and click Save

The Recent smart folder should appear in your Finder sidebar.

With our example, after editing you just need to click the Recent smart folder either in Finder (or in other cases the Open file dialog) to access the most recently modified files.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


This is a continuation of #260 where I talk about including the app version and device Name in feedback/support emails. After thinking about it, I created Apple Device Names. It provides a simple API that maps iPhone10,6iPhone X.

It's just a curl command away:

$ curl http://appledevicenames.com/device/iPhone10,6

iPhone X

So to generate something like this:

For info/diagnostic purposes:
  App v1.0.0 build 23 on iPhone X, iOS 11.0.3

You can do this in Swift:

//Stick this somewhere
private func deviceModel() -> String? {
    var keys = [CTL_HW, HW_MACHINE]
    var requiredSize = 0
    let fetchSizeResult = sysctl(&keys, UInt32(keys.count), nil, &requiredSize, nil, 0)
    guard fetchSizeResult == 0 else { return nil }
    var data = [CChar](repeating: 0, count: requiredSize)
    let fetchResult = sysctl(&keys, UInt32(keys.count), &data, &requiredSize, nil, 0)
    guard fetchResult == 0 else { return nil }
    return String(validatingUTF8: data)
}

//Stick this somewhere
func withDeviceName(block: @escaping (String) -> Void)  {
    let fallbackName = "Unknown"
    if let model = deviceModel(),
    let url = URL(string: "https://appledevicenames.com/device/\(model)") {
        URLSession.shared.dataTask(with: url) { data, _ , _ in
            DispatchQueue.main.async {
                if let data = data, let name = String(data: data, encoding: .utf8) {
                    block(name)
                } else {
                    block(fallbackName)
                }
            }
        }.resume()
    } else {
        block(fallbackName)
    }
}

//Calling code
withDeviceName { deviceName in
    let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
    let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")
    let osVersion = UIDevice.current.systemVersion
    if let appVersion=appVersion, let buildNumber=buildNumber {
        let body = "For info/diagnostic purposes:\n  App v\(appVersion) build \(buildNumber) on \(deviceName), iOS \(osVersion)"
        //body = "For info/diagnostic purposes:\n  App v1.0.0 build 23 on iPhone X, iOS 11.0.3"
        //Use body
    }
}

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


There's always been an app size limit for cellular downloads. It's 150 MB as of writing.

For those who are along the borderline, here's a great way to check how big your app is:

  1. Go to iTunes Connect
  2. My Apps
  3. Click the app
  4. Click Activity
  5. Under All Builds
  6. Click the version number to expand
  7. Click on the build
  8. Click App Store File Sizes

This reveals a list of device types and their corresponding download sizes.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In my apps, I include a button for users to send me feedback emails. I will pre-fill the email with a line like this:

For info/diagnostic purposes:
    MY_APP_NAME v1.0 build 101 on iPad Pro 9.7 Wifi + Cellular, iOS 10.0

This provides some basic information that can help me understand their issue or feedback better.

I generate this with code like this:

let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")
let osVersion = UIDevice.current.systemVersion
if let appVersion=appVersion, let buildNumber=buildNumber {
    let body = "For info/diagnostic purposes:\nMY_APP_NAME v\(appVersion) build \(buildNumber), iOS \(osVersion)"
    //Use body
}

If you want to include the device name (iPhone X, etc) property, you can use https://github.com/InderKumarRathore/DeviceGuru.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In #135 CAShapeLayer, Animated Views and XCPShowView(), we spoke about using CALayer and UIBezierPath to draw and animate outlines.

Here's another common thing you can do with it — Rounded corners:

let canvas = UIView()
canvas.frame = CGRect(x: 0, y: 0, width: 200, height: 300)
canvas.backgroundColor = .blue

let v2 = UIView()
v2.frame = CGRect(x: 20, y: 20, width: 50, height: 60)
v2.backgroundColor = .red
v2.layer.cornerRadius = 8
canvas.addSubview(v2)

And if you only want to round certain corners, use UIRectCorner:

let v3 = UIView()
v3.frame = CGRect(x: 20, y: 100, width: 50, height: 60)
v3.backgroundColor = .green
canvas.addSubview(v3)

let cornerRadius = 12
let layer = CAShapeLayer()
layer.path = UIBezierPath(roundedRect: v3.bounds, byRoundingCorners: [.topLeft, .bottomRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)).cgPath
v3.layer.mask = layer

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


This guide from PaintCode is a useful graphical illustration of various iPhone sizes, now updated to include iPhone 8 (Plus) and iPhone X.

There's also additional notes about the iPhone X here.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.


In Obj-C, you can use asserts like this:

NSAssert([self foo], @"Something something");

Similarly in Swift:

assert(foo())

In Obj-C, asserts are controlled by ENABLE_NS_ASSERTIONS (Enable Foundation Assertions in Xcode Build Settings) which is default to NO in release builds.

But in Swift, asserts are controlled by the Swift optimization level. With a release build — which defaults SWIFT_OPTIMIZATION_LEVEL (Swift Compiler - Code Generation > Optimization Level) to -O, the assert() doesn't run. It runs with -Onone.

It's not complicated once we realise these are 2 different flags, but it's still a good practice to only run code which has no side effects with an assert to present such errors.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


iOS 11 introduces a new class SFAuthenticationSession which supports Single Sign On (SSO) securely.

It's simple to use!

NSURL* url = [NSURL URLWithString:@"https://the_url_end_point_for_authentication_with_tokens_etc"];
[[SFAuthenticationSession alloc] initWithURL:url callbackURLScheme:nil completionHandler:^(NSURL *callbackURL, NSError *error) {
    //Inspect callbackURL to get the access tokens, etc for the login session
}];

A major benefit of using SFAuthenticationSession is that it runs in a separate process so the user can be confident that the app does not have a way to sniff the password. This is very useful for login protocols such as OAuth or SSO across multiple related applications.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


One of the easiest ways to start hunting down memory leaks is to see if a view controller is not being deallocated. Most common reason being an object stored in an instance variable is (in)directly holding a reference the view controller.

Here's a tip I picked up from @0xced:

Create an Xcode symbolic breakpoint and set the following values:

  • Symbol: -[UIViewController dealloc]
  • Add an Action: Log Message
  • Action value: --- dealloc @(id)[$arg1 description]@ @(id)[$arg1 title]@
  • Add another Action: Sound
  • Sound: Choose a sound

If you pop or dismiss a view controller and don't hear the sound, there's a leak.

Thanks @0xced!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Most apps have to work with web APIs. Paw is a HTTP client with a GUI. It lets you set up projects. You can run and inspect API calls and even let it generate Objective-C/Swift code making those API calls for you, which you can copy to your own codebase. I like to use it as a live document. Making API calls with both valid and invalid parameters and inspecting the results.

It's a wonderful tool to make working with APIs easier.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


The HTTPS/2-based push provider API introduced in 2015 has a very nice addition — instead of using certificates for push provider authentication, you can also use JSON Web Tokens (JWT).

To use token-based authentication, you need to generate a key [1] in Apple developer member center. Keys/tokens has two benefits over certificates:

  • Keys are tied to a developer account, not to a specific app. A token-based connection to the HTTPS/2 API can be used to send push notifications to all your apps.
  • Keys don't expire. But you are required to regenerate tokens within the hour.

If you manage your own push provider infrastructure, using tokens can be very helpful.

Refer to Apple doc on Communicating with APNs for details.

[1] It can be slightly confusing. "Key" is actually a certificate too.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Using in-app routing is a good way to decouple your UI navigation code from your view controllers. It's good to go further and make sure your view controllers don't rely too much on one another. Here's one trick that I have found useful:

When I create a new view controller, I develop and test it by setting my UIWindow instance's rootViewController to an instance of the view controller. e.g.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    //...
    //Comment out actual root view controller
    //self.window.rootViewController = [ActualRootViewController new];
    TheNewViewController* vc = [TheNewViewController new];
    //Set up view controller
    vc.photoId = @"123";
    self.window.rootViewController = vc;
    [self.window makeKeyAndVisible];
    return YES;
}

The first benefit is you can test it immediately when the app launches, making iterations faster. Equally important: it becomes near impossible to write code that is tightly coupled to this new view controller because you are not using it at the actual call site (yet).

Have fun!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


During development, I often want to retrieve the view controller that is currently displayed. This is rather vague — it could mean the view controller at the top of the stack of the current UINavigationController, the currently presented view controller, etc. So I wrote this function which figures it out most of the time:

func currentViewController(_ viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
    guard let viewController = viewController else { return nil }

    if let viewController = viewController as? UINavigationController {
        if let viewController = viewController.visibleViewController {
            return currentViewController(viewController)
        } else {
            return currentViewController(viewController.topViewController)
        }
    } else if let viewController = viewController as? UITabBarController {
        if let viewControllers = viewController.viewControllers, viewControllers.count > 5, viewController.selectedIndex >= 4 {
            return currentViewController(viewController.moreNavigationController)
        } else {
            return currentViewController(viewController.selectedViewController)
        }
    } else if let viewController = viewController.presentedViewController {
        return viewController
    } else if viewController.childViewControllers.count > 0 {
        return viewController.childViewControllers[0]
    } else {
        return viewController
    }
}

Call it with:

currentViewController()

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


There's a great technote from Apple that collects many useful pieces of information about Push Notifications in a single place.

Eg. ports used for push:

  • 2195 for binary provider API
  • 443 for HTTP/2 provider API
  • 5223 and 443 for devices receiving push
  • 80 inbound + outbound for OS X

That the entire 17.0.0.0/8 address block is assigned to Apple (useful for firewall rules)

and how to reset the push notification permissions alert on iOS:

The first time a push-enabled app registers for push notifications, iOS asks the user if they wish to receive notifications for that app. Once the user has responded to this alert it is not presented again unless the device is restored or the app has been uninstalled for at least a day.

If you want to simulate a first-time run of your app, you can leave the app uninstalled for a day. You can achieve the latter without actually waiting a day by following these steps:

  1. Delete your app from the device.
  2. Turn the device off completely and turn it back on.
  3. Go to Settings > General > Date & Time and set the date ahead a day or more.
  4. Turn the device off completely again and turn it back on.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Supporting App Transport Security is important. But not all the keys are obvious.

Here's where nscurl comes in. Mentioned in the same page above, running nscurl --ats-diagnostics --verbose <URL> shows you diagnostics output which will help you determine which keys and values you need to specify for ATS. e.g.:

Default ATS Secure Connection
---
ATS Default Connection
ATS Dictionary:
{
}
Result : PASS
---

================================================================================

Allowing Arbitrary Loads

---
Allow All Loads
ATS Dictionary:
{
    NSAllowsArbitraryLoads = true;
}
Result : PASS
---

================================================================================

Configuring TLS exceptions for httpbin.org

---
TLSv1.2
ATS Dictionary:
{
    NSExceptionDomains =     {
        "httpbin.org" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.2";
        };
    };
}
Result : PASS

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


While shipping an app in a timely manner should be our top priority, writing well structured code is critical for maintaining and improving your app in the long run. One way to do this is to decouple UI navigation code from your view controllers via a router, so your view controllers know less about each other.

routable-ios by @clayallsopp is a good library for this.

You set up the router in a centralized location, e.g. in your app delegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:[SomeViewController new]];
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = nc;
    [self.window makeKeyAndVisible];

    [[Routable sharedRouter] map:@"users/:username" toController:[UserViewController class]];
    [[Routable sharedRouter] map:@"places/:id" toController:[PlaceViewController class]];
    [[Routable sharedRouter] setNavigationController:nc];
}

Instead of writing code like this to display a user:

- (void)openUserWithUsername:(NSString*)aString {
    UserViewController* vc = [UserViewController new]
    vc.username = aString;
    //Or worse, you may need to figure if you have a navigation controller here
    [self.navigationController pushViewController:vc animated:YES];
}

You do this, without coupling the current view controller to UserViewController:

- (void)openUserWithUsername:(NSString*)aString {
    NSString* url = [NSString stringWithFormat:@"users/%@", aString];
    [[Routable sharedRouter] open:url];
}

UserViewController needs to implement -initWithRouterParams: to accept the routing argument(s):

- (id)initWithRouterParams:(NSDictionary*)params {
    if ((self = [self initWithNibName:nil bundle:nil])) {
        self.username = [params objectForKey:@"username"];
    }
    return self;
}

There are a few more options listed in the README.

You can install it using CocoaPods.

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes an ASCII table comes in handy. You have one right at your fingertips. Type in a shell:

man ascii

I picked up this tip from @captainsafia. Thanks Safia!

Update: I fixed a few typos in the code for issue #246. Check the updated version in the archives.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you have been writing Obj-C for a while, you should know that it is a good idea to prefix method names of methods what you define a class extension. eg.

@interface UIViewController (MyViewControllerExtension)

- (void)rsConstraintHeightTo:(CGFloat)height;

@end

Naturally, this gets translated to the following when you call the method in Swift:

rsConstraintHeight(to: 10.0);

What if you wanted to write this:

constraint(height: 10.0);

You can do it by changing your Obj-C declaration to use the NS_SWIFT_NAME macro:

@interface UIViewController (MyViewControllerExtension)

- (void)rsConstraintHeightTo:(CGFloat)height NS_SWIFT_NAME(constraint(height:));

@end

Notice that you can map both the method name and the argument.

Similarly, when you expose a method written in Swift to Obj-C, you can map the method name by including the desired method name with the @objc attribute:

//Instead of just @objc, use:
@objc(rsFoo)
func foo() {}

Then in Obj-C:

[self rsFoo];

This can also be used for mapping enum values from Obj-C to Swift. Refer to the docs under Overriding Swift Names for Objective-C Interfaces for more details.

I picked up this tip from Michel Fortin. Thanks Michel!


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


There's a handy little tool in Xcode hidden in the Find menu called Find Call Hierarchy. When invoked (shortcut keys: Ctrl-shift-cmd-h), it displays the call hierarchies for the method under the cursor.

There are often false positives, but it's still very useful.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


When we write a for-in loop like this:

for each in someCollection {
    //...
}

Swift calls the makeIterator() method on the collection and then make repeated calls next() on the result until it returns nil.

The object returned by the makeIterator() is of a type that conforms to the IteratorProtocol protocol.

You can make use of IteratorProtocol directly. For example, if you might a list of values and you want to be able to pick the next value from the list and perform an action with it. You could implement this using list-like collection, often a FIFO queue. Alternatively, with iterators:

var i = [1, 2, 3].makeIterator()
i.next() //1
i.next() //2
i.next() //3
i.next() //nil, we are done

Have fun!


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes you put a delayed operation being a flag which you can clear to cancel. It might look like this:

- (void)primeOperation {
    self.flag = YES;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, someTimeInSecs * NSEC_PER_SEC), dispatch_get_main_queue(), ^() {
        if (self.flag) {
            self.flag = NO;
            //do something
        }
    });
}

But the problem with this approach is after if you clear the flag and set up the operation again soon enough, you will end up with running that operation twice:

- (void)doSomething {
    [self primeOperation];
    self.flag = NO;
    [self primeOperation];
}

One of the ways to work around this is to create an NSOperation subclass.

Alternatively, you can create a lightweight class that wraps around a BOOL:

@interface BoolWrapper: NSObject

@property(nonatomic) BOOL state;
+ (instancetype)wrapperWithBool:(BOOL)state;

@end

@implementation BoolWrapper

+ (instancetype)wrapperWithBool:(BOOL)state {
    BoolWrapper* result = [self new];
    result.state = state;
    return result;
}

@end

You can change your code so that flag is now an instance of BoolWrapper:

- (void)primeOperation {
    self.flag = [BoolWrapper wrapperWithBool:YES];
    BoolWrapper* previousFlag = self.flag;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, someTimeInSecs * NSEC_PER_SEC), dispatch_get_main_queue(), ^() {
        if (self.flag == previousFlag && self.flag.state) {
            self.flag = [BoolWrapper wrapperWithBool:NO];
            //do something
        }
    });
}

This will now work since the identity check self.flag == previousFlag takes care that we are referring to the same "operation".


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


2 tips today, but about Finder.app rather than iOS app development :)

  1. If you hit F5 in Finder, the last item in the current directory will be selected and Finder will scroll to it. This should work with most function keys, but it seems like all of them will beep except F5. This selection and scrolling behavior puzzled me for years until it was explained to me: it's just Finder searching for a match alphabetically. If no match is found, it selects the last item and scrolls to it.

  2. Hit cmd+shift+. to show hidden files in Finder.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I like to use Swift enums to encode states and operations related to them since Swift enums are types that can have methods attached to them. I learnt one thing about enums recently, that enums with associated values can have labels. The Swift Programming Language book doesn't seem to mention this.

Eg. You have might an enum called Feeling with 3 cases.

enum Feeling {
    case happy(String, Int)
    case normal
    case unhappy(String, Int)
}

let theFeels1 = Feeling.normal
let theFeels2 = Feeling.happy("Because the weather is perfect", 2)

As you add more associated values, you start to lose track of what each value represents.

enum Feeling {
    case happy(String, String, Int, Int)
    case normal
    case unhappy(String, Int)
}

You can create a different struct for each case and pass in a struct instance.

Alternatively, you can add labels!

enum Feeling {
    case happy(reason: String, activity: String, numberOfPeopleWIthYou: Int, score: Int)
    case normal
    case unhappy(reason: String, score: Int)
}

Then you can/have to use labels when creating instances:

let theFeel = Feeling.happy(reason: "Because the weather is perfect", activity: "grocery shopping", numberOfPeopleWIthYou: 0, score: 2)

They look better when you dump() them:

dump(theFeel)

__lldb_expr_86.Feeling.happy
  ▿ happy: (4 elements)
    - reason: "Because the weather is perfect"
    - activity: "grocery shopping"
    - numberOfPeopleWIthYou: 0
    - score: 2

You can (optionally) use the labels in a switch statement if you want to. It checks that the label matches. Notice that score doesn't use a label.

switch theFeel {
case .happy(reason: let reason, _, _, let score):
    print("happy \(reason) with score: \(score)")
case .unhappy:
    print("unhappy")
case .normal:
    print("normal")
}

Interestingly, you don't have to have labels for every value, but I can't think of a good reason to use this:

enum Feeling {
    case happy(reason: String, String, Int, score: Int)
    case normal
    case unhappy(reason: String, score: Int)
}


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes, in Swift — especially for debugging — you will want to see if 2 objects references you are holding are actually referring to the same object. The ObjectIdentifier struct is useful for this.

var o1 = NSObject()
var o2 = o1
var o3 = NSObject()
print("o1's \(ObjectIdentifier(o1).debugDescription)")
print("o2's \(ObjectIdentifier(o2).debugDescription)")
print("o3's \(ObjectIdentifier(o3).debugDescription)")

You'll get something a unique identifier for each object instance like this and you can see that o1 and o2 refers to the same instance.

o1's ObjectIdentifier(0x0000608000001620)
o2's ObjectIdentifier(0x0000608000001620)
o3's ObjectIdentifier(0x0000610000001530)

Note that ObjectIdentifier doesn't work for value types like structs and enums.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


This tip is if you work with Core Location and wants to continue receiving location updates while the app is suspended.

You need to add the UIBackgroundModes key with value location to the app's Info.plist. In addition, — this is easy to miss because it was only added in iOS 9 — you want to set CLLocationManager's allowsBackgroundLocationUpdates property to true. In addition to getting updates while the app is suspended, if the app is killed and the device crosses the CLRegion you are monitoring, the app will be automatically launched. So this property is also useful for toggling that behavior.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.


I first read about keep the code in a method at the same level of abstraction in the book Smalltalk Best Practice Patterns. But here's an alternative online explanation:

E.g. A method with body written at more than 1 level of abstraction:

public List<ResultDto> buildResult(Set<ResultEntity> resultSet) {
    List<ResultDto> result = new ArrayList<>();
    for (ResultEntity entity : resultSet) {
        ResultDto dto = new ResultDto();
        dto.setShoeSize(entity.getShoeSize());        
        dto.setNumberOfEarthWorms(entity.getNumberOfEarthWorms());
        dto.setAge(computeAge(entity.getBirthday()));
        result.add(dto);
    }
    return result;
}

The same method refactored to 2 separate methods, each with its body written at the same level of abstraction:

public List<ResultDto> buildResult(Set<ResultEntity> resultSet) {
    List<ResultDto> result = new ArrayList<>();
    for (ResultEntity entity : resultSet) {
        result.add(toDto(entity));
    }
    return result;
}

private ResultDto toDto(ResultEntity entity) {
    ResultDto dto = new ResultDto();
    dto.setShoeSize(entity.getShoeSize());        
    dto.setNumberOfEarthWorms(entity.getNumberOfEarthWorms());
    dto.setAge(computeAge(entity.getBirthday()));
    return dto;
}

The problem with the original code:

There are two levels of abstractions in this method. First there is the loop which acts upon the whole result set and second there is the loop body which converts a single entity to a DTO. For the latter there is no syntactical grouping. The reader of the code has to find out that the first four lines of the loop body belong together. The code also doesn't explicitly state that these four lines convert an entity to a DTO. So the following code is better:

And the refactoring helps to improve things:

Now there are two smaller methods each of which is written in terms of a single level of abstraction. This is better readable as no mental grouping is necessary. Furthermore the two methods are still separately understandable (PSU) so no mental inlining is necessary and if you don't care about the details of the toDto method, you can just read and understand buildResult without being distracted by unnecessary detail.

(The code looks like its Java, but should be easy to read if you know Swift or Obj-C)


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Found this tool called mas-cli which provides a command line interface to the Mac App Store. You can install via Homebrew:

$ brew install mas

You can list apps:

$ mas list

443987910 1Password (6.6.4)
587512244 Kaleidoscope (2.1.0)
405399194 Kindle (1.12.4e)

Or upgrade a specific app:

$ mas upgrade 405399194

Or you can update everywhere app (including Xcode):

$ mas upgrade

Don't forget the option to run multiple versions of Xcode side-by-side by getting it directly from Apple's Developers Website.

Learn more about cli-mas.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


While developing for iOS (or macOS/watchOS/tvOS), do you sometimes see an error code returned by an Apple API and wonder what it is? Check out OSStatus. You can search for them, say -1004.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Continuing from #103 and #163, another useful argument to pass at launch is -NSShowNonLocalizedStrings YES. This will make every string returned by NSLocalizedString() be capitalized if it isn't localized. A wonderful way to find any strings that aren't localized yet.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In many apps, you'd often want to support the newest 2 major iOS versions (or more).

In the earlier days, in Obj-C, you could check directly — using NSProcessInfo — the iOS version number and see which features are available. Then Apple recommended for us to check directly if a feature is available by checking if a class or an object responds to specific selectors instead of checking iOS version numbers.

With Swift, the official recommendation switches back to checking iOS version numbers again with the use of #available. Not only can you use #available to check against iOS version numbers at runtime in Swift, you can apply the @available attribute to Swift functions and methods to indicate the minimum iOS version it requires. e.g.

@available(iOS 9, *)
func functionThatRequiresiOS9() {
    if #available(iOS 10, *) {
        functionThatRequiresiOS10()
    }
}

There are other uses of @available, for example in Swift 3.1, the @available attribute has been expanded to support Swift language versions. This is useful primarily for library authors:

@available(swift, obsoleted: 3.1)
func functionThatIsObsoleteIn3Dot1andLater() {
}

PS: everything above applies to watchOS, tvOS and macOS too.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I'm a fan of not using Interface Builder/Storyboards and creating views in code, maintaining a separate view hierarchy alongside the hierarchy of view controllers in your app. I wrote a post about not using Interface Builder a few years ago. It's been a few years, so some of it might be outdated, but the premise remains the same.

Soroush Khanlou talks in more detail about pushing some of view controller's responsibility into its views in Smarter Views and is very relevant. Check it out.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In iOS 8, Apple has added Shared Web Credentials which lets you share login information between your iOS app and Safari. Adding support for Shared Web Credentials consists of 2 parts:

  1. Serving up a site association file on your website.
  2. Reading/writing to the keychain in your iOS app.

Note that sharing of login is 2-way, so when your user logs in manually with username/password or changes password in your app, it's also helpful to save it into the keychain so your website can use it (when accessed with Safari).

Detailed instruction is available at Apple.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Have you ever looked at some text in an app or website and wondered what that font is? You may like WhatTheFont then. You can take a photo or screenshot and let the app figure it out for you.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Hitting cmd+opt+/ in Xcode while the cursor is on a type or function declaration will generate a quick help documentation for you. E.g.

With a function like this:

func foo(name: String) -> Int {}

This is generated:

/// Description
///
/// - Parameter name: name description
/// - Returns: return value description

Works with both Swift and Obj-C.

PS: This shortcut might already be used by another app. E.g. Alfred uses this for one of it's shortcuts. It's available via Editor > Structure > Add Documentation, so you can reassign a different shortcut.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Heard of Promises?

If you haven't, here's an example of what promises help to improve:

fetchUserId({ id in
    fetchUserNameFromId(id, success: { name in
        fetchUserFollowStatusFromName(name, success: { isFollowed in
            // The three calls in a row succeeded YAY!
            reloadList()
        }, failure: { error in
            // Fetching user ID failed
            reloadList()
        })
    }, failure: { error in
        // Fetching user name failed
        reloadList()
    })
}) {  error in
    // Fetching user follow status failed
    reloadList()
}
🙉🙈🙊#callbackHell

With promises, you can write something like:

fetchUserId()
    .then(fetchUserNameFromId)
    .then(fetchUserFollowStatusFromName)
    .then(updateFollowStatus)
    .onError(showErrorPopup)
    .finally(reloadList)

Basically, without the ever-increasing indentation, making flow control clearer.

Another example is when you fire off several network calls in parallel and only want to act (eg. display them on screen) when results from all of them have been returned. Promises let you do something like this:

whenAll(fetchHeaderInformation(), fetchBodyInformation(), fetchFooterInformation()).then { allInfo in
  //All the results are ready
}

The async example code above was taken from the freshOS repository README.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Did you know that since iOS 2, there's a class included in Foundation called NSURLProtocol?

From the docs:

An NSURLProtocol object handles the loading of protocol-specific URL data. The NSURLProtocol class itself is an abstract class that provides the infrastructure for processing URLs with a specific URL scheme. You create subclasses for any custom protocols or URL schemes that your app supports.

Basically, it lets you implement a proxy for URL loading in your app. How does that help?

  1. I like to work offline — without connectivity to focus — sometimes. But most apps need to at least make a network request or two and fetch some data via an API call. You can use NSURLProtocol to do just that.
  2. Alternatively, you might be have automated tests that makes network calls. You'll generally want those to be deterministic and playing back a known, static version using NSURLProtocol is very useful.

There's a library that does just that — VCRURLConnection. From the README, here's how you make a recording:

[VCR start];

NSString *path = @"http://example.com/example";
NSURL *url = [NSURL URLWithString:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

// use either NSURLSession or NSURLConnection
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request];
[task resume];

// NSURLSession makes a real network request and VCRURLConnection
// will record the request/response pair.

// once async request is complete or application is ready to exit:
[VCR save:@"/path/to/cassette.json"]; // copy the output file into your project

You can play it back with:

NSURL *cassetteURL = [NSURL fileURLWithPath:@"/path/to/cassette.json"];
[VCR loadCassetteWithContentsOfURL:cassetteURL];
[VCR start];

// request an HTTP interaction that was recorded to cassette.json
NSString *path = @"http://example.com/example";
NSURL *url = [NSURL URLWithString:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

// use either NSURLSession or NSURLConnection
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request];
[task resume];

// The cassette has a recording for this request, so no network request
// is made. Instead NSURLConnectionDelegate methods are called with the
// previously recorded response.

It's available over Carthage and Cocoapods. Pretty handy isn't it?


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes you want to make a subview have rounded corners. An easy way to do this is:

v.backgroundColor = bgColor
v.layer.cornerRadius = 7
v.layer.masksToBounds = true

This works well most of the time, but you run into performance degradation when you render more complex subviews with rounded corners, e.g many UILabels with rounded corners in a UITableView with many cells.

An easy way around this issue is to switch of masksToBounds and set the background on the layer instead of the view:

v.layer.backgroundColor = bgColor.cgColor
v.layer.cornerRadius = 7


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In #77, I mentioned RubyMotion as an alternative for building iOS (and now OS X and Android) apps. Since it generates native code and uses a dialect of Ruby, it's especially attractive to developers who are already familiar with Ruby.

In a similar way, I'd like to point out React Native which lets you write iOS (and Android) apps in Javascript. I'm not a big fan of Javascript, but React Native (and similarly React for web) opens up a different paradigm for mobile app development which is well worth looking into. Even if you are never going to be using React Native for iOS app development, it's well worth spending an hour running through the official tutorial. You should at least go through these:

  • Install React Native (it's just a shell command away)
  • Create a React Native project (another command)
  • Run the empty app in the simulator
  • Hit Cmd+D to bring up the menu, enable Live Reload
  • Make a few simple changes in index.ios.js
  • Examine how a "screen"/component is defined/created in index.ios.js
  • Continue with the tutorial to learn about stuff such as Props, State and Style

This should give you a good introduction to what React Native offers.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


There are many configuration options in Xcode's Build Settings. Some are seldom-used, while some are new. You can check what they do by revealing the Quick Help Inspector (cmd+opt+2 as of writing).

Some of us are on small screens. You can opt-double click on a setting to display a popup showing the same information.

Similarly, opt-click on a symbol (class, function/method) in the code editor to view its documentation.

Pressing the opt key while clicking or double-clicking on macOS often brings up something additional in various apps.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Collection has a property called lazy which is very useful for performance reasons. From the docs, lazy:

A view onto this collection that provides lazy implementations of normally eager operations, such as map and filter.

Array implements Collection, so if you have a large array, you can do this:

var veryLargeArray = [1, 20, 30, 4, 55]
var c = veryLargeArray.lazy.map { $0 * $0 }
c[1] //Random access without processing the entire array

It's a tiny, localized change to your code that, under the right circumstances, can have incredible performance improvements. Since lazy is a property of the Collection protocol, you can use it with all collection types that implement it, including Dictionary and Set.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


As developers using macOS, we often need to use the Terminal app or an equivalent. Sometimes you want to edit a command that you ran earlier. Most shells let you recall history by pressing the up arrow key. But what happens if you need to edit a long command? Again, depending on your shell, you might be able to use your left/right arrow keys or possibly alt-left/alt-right (for fish shell).

Did you know that you can opt-click in Terminal to move your cursor? It's a major time-saver.

PS: I'm not sure if (arguably non-iOS) tips such as this are of interest to you. If you can hit reply and let me know in a few words if you want more or less of these, it'll be much appreciated!


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes you legitimately want to identify user iOS devices uniquely. You can use UIDevice's identifierForVendor for that. From the docs:

The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.

However, the identifier value may change if all the apps under same developer account are deleted and reinstalled. One workaround is to store it in the Keychain. You want to be careful and set the item to be not synchronizable so you don't end up with the same identifier being assigned to every device owned by the same user.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you have upgraded to macOS 10.12.2 and use SSH (e.g. with git), you'll probably notice that macOS no longer seem to store your keys and their passphrases with ssh-agent. Here's a solution from @mjtsai:

Add this to your .ssh/config file to:

Host *
  UseKeychain yes
  AddKeysToAgent yes


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Over the years, I've found that downloading Xcode from the Mac App Store has several disadvantages. You no longer have control over which version of Xcode you are running. And a new version of Xcode gets downloaded halfway and you are unable to continue working.

Most developers also download the latest beta version of Xcode from Apple's website for testing their apps against newer versions of iOS or to take advantage of APIs in soon-to-be released versions of iOS.

There's a Downloads for Apple Developers website where you can download other versions of Xcode, including the latest production version. Downloading Xcode from here instead of the Mac App Store lets you run different versions of Xcode in parallel easily.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In #13 and #67, I mentioned using Link Conditioner on macOS and iOS respectively to simulate a slower network for testing your app. Here's an extension of that:

Test your app with Airplane Mode enabled!

Depending on your priorities, this can mean getting the app to work almost perfectly in offline mode — i.e. caching enough data so that you can fulfill most of user needs (e.g. maps apps or document viewer apps) and persisting user operations that require connectivity (such as posting a tweet) so they can be "played back" when there's connectivity — to something similar like displaying an alert to the user notifying that the app needs connectivity to work.

At the very least, you should check that the app doesn't break without connectivity, e.g. overriding your app's local cache with empty or "nil" data because of failed network requests.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Using a view controller (or rather its view) to display content is a very standard operation in iOS apps. Here's a common way to do it:

let detailVC = DetailViewController()
vc.navigationController?.pushViewController(detailVC, animated: true)

DetailViewController performs one or more network operations, fetching data from a remote server and then displays the results to the user.

What we sometimes get wrong is writing a function like displayActivityIndicatorView() to display an instance of UIActivityIndicatorView in the middle of the screen blocking all interaction, including tapping the back/close/cancel button to cancel the operation until the data is available:

class DetailViewController: UIViewController {
    override func viewDidLoad() {
        displayActivityIndicatorView()
        loadDataOverNetworkSyncAndDisplay()
        hideActivityIndicatorView()
    }

    func loadDataOverNetworkSyncAndDisplay() {
        self.fetchDataByCallingAPI()
        self.displayFetchedData()
    }
}

This is bad UI and makes the user feel like they do not have control since they can't interact with the app while waiting for the data to load.

I prefer to display an empty screen (or preferably displaying cached data), and when the data is fetched, update the screen:

class DetailViewController: UIViewController {
    override func viewDidLoad() {
        displayWhateverDataIsAvailable()
        loadDataOverNetworkAsyncAndDisplay()
    }

    func loadDataOverNetworkAsyncAndDisplay() {
        DispatchQueue.global().async {
            self.fetchDataByCallingAPI()
            DispatchQueue.main.async {
                self.displayFetchedData()
            }
        }
    }
}

This lets the user cancel the operation if they like and if there's cached data displayed, interact with it.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


CloudKit is a remote datastore provided by Apple. One of the most common usage patterns for it is to persist data across app installs and devices.

Unlike iCloud Core Data (which is now defunct), you need to provide your own local storage mechanism. You can use Core Data, SQLite, plists, among many other options. This also works particularly well if you use your local datastore as a cache for CloudKit. Unlikely solutions like the soon-to-be-defunct Parse, CloudKit doesn't support server side code. So an easy way to think about CloudKit is to think of it as a remote database that you can read-write directly from your apps.

I'll list a few important concepts in CloudKit and mention the closest RDBMS concept. Note that since CloudKit isn't a RDBMS, the terms usually don't mean exactly the same thing:

  • Database - there is a public database and a private database. Every user can access the public database and each user can only access their own data in the private database.
  • Zones - zones group records together. Updates to records in a zone can be an atomic transaction. There is a default zone in both the public database and private database. You can only create custom zones in the private database. This is similar to a database in an RDBMS.
  • Record type - a collection of records. This is similar to a table. A record type consists of fields which can be one of several built-in types such as String, Date/Time, Int(64) or a list of these types, such as a List of Strings.
  • Record - a row of data. This is equivalent to a row in a table.
  • Dashboard - CloudKit provides a web-based dashboard

Code to use CloudKit is too long for a nugget, so I'll point you to Apple's CloudKit quick start guide.

CloudKit is practically free for most usage patterns, so check it out.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.


One of the simplest ways to improve security for your app data is to make use of the file data protection APIs

The iOS Security doc is an important document which also talks about other aspects of iOS security. File data protection is simple to understand though.

There are a few options:

  • NSFileProtectionComplete — file is only accessible when device is unlocked
  • NSFileProtectionCompleteUnlessOpen — file is accessible while the device is unlocked and will remain unlocked while it's open. THis is useful if you want to read/write to it while running in a background task
  • NSFileProtectionCompleteUntilFirstUserAuthentication — file is accessible once the device is unlocked and until it is rebooted
  • NSFileProtectionNone - file is not encrypted

To set them on a per-file basis:

FileManager.default.setAttributes([FileAttributeKey.protectionKey: NSData.WritingOptions.completeFileProtection], ofItemAtPath: filePath)

If you want to set a default protection class for every file your app creates, you can specify the com.apple.developer.default-data-protection entitlement in Xcode.

File protection is easy to implement, and hardware-optimized. You should use it.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you want to print a struct, especially a collection, use dump() instead of print(). The latter prints one long line like this (wrapped here):

[Item(title: "Item 1", age: 10, address: Address(value: "address 1")), Item(title: "Item 2", age: 10, address: Address(value: "address 1"))]

whereas dump() does this:

▿ 2 elements
  ▿ Item
    - title: "Item 1"
    - age: 10
    ▿ address: Address
      - value: "address 1"
  ▿ Item
    - title: "Item 2"
    - age: 10
    ▿ address: Address
      - value: "address 1"


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Here's a simple tip that might drastically improve your app performance: don't block your app launch.

i.e. when you implement application(_:didFinishLaunchingWithOptions:) or related methods in UIApplicationDelegate such as application(_:willFinishLaunchingWithOptions:), don't perform operations in them that run synchronously in the main thread. Naturally, running long operations in your app delegate on the main thread blocks your app from launching/resuming. It can be overlooked though. For example, when you implement and perform data migration when your app launches. Initially this might be an immediate operation. But as you go along and the app's data model become more complex and the user accumulates more data, a simple data migration might take too long and causes the app launch to be noticeably slower. This is not only poor user experience — a slow app launch can cause iOS to kill your app.

The same principle applies to methods such as applicationDidBecomeActive(_:).


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes you want to grab all the directory and files you wrote into your app's document directory for testing/debugging. When running on the simulator, you can print the document directory and access it directly. How's how you can do it on an actual device:

  1. Plug in your iOS device via USB
  2. In Xcode, choose Window > Devices
  3. Click on your iOS device under DEVICES
  4. Under Installed Apps, click on your app
  5. Click the gear button
  6. Click Download Container

This will download the entire sandbox container, including temp files.

Happy debugging!


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Rather than a specific piece of code, I want to talk about a kind of "pattern" that I like to use.

With good connectivity for most iOS devices nowadays, I noticed there's a paradigm that works quite well for many types of apps.

Where applicable, use your app's local datastore as a temporary cache — be it Core Data, SQLite, plist or any other databases. This is only possible if you have a server side database/API which you can sync to.

I took a quick look at the top apps in the app store and can easily name a few types of apps that can work with this model, e.g. chat apps, Twitter apps, Facebook apps, news apps, podcasts apps. There are more and they tend to display content that is refreshed very often.

This gives you the advantage of having a single source of truth (the server) and if any goes wrong, you can just blow away your local datastore and rebuild it from the server.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Here's something I read in a tweet by @steveluscher a while back.

map([🌽, 🐮, 🐔], cook)
=> [🍿, 🍔, 🍳]

filter([🍿, 🍔, 🍳], isVegetarian)
=>  [🍿, 🍳]

reduce([🍿, 🍳], eat)
=> 💩

Wonderful illustration of how these higher order functions for functional programming work.

PS: I mentioned in last week's issue about iOS Conf SG. The video of my talk is now available here. There are gems in the conference such as Leveraging Swift's Type System by @benjaminencz. There are many others. Check out all the talks here.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


UIAlertController was introduced in iOS 8 providing a block-based API among other changes. But it is still not very customizable. If you want to show e.g a large image or otherwise more customizable content, PMAlertController is one good solution. It has a similar API to UIAlertController and is available via CocoaPods and Carthage.

Here's sample code from the README (Swift 3):

let alertVC = PMAlertController(title: "A Title", description: "My Description", image: UIImage(named: "img.png"), style: .alert)

alertVC.addAction(PMAlertAction(title: "Cancel", style: .cancel, action: { () -> Void in
            print("Capture action Cancel")
        }))

alertVC.addAction(PMAlertAction(title: "OK", style: .default, action: { () in
            print("Capture action OK")
        }))

self.present(alertVC, animated: true, completion: nil)

PS: For the last 2 days, I was at iOS Conf SG along with a great lineup of speakers including @natashatherobot, @merowing_, @_ryannystrom and @inamiy. If you are interested in my talk, here's a link to the deck. The videos for the all the talks should be up soon. I'll post links soon.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift 2.0 introduced the defer statement that let us run code just before a function returns.

This is especially useful if you need to clean up resources at multiple points within the same function. E.g.

func writeOutput() {
    var stream: NSOutputStream //initialize it. Possibly a subclass
    if (someCondition) {
        doSomething()
        stream.close()
        return
    } else {
        doSomethingElse()
    }
    stream.close()
}

The example above is contrived, and the code can be improved with some refactoring. But in the function, you can see that clean up code (stream.close()) has to be run at two places. This breaks the DRY principle, and is easy to miss when you modify the code. With the defer statement you can rewrite it:

func writeOutput() {
    var stream: NSOutputStream //initialize it. Possibly a subclass
    defer {
        stream.close()
    }
    if (someCondition) {
        doSomething()
        return
    } else {
        doSomethingElse()
    }
}

The code in the defer block runs right before the function returns. So clean up code only appears once and is close to the initialization code, making it easier to reason. You can write multiple defer blocks in a function and they will be called in reverse order if you initialize multiple resources.

So use defer. Cleaner, fewer errors.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


UIViewController adds the methods showViewController(_:sender:) and showDetailViewController(_:sender:) in iOS 8.

They do the right thing with UINavigationController and UISplitViewController, e.g for UINavigationController, showViewController(_:sender:) will push the view controller and showDetailViewController(_:sender:) will do a present it.

In your own custom view controllers, you can also override these methods to display the view controllers appropriately.

The beauty of these pair of methods is that they walk up the view controller hierarchy looking for view controllers that implement them and do the right thing.

Using showViewController(_:sender:) and showDetailViewController(_:sender:) helps decouple the shown/presented view controller from knowledge of the view controller hierarchy.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.


In #61, I talked about the null coalescing operator for Obj-C. This is also available in Swift as the nil-coalescing operator ??.

Here's an example where it's useful. You have an optional object that you want to use if it contains a value, otherwise fallback to a default.

let possiblyNilObject: NSObject? = nil
let defaultObject = NSObject()

You could use if-let-else:

let v3: NSObject
if let v1 = possiblyNilObject {
    v3 = v1
} else {
    v3 = defaultObject
}

Or the ternary conditional operator:

let v4 = possiblyNilObject != nil ? possiblyNilObject! : defaultObject

Or alternatively, the nil-coalescing operator:

let v5 = possiblyNilObject ?? defaultObject


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


In NSDate (now Date), there's a handy property doesRelativeDateFormatting that, when enabled, returns string values such as "today" and "tomorrow" from string(from:) when appropriate in that locale:

let dateFormatter1 = DateFormatter()
dateFormatter1.dateStyle = .full
dateFormatter1.doesRelativeDateFormatting = true
print(dateFormatter1.string(from: d)) //Today

let dateFormatter2 = DateFormatter()
dateFormatter2.dateStyle = .full
print(dateFormatter2.string(from: d)) //Thurs, September 22, 2016

let dateFormatter3 = DateFormatter()
dateFormatter3.dateStyle = .full
dateFormatter3.locale = Locale(identifier: "zh_Hans_SG")
dateFormatter3.doesRelativeDateFormatting = true
print(dateFormatter3.string(from: d)) //Chinese equivalent of "Today"


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you use functions like abort() in Swift, and write code after the function call, you'll notice the compiler issues the warning "Will never be executed":

func foo() {
    abort()
    print("Should not reach here") //Warning for this line
}

And when you call abort() (which doesn't return a value) as the last statement in a function that expects a value to be returned, the compiler doesn't generate a warning.

func bar() -> Int {
    if true {
        abort()
    } else {
        return 1
    }
}

This works because abort() is defined with the return type Never:

public func abort() -> Never

Similarly for exit():

public func exit(_: Int32) -> Never

The documentation says this about Never:

Use Never as the return type when declaring a closure, function, or method that unconditionally throws an error, traps, or otherwise does not terminate.

So if you want to write your own function that logs a catastrophic error and then call fatalError(), you should use the return type Never to signal to the compiler:

func catastrophicError(error: String) -> Never {
    postErrorToSomeCustomLogFacility(error)
}


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift provides the @autoclosure declaration attribute. When applied to a function parameter type, it converts the call site expression into a no-arg closure with a return value, delaying the evaluation of the expression. For example, in the following code, both normalFunction() and withAutoClosure() are called with the output of foo(), but because withAutoClosure()'s argument is declared as @autoclosure, it doesn't evaluate foo(). Instead the foo() call is wrapped into a closure which is then passed to withAutoClosure().

func foo() -> Int {
    print("foo called")
    return 1
}

func normalFunction(_ i: Int) {
    print("normalFunction:")
    print("    Value returned by foo: \(i)\n")
}

func withAutoClosure(_ fn: @autoclosure ()->Int) {
    print("withAutoClosure:")
//  print("value returned: \(fn())")
    print("    Notice foo is not called?")
}

normalFunction(foo())
withAutoClosure(foo())

This will produce the output:

foo called
normalFunction:
    Value returned by foo: 1

withAutoClosure:
    Notice foo is not called?

Using @autoclosure, you can decide to skip the evaluating the expression or evaluate it one or more times. The Swift blog gives an example of implementing assert() using @autoclosure, as well as short-circuiting logical operators.

Note that @autoclosure has to be used judiciously because the someone reading the code cannot easily determine that the argument has @autoclosure applied to it.

PS: This code is written in Swift 3. Minor modifications would make it work with Swift 2.2

PPS: If you have any interesting (and short) tip you would to share or a feature you would like me to talk about, reply to this email


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift provides a Measurement type that represents a value and its unit. e.g. 2cm.

var v1 = Measurement(value: 1, unit: UnitLength.inches) //1"
v1.convert(to: UnitLength.centimeters) //v1 is now in cm
var v2 = Measurement(value: 2, unit: UnitLength.inches) //2"
v1+v2 //addition

Measurements helps introduce type safety into calculations and reduces conversion errors.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift Enumerations with associated values are useful for representing a constrained set of cases with associated values. For e.g. in #193, I talked about using Result Enumerations to simplify error handling. In that example, there are 2 possible cases/states — Success and Failure.

In a similar manner, you can use enum cases to encode values such that you can simplify code and reduce duplication by eliminating nil handling. A good example is when you are building a tree or a linked list. There is often a Node type that looks like this for singly linked lists:

class Node<T> {
    var next: Node<T>?
    var value: T?
}

Or for binary trees:

class Node<T> {
    var left: Node<T>?
    var right: Node<T>?
    var value: T?
}

While you can rely on optionals, it gets unwieldly as you need to do nil checks for each var that is an optional Node.

Using enums, you can instead do:

indirect enum Node<T> {
    case Node(value: T)
    case Empty
}

A good example of this approach for working with Binary trees can be found at The power of Swift enums. Look under the title Binary trees.

Enums are shaping up to be a very useful construct in Swift.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


I was going to write a tip about pattern matching using enums, but realized that someone else has already done a great job, including other forms of pattern matching in Swift, and not only against enums. So I'll point you to this post by Benedikt Terhechte :)

Enumerations are powerful in Swift, I expect to be writing more about using them over here.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift arrays have a flatMap function that is very handy. Suppose you have an array of Int and want to perform an operation for each element and return the results as a new array. This is the classic use of map:

let source1 = [1, 2, 3]
let l1 = source1.map {$0*2}
l1 //[2, 4, 6] of type [Int]

If the source array is of type [Int?], it becomes trickier:

let source2: [Int?] = [1, 2, nil, 3]
let l2 = source2.map {$0} //Can't easily do $0*2, we'll just use $0 for illustration
l2 //[{some 1}, {some 2}, nil, {some 3}] of type [Int?]

Notice that the result (l2) is now an [Int?]. Sometimes you want a [Int], discarding any nil values. This is where flatMap comes in:

let l1 = [1, 2, nil, 3].flatMap {$0}
l1 //[1, 2, 3]

The result is an [Int].

flatMap performs the operation and discards the value if it's nil. This is useful in this case:

let someSourceIdentifiers = ...
let objectsFound = someSourceIdentifiers.flatMap {lookupObject($0)}

There's another use of flatMap, which is to flatten arrays.

let l2 = [[1, 2], [3, 4, 5]].flatMap {$0}
l2 //[1, 2, 3, 4, 5]

In other words, it unpacks 1 level of array.

Notice how it doesn't unpack here:

let l3 = [1, [2, 3, 4], 5].flatMap {$0}
l3 //[1, [2, 3, 4], 5]


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift Talk is a weekly video series about Swift where the hosts talk through a problem and write the code for the solution. The discussion and live coding format is great because in their own words, the series is:

packed with live-coding and discussions about the pros and cons of our decisions.

It alternates bi-weekly between free and subscriber-only content.

Check it out, it's great.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Swift Playgrounds are wonderful for teaching, exploring API and prototyping ideas and algorithms. If you like Swift Playgrounds but work with Obj-C, you are going to love KZPlayground by @merowing_. Available as a CocoaPod, you can bundle it into your project (during development). In many ways, it works even better than Swift playgrounds.

Check out the demo video.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Sometimes you want to set global state before any of your other code runs. With Obj-C, you can override the +load method for a class to do that. The +load method runs once-only, automatically when the class is loaded at launch.

If you try to override the class load() function in Swift, you will get the error "Method 'load()' defines Objective-C class method 'load', which is not permitted by Swift". So you have to fall back to overriding the class function initialize() instead. There is a key difference between load() and initialize(). The former basically runs when the app starts up (when the class is loaded), but the latter only when the class is first used, so you might want to implement initialize() for your class which implements UIApplicationDelegate.

Either way, you should be careful not to put long running code in load() or initialize() because that will block the main thread and the launch of your app.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


If you work with Swift, you'll notice that Xcode doesn't let you refactor Swift code yet. This brings us to another wonderful tool by John Holdsworth called Refactorator.

Refactorator lets you perform rename refactorings on your Swift code. You can install it via Alcatraz.


Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

Like this post? Follow me @hboon on Twitter.

.


Every developer has their favorite set of tools. I have written about a few of them so I'll link to those tips. Here's what I use mainly for iOS app development (in alphabetical order):

AppCode

AppCode is worth using just for the refactoring tools, quick-fix functionality and inspections.

Charles

A proxy server that lets you examine HTTP(S) requests made by (other) apps.

Dash

A third-party documentation viewer. Viewing documentation in Xcode used to be very slow. Dash was much faster, but the speed difference is not so significant anymore.

ImageOptim

A very handy tool for reducing the size of your PNG files.

Kaleidoscope

A pretty diff tool

MacVim

I write most of my code in MacVim. Still one of the faster way to enter and edit text.

Paw

A tool that lets you make HTTP(S) API requests and display the results in a nice format. Supports extension which generate code you can copy and paste to make the same requests in your project.

Regex

I built this app so I can work out regular expressions as well as test them.