Skip to content

Instantly share code, notes, and snippets.

@jazzychad
Last active March 15, 2022 19:00
Show Gist options
  • Save jazzychad/8eab4510f28915804be5 to your computer and use it in GitHub Desktop.
Save jazzychad/8eab4510f28915804be5 to your computer and use it in GitHub Desktop.
Swift models as structs or classes?
{
"title": "Swift models as structs or classes?",
"timestamp": "2015-07-17T20:18:46.000Z",
"visbility": "public",
"visibility": "public"
}

I just read today's Mike Ash post "When to Use Swift Structs and Classes" which was highly relevant as I am working on a new Swift project.

One point he made hit home as it related to a decision I've been making about using structs or classes for Model objects in the app.

This paragraph was especially interesting:

"What about model types? You might have a User type representing a user on your system, or a Crime type representing an action taken by a User. These are pretty copyable, so they should probably be value types. However, you probably want updates to a User's Crime made in one place in your program to be visible to other parts of the program. This suggests that your Users should be managed by some sort of user controller which would be a reference type."

Because mac/iOS apps are UI driven and necessarily stateful, I like to keep my UI in sync with the data in my model instances.

By way of example, consider the Twitter app. You have multiple tabs within the app which can all display arbitrary feeds/tweets/users/etc.... let's say for example that you have the same tweet open in multiple tabs. If you hit the fav button on one tweet, you want the updated fav count to be reflected in every tweet-view currently living in the app.

In Objective-C I am used to accomplishing this in the following way: Each view that represents some model data has a @property of that type, and when that property is set, the view registers as an observer on NSNotificationCenter for "ModelDidUpdateNotification" on that specific object. When something on the model changes, it posts the "ModelDidUpdate" notification, and the view will update its UI state to reflect the current model's data.

So the whole flow would look like this:

Tap fav button on tweet -> view (or data controller) manipulates model data -> model posts update notification -> view(s) receive notification -> view(s) update UI

This works really well, especially if you have a data store/controller that doles out the same canonical model instance to each view that represents it.

Now consider using Swift structs for models:

You can no longer have "one canonical model instance" as values are copied around. You can no longer use NSNotificationCenter to watch for notifications from a specific model (as you can't use a struct as the target of observation, nor do you have a single canonical copy of the model anyway). You could cheat by using NSNotificationCenter to pass some sort of identifier about the model (e.g. userId) in the userInfo dictionary and box an updated model struct in a generic wrapper class to also read from the userInfo dictionary, but then the observers have to register to listen for updates from 'nil' and filter out any notifications that don't match the identifier they care about (but that seems overly expensive).

For now I have decided to make my models reference types and use the Observer pattern (have a set of observers in the model objects that conform to some Observable/Observer protocol with a method that gets called when something updates) instead of using NSNotificationCenter, and it works just as elegantly as before, but I'm curious how "your User structs should be managed by some sort of user controller which would be a reference type" idea would work to solve this problem to keep everything that cares about a particular model in sync?

I'm curious to hear what other Swift developers think about this specific topic.

@bigDeeOT
Copy link

but I'm curious how "your User structs should be managed by some sort of user controller which would be a reference type" idea would work to solve this problem to keep everything that cares about a particular model in sync?

--

Well for that example you used for twitter, if you favorite a tweet on one screen, it could be updated on another screen through the viewWillAppear function. So in viewWillAppear you just reload all the labels on screen based on the model objects. The model objects will already have the correct data since they are reference types.

Is that a bad idea? I'm not an expert!

@epeusvn
Copy link

epeusvn commented Sep 27, 2018

but I'm curious how "your User structs should be managed by some sort of user controller which would be a reference type" idea would work to solve this problem to keep everything that cares about a particular model in sync?

--

Well for that example you used for twitter, if you favorite a tweet on one screen, it could be updated on another screen through the viewWillAppear function. So in viewWillAppear you just reload all the labels on screen based on the model objects. The model objects will already have the correct data since they are reference types.

Is that a bad idea? I'm not an expert!

It's not what he was talking about, if you use struct then the model in another screen is a copy and if will not reflect the change made to the model of the screen you favorite a tweet.

This link from apple may help you decide when to use struct or class : https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment