Should I use ObservableObject in Managers - swift

Im learning about SwiftUI for macOS development, and Im wondering what would be the right approach when creating Managers, services etc. These are objects not related to the UI - strictly business logic things, not even ViewModels. Should I not use things like ObservableObject, Published, AppStorage, etc. in this kind of classes? On one hand it seems to be beneficial to add this, so that I can later easily use them with ViewModels, and bind directly to some properties. On the other hand it seems wrong - like these property wrappers are strictly SwiftUI related. So should I resign from these things in managers, services and other business logic objects?

Both ObservableObject and Published are defined in Combine, so they are fine to use outside of the UI layer of your app. On the contrary, #AppStorage is defined in SwiftUI, so you should only use it in Views.
However, the fact that something is defined in Combine doesn't necessarily mean that it provides meaningful value to use when not binding to your UI.
ObservableObject's main use case is storing objects as #ObservedObject on a View and getting automatic view updates. Even though you could consume the objectWillChange Publisher that ObservableObject provides from outside a view, there's not much use for it, so in general, I wouldn't advice on making objects conform to ObservableObject unless they are directly updating your SwiftUI views.
#Published on the other hand provides significant value even outside your ViewModel-View interaction. Observing changes to mutable state is quite useful even in a pure business logic layer, such as exposing the current location of the user in a location manager class and observing it from a view model. Marking this property #Published makes it much easier to observe.
The separation of what objects a View should directly access is a subjective topic, so I won't go into that in much detail, but if you want to keep your View independent of your business logic objects other than the ViewModel, you should store managers, services, etc on your ViewModel and proxy any properties that need to update the UI through the ViewModel. For this to work, you don't need to make your managers/services conform to ObservableObject, however, storing mutable state as #Published can be quite helpful.

ObservableObject allows you to store state in an object that is independent from any views. When you conform your class to ObservableObject then views can observe it (or listen). To broadcast (publish) values of your variables to the views, just mark them with property wrapper #Published. Obviously, you know that.
I consider this pattern as strictly dedicated to Object->Views communication.

Related

What is the right architecture to design classes for SwiftUI app

I am bit new to app development in SwiftUI. In last 2-3 months I have developed few small iOS app just to learn concepts. Otherwise I am experienced developer in C#, Java etc.
One thing I am little unsure about SwiftUI is the right set of architecture around developing classes for the project. I mean like there could be couple of ways
We write model classes that represent the data that our application need to hold. In purist form the model classes should only be concerned about just data, I mean the model classes should only hold the attributes that reflect the data.
Say I am writing a Inventory management app so if one of the model is Merchandise item then its attribute could be Id, name, price, barcode etc. In my opinion the model classes should not concerned about View's concern like #Published, #ObservableObject, #State, #EnvironmentObject etc etc. Model should just stick to representing domain only. Correct?
Ideally the model classes should be written as Class not Struct (if I carry over my understanding of OOPS from C++ to Java/C# where we write classes not struct)
The second set of classes we need are views i.e. inherited from View. Undoubtedly these has to be Struct as SwiftUI framework works this way.
Now in between the model classes (presuming they are classes or at max we made them Struct for the sake of SwiftUI framework) and View classes, lots of communication, state change, eventing has to happen to make app worthy of doing something. I mean handling user gestures, creating & editing data which should update screens when user navigate back and forth between UIs.
I found it little hard to connect Model (if they are developed in purist form) and View. Hard in the sense that as I started writing Views and look to implement use cases which involve data editing, reflecting changes in views etc I found pure model classes insufficient. They have to be modified to reflect SwiftUI features like binding, observability, published to sync data between view and model and also between two models.
Wondering what is the right design pattern to connect and communicate between model and view? Is MVVM the right design pattern to be used in SwiftUI based project? If not then what else is right pattern?
If MVVM is right pattern then are there any quality guide or resources or sample SwiftUI projects (gitHub??) I can look at and learn?
I think your hypothesis is wrong.
Ideally the model classes should be written as Class not Struct
Make a distinction between model with and without state.
Model without state should be value type.
Model with state should be reference type.
The second set of classes we need are views i.e. inherited from View. Undoubtedly these has to be Struct as SwiftUI framework works this way.
Value type cannot be inherited. I also think they are models rather than views.
E.g.; struct Model: View {}
They are models, that can be used to build views, hence the View conformance.
The fact that it is of value type also supports that it's not view. (cannot be inherited)
Whether your model has state or not, as long as it conforms to View, it can be used to render a view. This is the design of SwiftUI, taking a page from React, IMO. (I personally don't see React ever bothering with MVVM)
Now since you think Model should be strictly without state, you have a problem.
You need a reference type object that handles all the state and bridge it to the view.
You can follow MVVM. In that case you lose most of the SDK support that builds around struct Model: View, e.g.; #State, #StateObject, #EnvironmentObject, and associated automatic binding and safety checks. You would also add at least one reference type for each of the views, and put most of the control / business logic in it. (where else can you put it?)
So it's in effect a view controller. And you would be doing most of the Control work on a reference type object, without safe guards of immutability. That is on top of all the overheads you would introduce; and since you would pass view model around to be "reusable", you are going to have all the usual bugs caused by shared reference with implicit states.
Take my above assessment with a grain of salt, of course.
Or you can do what official guide do: struct Model: View {} with possible states in it.
The key here, as SDK requires you to put extra annotation, is that state objects are explicitly identified. E.g.; #StateObject, #ObservableObject. And you have to create reference type objects separate from your model. It essentially cuts out the middle man that is view model.
I think this is the most difficult thing for MVVM devs to get used to. You no longer need a view model to do what a view model does.
But shouldn't it be obvious? View model depends on how binding is designed. If SwiftUI has a binding design so efficient, (it does so declaratively without extra object) view model could be automatic.
SwiftUI removes UIViewController, does that mean you can't have Control?
I don't see MVC developers come out and create a Controller for every view.
Same reasoning, you can have MVVM without VM. Design pattern is a #State of mind.
To summarize:
I think the best architecture is official SDK. Learn to walk before you run.
MVVM in legacy sense is an option too. But I think you need to consider the possibility that
traditional wisdom is not up-to-date with latest SDK.

In an observer pattern, is it better to pass data around in the notification, or have the observers reach out to a singleton?

Background
I'm working on an iOS game in Swift which has realtime theme updates. This basically means that SKSpriteObjects change their color when a the theme changes. As I'm implementing it, I'd like to do it in a way that is good OOP practice, and good for scalability (lots of objects doing this at once). I've got two ideas for achieving this:
Method One: Notifier/Observer + Singleton
-Register all updatable SKSpriteObjects as observers for the key "updateTheme"
-Create a singleton called GameState with the current theme colors
-When the "updateTheme" notification is fired, each of the observers will reach out the the singleton for their new colors.
Method Two: Notifier/Observer + passed object
-Register all updatable SKSpriteObjects as observers for the key "updateTheme"
-The object that fires the notification "updateTheme" will create and attach an object to the notification that contains the current theme attributes.
-When the "updateTheme" notification is observed each of the observers will unwrap the object, and then access the updated colors from that unwrapped object.
Question
Although I think that passing an object around in a notification is a better OOP practice, I'm imagining that all the unwrapping going on won't be the best idea for speed. So with that, I'm more inclined to go for the singleton approach. What are your thoughts? Perhaps there's a better way that I didn't think of to massively update all the objects in my game.
Never to a singleton.
Or, to put it in different words:
Whenever you have two options, and one of them involves a singleton, pick the other option.
My recommendation would be to first write your game properly, then see if it suffers performance wise, and if and only if it does, then worry about performance. And what usually tends to happen is that you will find a few places where you can provide nice and neat algorithmic optimizations that will make your game perform better, instead of tweaking and hacking all over the source code to save clock cycles here and there.
That having been said, consider one more alternative: it is a common pattern with event observers to pass to them as their first parameter a reference to the object issuing the notification. So, why not have the observable pass a reference to itself to the observers, so that the observers can then obtain whatever they need from the observable?

Friend classes in Swift (access private members of internal class)

I have two Swift classes in two different files, both in the same target. Is there a way to give one access to the private members of the other without exposing them as internal or public?
(I'm essentially looking for something analogous to friend in C++.)
Motivation:
This could be useful for something like implementing UIViewControllerAnimatedTransitioning in a separate "transition" class—typically requiring intimate knowledge of the source and destination view controllers—without requiring those view controllers to expose private subviews to the rest of the target.
I have two Swift classes in two different files, both in the same target. Is there a way to give one access to the private members of the other without exposing them as internal or public?
No. The rules you get are the rules you get. There is not some magic way to break them. You can put the two types in the same file, or (at the other extreme) you can move them both off into a module of their own and give them internal scope so that they can see each other but no one else can see them.
This could be useful for something like implementing UIViewControllerAnimatedTransitioning in a separate "transition" class—typically requiring intimate knowledge of the source and destination view controllers—without requiring those view controllers to expose private subviews to the rest of the target
I don't see why you need this. It is easy to move UIViewControllerAnimatedTransitioning material into a file of its own already. There is no need for exposure of private subviews. That is why this stuff has been broken off into a separate protocol. The roles of animator and view controller are already completely independent. If you think exposure of private subviews is required, you're doing something wrong (and you should be asking a question about that). [For example, it may be that you are unaware of the transitionCoordinator function, which allows a view controller to participate in its transition animation without knowing what it is.]

Must NSManagedObject subclasses by passed to the controller or should these objects remain only in the model

The reason I ask is because I have separate domain objects which I map from the NSManagedObject subclasses so as to keep my data access logic separate.
But I think its going to be a problem for updating.
I wouldn't say that NSManagedObject subclasses must be passed to a controller object: In theory you could do what you're describing, and build a "front end" layer that sits between your Core Data model and your controllers – you're creating a lot more work, of course, and it might be just as easy to throw out your old model and start over, if and when you ever do decide to stop using Core Data.
You may also have to put more effort into keeping your model objects separate from your controller objects, what with a middle layer that could easily become a hodgepodge of both. It sounds like you've already gone down this road, though, so the question is probably more about the best use of your time and resources, and whether it's more cost-effective to phase out the middle layer or maintain it.
If you mean should you pass MySubclass vs NSManagedObject; it does not matter. The instance is what it is, your subclass. You can call it anything in between id and MySubclass.
So you can set up your controller to accept just an id or NSManagedObject you can pass it your subclass without an issue. If you want more exposed control to the subclass then you can pass around the subclass.
If that does not answer your question then I suggest you expound upon your question with an example.

Wheres the best place Iphone app to place a Data Model instance and how would you Access it?

I am learning tons on this thing. Reading also, but this is awesome!
Ok.. so long story sort I hope. I'm making a data class to pump out some instances of people that have various attributes. I would like my view controllers to be able to access them (through properties of course.. I think) to manipulate their data.
Where in an iphone app would be the best place to do this, and how would you write the code to message to this object. My current setup would be to have a navigation controller with a firstlevelviewcontroller that created a few secondlevelviewcontroller children instances that would do things like pickers for date of birth, and height, weight, etc.
Could the Navigation Controller make these model objects? Should application delegate? Lets say application delegate does. If so, then how would I put references to these objects from my first and second level view controllers?
Awesome!
**Update for the new millenium. **
I'm reading on core data structures, and though they are awesome, they are above and beyond what I need for this project. what I need is simple, I think..
I want one class that is a data class with a few variables that I can manipulate. I want to manipulate these from two view controllers. I might want more than one data instance, so I don't want a singleton data object. I don't need a persistent store of data.
I would like to know how to step by step have this data class instantiated.. should it be in app delegate? can i do it somewhere else? I dont want it a child of one of the view controllers.. How would I do that? then, how would I reference it from the view controllers and manipulate data (I'm pretty sure through properties but I can't figure out how to reference the instances to make this happen).
CHeers! thanks for the help!
Lots of questions that fringe on conjunction of various best practices.
First, the NSManagedObjectContext (if instantiated in the application delegate) can be shared in any number of ways. You can push it on through as you load your controllers or, something I've been more want to do (and will gladly argue the merits), you can hand it off to a Singleton that any controller has access to.
Depending on the model graph and how your UI maps to the data objects (you didn't say), keep in mind being memory friendly. I defer creating the NSFetchRequests until there is a controller that needs the data (CRUD).
If you want to edit your question or add comments that may provide more clarity... the answer may change
Frank