In many Apps I have developed for iOS since I use Swift, I came across a very common problem. My model would have an optional String property and it was my job do display it to the user in a meaningful way. Well, in most cases, that job is to easy. Let’s say I have a UILabel in which I want to show some text or make the label disappear when there is no text:

myLabel.text = myModel.someString

Put your UILabel in a UIStackView and you are already done. The stackview will take care of hiding your label if it is empty. But there is one downside: if the String is not nil but the text is actually an empty String, the label will be hindden as well.

What might not sound as a big deal becomes pretty obvious a problem when you work with self sizing UITableViewCells. Doesn’t this one look pretty ugly?

example of why you might need default value for optional string or default value for empty optional string

So in my apps, I used to have some pretty ugly piece of code to check whether or not an optional String is not nil and not empty and otherwise use a default value like so:

if let text = myModel.someString, !text.isEmpty {
    myLabel.text = text
} else {
    myLabel.text = "Text is nil or empty"
}

Yeah you guessed it or shall I say smelled it? This piece of code smells really bad. Repeating the same pattern over and over again is commonly considered an anti-pattern. Since I’ve learned a lot about protocols and protocol extensions in the last few days, I was sure I could now come up with something better and more practical.

Something which would increase readability and at the same time reduce the amount of duplicated code. So here are the requirements of what we need to do:

  • Add a function to the type of optional String
  • Make the function take a default value String as argument
  • If the String it nil or empty, return the default value
  • If the String is not nil and not empty, return the String

Ladies and gentlemen, I present to you my solution for this. 👏👏👏

extension Optional where Wrapped == String {
    func orWhenNilOrEmpty(_ defaultValue: String) -> String {
        switch(self) {
        case .none:
            return defaultValue
        case .some(let value) where value.isEmpty:
            return defaultValue
        case .some(let value):
            return value
        }
    }
}

“Hey, but why constrain it to a String?”, you will ask: “Why don’t you make this a generic so it is available on all types?”. Well, because we need to call the isEmpty function on it and I am not aware of a protocol which defines the isEmpty function. Integers for example are never empty, even though you might consider 0 empty in some cases. 🤔

But wait, we are using Swift, right? We can just create our own protocols! 😅

Lets go a little bit crazy on this and define a Emptyable protocol by yourself as well as extend some of the types which we know implement a isEmpty property already – like String and Arrays. Then do some generics trickery and et voilà:

protocol Emptyable {
    var isEmpty: Bool { get }
}

extension Optional where Wrapped: Emptyable {
    func orWhenNilOrEmpty(_ defaultValue: Wrapped) -> Wrapped {
        switch(self) {
        case .none:
            return defaultValue
        case .some(let value) where value.isEmpty:
            return defaultValue
        case .some(let value):
            return value
        }
    }
}

extension String: Emptyable {}

extension Array: Emptyable {}

Woa, now I’m actually impressed by myself – because the latter, generic implementation just came to my mind when I was writing this article and was about to hit publish. Maybe I should blog more often about the little improvements I come up with, just to come up with even more clever ways of solving things. 🤓

The best part: it works on any optionals and even forces you to implement isEmpty if the type does not already have an isEmpty implementation:

struct MyStruct: Emptyable, CustomStringConvertible {
    var name: String
    var isEmpty: Bool { return name.isEmpty }
    var description: String { return name }
    init(name: String) {
        self.name = name
    }
}

var myOptional: MyStruct? = nil
myOptional.orWhenNilOrEmpty(MyStruct(name:"Hello World")) //"Hello World"

myOptional = MyStruct(name: "")
myOptional.orWhenNilOrEmpty(MyStruct(name:"Hello World")) //"Hello World"

myOptional = MyStruct(name: "Yeah")
myOptional.orWhenNilOrEmpty(MyStruct(name:"Hello World")) //"Yeah"

If you know a better way to conditionally check whether or not a type implements a isEmpty or not without making it implement a custom protocol, let me know it. I’d love to find out that Swift would be that awesome that you now only can constraint to self-types or the implementation of a protocol but to the actual presence of a property or function.😍

But we can go even one step further. Why would we even bother calling a function by ourselves and as you can guess from the name of this function, I’m not the best person when it comes to naming. 🙈

BUT, I’m one of the best when it comes to laziness, especially when typing. Also (about two hours after the first release of this post, I just remembered the beautiful ?? operator. Since I have never written a custom operator by myself but I know that this is possible in Swift, I thought: “Why not give it a try and learn something new?” (as if almost all of the above wasn’t already new to me 😝).

So here it is. The most elegant way I could come up with to provide a default value when there is no value or if it is empty:

infix operator ???: NilCoalescingPrecedence
extension Optional where Wrapped: Emptyable {
    static func ???(left: Wrapped?, right: Wrapped) -> Wrapped {
        return left.orWhenNilOrEmpty(right)
    }
}

let optionalString: String? = nil
let mandatoryString = optionalString ??? "Default Value"

So that shall it be for today. I hope you have learned at least as much as I learned today. Here is a playground to see all of the above code in action. Have fun playing with it and I’ll see you next time ✌️