Imitating sealed class in Swift

Kotlin's sealed classes are a powerful feature that allows developers to define a closed set of subclasses for a given class. In this blog post, we'll take a look at how to imitate this feature in Swift and the benefits it can bring to your code.

First, let's define what a sealed class is. A sealed class is a class that can have one or more subclasses, but the set of subclasses is closed and cannot be extended by external classes. This feature allows developers to define a clear and explicit hierarchy of classes, making it easier to reason about and work with their code.

To imitate a sealed class in Swift, you can use an enumeration with associated values. This allows you to define a closed set of cases, each with its own set of associated values.

Representing Model in Kotlin

Working with Kotlin Sealed classes the best example on can think of is a UiModel representing different states of a view like Loading, Error and Content etc.

sealed class UiModel {

    object Loading : UiModel()

    data class Content(
        val title: String,
        val body: String
    ) : UiModel()

    data class Error(
        val message: String
    ) : UiModel()
}

we can then use the UiModel in the view as below:

fun main() {
    val uiModel: UiModel = UiModel.Loading

    when (uiModel) {
        is UiModel.Loading -> showLoading()
        is UiModel.Content -> showContent(uiModel)
        is UiModel.Error -> showError(uiModel.message)
    }
}

private fun showLoading() {}

private fun showContent(content: UiModel.Content) {}

private fun showError(message: String) {}

Representing Model in Swift

To imitate this in Swift, you can use an enumeration with associated values like this:

enum UiModel {

     struct Content {
         let title: String
         let description: String
     }

     case loading
     case content(Content)
     case error(String)
}

By using an enumeration in this way, you can define a closed set of subclasses that cannot be extended by external classes. This allows you to define a clear and explicit hierarchy of classes, making it easier to reason about and work with your code, just like in Kotlin.

Another benefit of using this approach is that it can improve the type safety of your code. With a sealed class, the compiler can ensure that you handle all cases correctly, and you can use type inference to make sure that your code is using the correct case of the enumeration.

we can use the UiModel in the viewController as :

func main() {
    let uiModel = UiModel.loading

    switch uiModel {
    case .loading: 
         showLoading()

    case .content (let content): 
         showContent(content)

    case .error(let message):
         showError(message)
    }
}

private func showLoading() {}

private func showContent(_ content: UiModel.Content) {}

private func showError(_ message: String) {}

Conclusion

In conclusion, imitating sealed classes in Swift can help you define a clear and explicit hierarchy of classes, making it easier to reason about and work with your code. By using an enumeration with associated values, you can define a closed set of subclasses that cannot be extended by external classes, and improve the type safety of your code. If you're working on a Swift project and want to take advantage of the benefits that sealed classes can bring, consider using this approach in your code.