<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mvvm on blog.iankulin.com</title><link>https://blog.iankulin.com/tags/mvvm/</link><description>Recent content in Mvvm on blog.iankulin.com</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Sat, 03 Dec 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.iankulin.com/tags/mvvm/index.xml" rel="self" type="application/rss+xml"/><item><title>Towards MVVM</title><link>https://blog.iankulin.com/towards-mvvm/</link><pubDate>Sat, 03 Dec 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/towards-mvvm/</guid><description>&lt;p&gt;On one of the more mediocre &lt;a href="https://firesideswift.fireside.fm/96"&gt;episodes of Fireside Swift&lt;/a&gt;, McSwiftface and Zach talk about the &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID principles&lt;/a&gt; of class design, although I don&amp;rsquo;t hold the principles as the article of religious fervour that many interviewers apparently do, they are a useful touchstone for considering class quality. OOP had been in swing (in a commercial way) for a few years by then - I was writing in Delphi and C++. The spaghetti code era was a long way behind us and the idea of separation of responsibilities was well established.&lt;/p&gt;
&lt;p&gt;I have been thinking about architecture a bit anyway - the introduction of Core Data into the &lt;a href="https://www.hackingwithswift.com/100/swiftui"&gt;#100Day&lt;/a&gt; apps I&amp;rsquo;m up to (day 63) means that there&amp;rsquo;s complicated looking code scattered around my views. In the &lt;a href="https://cs193p.sites.stanford.edu/"&gt;cs193p lectures&lt;/a&gt;, MVVM is right near the start, and I made &lt;a href="https://blog.iankulin.com/tags/mvvm/"&gt;some early forays&lt;/a&gt; into it, but so far no talk of architecture in 100Days (although I know it&amp;rsquo;s coming soon.&lt;/p&gt;
&lt;p&gt;I have certainly had the experience before of needing a layer between my apps and the database tech so they can be swapped out, and it&amp;rsquo;s basically a reflex to me to always wrap any commercial external code I&amp;rsquo;m introducing in any reasonable size program to abstract it a bit and make the (likely) task of having to replace it in the future a lot easier.&lt;/p&gt;
&lt;p&gt;Once again, YouTube serves me up a timely video.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/ehV2gp5uVhs?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;When I watch this, I can see why Paul Hudson might have left it for later in the course. There is a lot of complexity. It&amp;rsquo;s not simple code, it&amp;rsquo;s scalable code. This is good for real life apps, but it does not follow that it&amp;rsquo;s good for learning programming.&lt;/p&gt;</description></item><item><title>@ObservedObject v @StateObject</title><link>https://blog.iankulin.com/observedobject-v-stateobject/</link><pubDate>Sat, 13 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/observedobject-v-stateobject/</guid><description>&lt;p&gt;The Youtube algorithm thinks I need to watch more MVVM videos, and it turns out it&amp;rsquo;s probably right. A day or two ago in an &lt;a href="https://blog.iankulin.com/simple-mvvm/"&gt;MVVM&lt;/a&gt; post using a super simple example, I stored the view model as a property of the view using the @ObservedObject wrapper, as I created it.&lt;/p&gt;
&lt;p&gt;struct ContentView: View {
@ObservedObject var light = LightViewModel()&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var body: some View {
 VStack{
 Spacer()
 if light.isOn(){
 drawLitBulb
 }
 else{
 Image(systemName: &amp;quot;lightbulb.fill&amp;quot;).font(.system(size: 72))
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But then today, Youtube served me up this video from &lt;a href="https://www.youtube.com/c/BeyondOnesAndZeros/videos"&gt;BeyondOnesAndZeros&lt;/a&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/LntH6moCuo0?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;They start off with @ObservableObject, but then say that if the View Model is instantiated there, that this is repeated every time the View is recreated (which happens every time it&amp;rsquo;s redrawn).&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t really understand the property wrappers (like @ObservableObject) but I assume this was a type property - ie static. Apparently not. The &lt;a href="https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app"&gt;Apple documentation on managing data&lt;/a&gt; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SwiftUI might create or recreate a view at any time, so it’s important that initializing a view with a given set of inputs always results in the same view. As a result, it’s unsafe to create an observed object inside a view. Instead, SwiftUI provides the &lt;a href="https://developer.apple.com/documentation/swiftui/stateobject"&gt;&lt;code&gt;StateObject&lt;/code&gt;&lt;/a&gt; attribute for this purpose.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So that code should use @StateObject, and @ObservedObject should be used where I pass it down into other view structs in the hierarchy.&lt;/p&gt;
&lt;p&gt;Paul Hudson gives a good example in his explanation on this topic &lt;a href="https://www.avanderlee.com/swiftui/stateobject-observedobject-differences/"&gt;here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Simple MVVM</title><link>https://blog.iankulin.com/simple-mvvm/</link><pubDate>Thu, 11 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/simple-mvvm/</guid><description>&lt;p&gt;MVVM (Model-View-View Model) is an architectural pattern for apps that separates the data (Model) from the user interface (View). The communication between these two parts is facilitated by a View Model.&lt;/p&gt;
&lt;p&gt;Model &amp;lt;-&amp;gt; View Model &amp;lt;-&amp;gt; View&lt;/p&gt;
&lt;h3 id="model"&gt;Model&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;Model&lt;/em&gt; is platform independent - we should be able to pluck it out and add it to a different application running on a different platform without any trouble. Any business rules will be part of the Model along with the data. For example, if it&amp;rsquo;s a rule that every customer has a sales contact, this can be enforced in the Model.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2022-08-06-at-4.20.38-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2022-08-06-at-4.20.38-pm.png" width="85" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Model (or Models - an app could have more than one) does not know anything about the &lt;em&gt;View&lt;/em&gt; or the &lt;em&gt;View Model&lt;/em&gt;. In a SwiftUI app, we&amp;rsquo;ll almost always have the model in its own file.&lt;/p&gt;
&lt;p&gt;Our simple example app for this post is going to be a light bulb app. There will be a picture of a light bulb, and a button which will toggle the light off an on. It&amp;rsquo;s difficult to think of a simpler Model. This is what I&amp;rsquo;ve come up with.&lt;/p&gt;
&lt;p&gt;struct Light{
var on: Bool = false
}&lt;/p&gt;
&lt;p&gt;A Model in a real application could be massive - with connections to online data stores and complex business rules. Our light just has two exclusive states - off and on. We could make it more complex - it could be an incandescent light with a particular resistance and a formula for the brightness output for any particular voltage that was applied. All of that would go into the Model. But for today, we&amp;rsquo;ll just have &lt;em&gt;on&lt;/em&gt; or not.&lt;/p&gt;
&lt;p&gt;In all of the SwiftUI examples I&amp;rsquo;ve seen so far, the Model has been a struct. Perhaps it can be other things, but Swift has deep magic (structs are mysteriously immutable, so they are &lt;a href="https://www.hackingwithswift.com/books/ios-swiftui/why-state-only-works-with-structs"&gt;actually rebuilt when any properties change&lt;/a&gt;) for efficiently knowing if structs have changed, so perhaps not.&lt;/p&gt;
&lt;h3 id="view-model"&gt;View Model&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;View Model&lt;/em&gt; will have the &lt;em&gt;Model&lt;/em&gt; as a property. That way it can do things to the Model, and to access the bits it needs to pass off to the View. The View Model is always a class, as it needs to comply with the protocol of ObservableObject. If &lt;em&gt;protocol&lt;/em&gt; and &lt;em&gt;ObservableObject&lt;/em&gt; are foreign to you, don&amp;rsquo;t panic. You don&amp;rsquo;t need to understand any more than that the View needs to know when the View Model changes, so it observes the View Model, and for that magic to happen, the View Model needs to be a class having that ability (of being observed) which it gets from having the protocol ObservableObject.&lt;/p&gt;
&lt;p&gt;The View Model will also have properties or methods that the View can use to access the Model data. Remember the Model is completely hidden from the View, so the View Model provides that access. In a real situation, it would also do whatever translation or packaging was required to make the View&amp;rsquo;s life easy. In our example it is rather simple.&lt;/p&gt;
&lt;p&gt;class LightViewModel: ObservableObject {
@Published private var lightBulb = Light(on: false)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func toggle() {
 lightBulb.on = !lightBulb.on
}

var isOn: Bool { return lightBulb.on }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Again, the View Model is in it&amp;rsquo;s own file. The only thing we haven&amp;rsquo;t mentioned is the &lt;em&gt;@Published&lt;/em&gt; used in the property for our Model. This is just part of the magic mentioned earlier in the discussion about &lt;a href="https://developer.apple.com/documentation/combine/observableobject"&gt;ObservableObject&lt;/a&gt; which allows the View to know that something has changed, and that it needs to react to this by rebuilding the View.&lt;/p&gt;
&lt;h3 id="view"&gt;View&lt;/h3&gt;
&lt;p&gt;The View is just our regular SwiftUI view. A crucial part is that it holds the View Model for the light as a property wrapped with the @ObservedObject. This completes out connections between the three parts of our architecture.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Model View is an @ObservableObject which has the Model as a @Published property&lt;/li&gt;
&lt;li&gt;The View contains the View Model as an @StateObject property&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These connections have these effects&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The View cannot ever access the Model directly&lt;/li&gt;
&lt;li&gt;If the Model changes, the View Model is aware, and broadcasts this in a way that the View knows about&lt;/li&gt;
&lt;li&gt;The View just redraws itself if that happens&lt;/li&gt;
&lt;li&gt;As the View does this, it asks the View Model for the parts of the data it needs&lt;/li&gt;
&lt;li&gt;This both protects and hides the Model from the view, and is an opportunity for the View Model to do any work it needs to to the data to make it easy for the View to put on the screen.&lt;/li&gt;
&lt;li&gt;Any user interaction that occurs in the View is passed to the View Model to deal with.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;struct ContentView: View {
@StateObject var light = LightViewModel()&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var body: some View {
 VStack{
 Spacer()
 if light.isOn {
 drawLitBulb
 }
 else {
 Image(systemName: &amp;quot;lightbulb.fill&amp;quot;).font(.system(size: 72))
 }
 Spacer()
 Button(&amp;quot;Toggle Light&amp;quot;, action: {
 light.toggle()}
 )
 .padding()
 .font(.title)
 .foregroundColor(.white)
 .background(Color.accentColor)
 .cornerRadius(10)
 .padding()
 }
}

var drawLitBulb: some View {
 // view of an iluminated bulb
 ZStack{
 Circle().fill(.yellow).frame(width: 150, height: 150)
 Image(systemName: &amp;quot;lightbulb&amp;quot;).font(.system(size: 72))
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;To make the code read nicely, the View Model is called &amp;ldquo;light&amp;rdquo;, and it&amp;rsquo;s an @StateObject so for the redrawing trigger to work correctly. The rest of the code should be reasonably clear if you&amp;rsquo;ve made a few SwiftUI views.&lt;/p&gt;
&lt;p&gt;We check if the light is on (by asking the View Model), if it is, we draw a lit bulb, if not, an unlit bulb is drawn. The last UI element is our Button() whose action is the toggle() method of light - our View Model.&lt;/p&gt;
&lt;p&gt;The source for this project is on &lt;a href="https://github.com/IanKulin/MVVMLight"&gt;GitHub here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>MVVM Explained</title><link>https://blog.iankulin.com/mvvm-explained/</link><pubDate>Sun, 07 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/mvvm-explained/</guid><description>&lt;p&gt;The first nine minutes of &lt;a href="https://www.youtube.com/watch?v=sLHVxnRS75w"&gt;this video&lt;/a&gt; from &lt;a href="https://twitter.com/Its_Macco"&gt;Emmanuel Okwara&lt;/a&gt; finally gave me a clear understanding of the difference between MVC and MVVM.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/sLHVxnRS75w?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;In both MVC and MVVM the data &amp;amp; logic (Model) are separated from the part that the user interacts (View). Usually the View is a screen with controls and so on, but that&amp;rsquo;s not compulsory - for example a voice mail app interface would be all audio and DTMF. The point is that in both, the user interface (view) does not mess directly with the data (model) - it has to go through some sort of gatekeeper.&lt;/p&gt;
&lt;p&gt;The new understanding I got from Emmanuel is that in MVVM, the View Model does not know what is in the View. It does not alter the view, just broadcasts that there&amp;rsquo;s been a change and lets the view go ahead and update itself. It makes sense that this would be the paradigm for SwiftUI&amp;rsquo;s declarative interface style, and is also (I imagine but actually have no idea) the basis for React.js&lt;/p&gt;
&lt;p&gt;One thing Emmanuel mentions that I&amp;rsquo;m not clear on is that each View will have it&amp;rsquo;s own View Controller. Currently all my tiny apps have had one view in the SwiftUI sense. I have pulled out sub views, and some have had views within views - for example with the Navigation View. So I guess my question would be, &amp;ldquo;What constitutes a View in MVVM?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I noped out at the nine minute mark as soon as Interface Builder showed it&amp;rsquo;s face. I&amp;rsquo;m an iOS15 SwiftUI baby - I will, eventually, need to learn the old magic, but competence developing iOS apps using SwiftUI current methods is the MVP.&lt;/p&gt;
&lt;p&gt;With this understanding, and having finished lecture 4 from the cs193p series, I think a good project for today would be the simplest possible MVVM app with the correct separations and bindings.&lt;/p&gt;</description></item></channel></rss>