Better handling for conditional rendering

Image for post
Image for post
Photo by Daniel Mingook Kim on Unsplash.

We already saw in a previous article how common optional views are. We also saw that the logic handling the optionality can have different owners. Finally, we saw how to implement reusable optional views with Swift + UIKit.

This time, we are going to skip the introduction and go straight into how to do the same thing with SwiftUI using an example.

Go Premium Widget

Let’s say we have a freemium app where users do not need to pay to use the app, but we want to make them well aware of our premium plan that includes additional features.

We are going to show a “Go Premium” widget on different parts of the app where they can tap to launch the process. But Go Premium widgets should not be shown when users are already premium for obvious reasons. …


How to reuse optional views effectively

Image for post
Image for post
Photo by Simon Berger on Unsplash

Optional views are present in many apps of all kinds. There are 1000 reasons for needing to show or hide a view based on a condition such as app state, user profile, feature/product availability, A/B testing, etc.

There are also many ways of tackling this issue, but we could split them into three groups, based on which component is responsible for this logic.

  • Container/optional view’s parent: It comes up as the first option because it seems the easiest and simplest way. And it might be, indeed, in simple cases. …

Developing A Newspaper App

Image for post
Image for post
Photo by Yura Fresh on Unsplash

Introduction

In a previous article we saw the definition of the YAGNI principle. In this article we are going to see an example to illustrate how costly might be not following this principle.

A Newspaper App

Let’s say John is building a smartphone front-end for an online newspaper. In a first version, releasing in a couple of weeks, the app needs to show a list of headlines and users should be able to read the news content by tapping on them. The classic Master-Detail App. Easy peasy.

Image for post
Image for post
Master-Detail News App Prototype

Foreseeing future needs

App has been thought to be online, but as John is building the first screen, he starts thinking that maybe he should persist the news that are being retrieved from the server in a database. He thinks that, even though it is not strictly needed now, it might be useful in the future. …


Do not add functionality until it is completely necessary

Image for post
Image for post
Photo by Vitaly Taranov on Unsplash.

Introduction

YAGNI, You Ain’t Gonna Need It, or You Aren’t Going to Need It is a principle from Extreme Programming (and somehow related with Lean Thinking) that states that a programmer should not add functionality until it is completely necessary:

“Always implement things when you actually need them, never when you just foresee that you need them.”

Even if you are totally sure that you will need a feature or piece of code later on, do not implement it now. …


Photo by Max Nelson on Unsplash
Photo by Max Nelson on Unsplash
Photo by Max Nelson on Unsplash

In a past article, I used the OOP principle favor composition over inheritance as one of the reasons for avoiding the use of protocol default implementations in Swift. I didn’t want to go into detail because it would’ve been too long.

In this article, I’m going to use a familiar example for showing how we use composition over inheritance and why, when the goal is reusing code, it is a better approach.

BaseViewController

One of the most popular uses of inheritance for reusing code I’ve ever seen in an iOS project, is to have a BaseViewController. …


Composition over inheritance, the interface-segregation principle, method dispatch, and unit testing

Image for post
Image for post
Photo by Alex Knight on Unsplash

Because the reasons for not using them outweigh the benefits you’d get from doing so. Let’s see some of them:

  • Composition over inheritance and interface-segregation principles.
  • Method dispatch for protocols.
  • Unit Testing.

Protocol Default Implementation

As mentioned in Swift’s documentation:

“You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol.”

In fact, not only can you provide a default implementation to methods or computed properties defined in the protocol, you can also add new ones.

Let’s see an example:

protocol SampleProtocol {
func foo()
}
extension SampleProtocol {
func foo() {
print("foo")
}
func bar() {
print("bar")
}…

Mapping and flatMapping optionals for cleaner code

Image for post
Image for post
Photo by Max Nelson on Unsplash

At this stage, you might know that Swift Optionals are just enums on steroids:

enum Optional<Wrapped> {
case none
case some(Wrapped)
}

In fact, you can use the long form to use them:

let longFormSomeOptional = Optional<Int>.some(1)
let longFormNoneOptional = Optional<Int>.none

You might also know how to use Optional binding (if let, guard let, and switch), Optional chaining, the nil-coalescing operator, and forcing unwrapping.

But, you might not know some other operations explained below that can make your life easier.

Mapping an Optional

There’s a map operation in the Optional enum that allows us to map its unwrapped value:

func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?


Swift.Result’s potential goes beyond just getting the value/error using a switch clause. Let’s look at a few things you can do

Image for post
Image for post
Photo by Hitesh Choudhary on Unsplash

Get the Success Value as an Optional

In some cases, you just need the success value of a Result. With func get() throws -> Success, you don’t need to use a switch clause.

let resultSuccess = Result<Int, Error>.success(1)
let value = try? resultSuccess.get()
// value is Optional(1)
let resultFailure = Result<Int, Error>.failure(someError)
let value2 = try? resultFailure.get()
// value is nil

Convert a Throwing Expression to a Result

There are other cases when you have a throwing expression (e.g. function, closure …) but need a Result instead. It’s your lucky day because Result has an init that catches thrown errors.

init(catching body: () throws -> Success)

enum RandomError: Error {
case noNumber
}
func random() throws -> UInt {
if Bool.random() {
return UInt.random(in: 1...20)
} else {
throw RandomError.noNumber …

About

Alberto Salas

iOS Engineer. UX, Agile, Lean, and Software Architecture Hooligan. www.linkedin.com/in/albsala

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store