Didn't get a chance to attend the SwiftUI Best Practices with Realm Meetup? Don't worry, we recorded the session and you can now watch it at your leisure to get you caught up.
SwiftUI Best Practices with Realm
In this event, Jason Flax, the engineering lead for the Realm iOS team, explains what SwiftUI is, why it's important, how it will change mobile app development, and demonstrates how Realm's integration with SwiftUI makes it easy for iOS developers to leverage this framework.
- In this 50-minute recording, Jason covers:
- SwiftUI Overview and Benefits
- SwiftUI Key Concepts and Architecture
- Realm Integration with SwiftUI
- Realm Best Practices with SwiftUI
Ian Ward: All right, I think we are just about ready to kick it off. So to kick it off here, this is a new year and this is our kind of first inaugural meeting for the user group for the Realm user group. What we're going to do over the course of this next year is have and schedule these at least once a month if not multiple times a month. Where we kind of give a talk about a particular topic and then we can have a Q&A. And this is kind of just about exchanging new and interesting ideas. Some of them will be about iOS, obviously we have other SDKs. It could be about Android. Some of them will come from the Realm team. Others could come from the community. So if you have a particular talk or something you want to talk about, please reach out to us. We would love to hear from you. And potentially, you could do a talk here as well.
Ian Ward: The format kind of today is we're going to hear from Jason Flax. And actually, I should introduce myself. I'm Ian Ward. I do product at MongoDB but I focus on the Realm SDK, so all of our free and opensource community SDKs as well as the synchronization product. I came over the with the Realm acquisition approximately almost two years ago now. And so I've been working on mobile application architecture for the last several years. Today, we're going to hear from Jason Flax who is our lead iOS engineer. The iOS team has been doing a ton of work on making our SwiftUI integration really great with Realm. So he's going to talk about. He's also going to kind of give a quick rundown of SwiftUI. I'll let him get into that.
Ian Ward: But if you could please, just in terms of logistics, mute yourself during the presentation, he has a lot to go through. This will be recorded so we'll share this out later. And then at the end, we'll save some time for Q&A, you can ask questions. We can un-mute, we can answer any questions you might have. If you have questions during the presentation, just put them in the chat and we'll make sure to get to them at the end. So without further adieu, Jason, if you want to kick it off here and maybe introduce yourself.
Jason Flax: Sure thing. Yeah, thanks for the intro there. So I'm Jason Flax. I am the lead of the Cocoa team or the iOS team. I did not come along with the Realm acquisition, I was at Mongo previously. But the product that I was working on Stitch largely overlapped with the work of Realm and it was a natural move for me to move over to the Cocoa team.
Jason Flax: It's been a great, has it been two years? I actually don't even know. Time doesn't mean much right now. But yeah, it's been a lot of fun. We've been working really hard to try to get Realm compatible with SwiftUI and just working really well. And I think we've got things in a really nice place now and I'm pretty excited to show everyone in the presentation. I'll try to move through it quickly though because I do want to get time for questions and just kind of the mingling that you normally have at an actual user group. Cool.
Ian Ward: Perfect. Thanks Jason. Yeah, normally we would have refreshments and pie at the end. But we'll have to settle for some swag. So send out a link in the chat if you want to fill it out to get some swag, it'd be great. Thank you for attending and thank you Jason.
Jason Flax: Cool. I'll start sharing this. Let's see where it's at. Can people see the presentation?
Ian Ward: I can. You're good.
Jason Flax: Cool. All right, well, this is SwiftUI and Realm best practices. I am Jason Flax lead engineer for the Realm Cocoa team. All very self explanatory. Excited to be here, as I said. Let's get started. Next. Cool, so the agenda for today, why SwitftUI, SwiftUI basics which I'll try to move through quickly. I know you all are very excited to hear me talk about what VStack is. Realm models, how they actually function, what they do, how they function with SwiftUI and how live objects function with SwiftUI since it's a very state based system. SwiftUI architecture which expect that to be mildly controversial. Things have changed a lot since the old MVC days. A lot of the old architectures, the three letter, five letter acronyms, they don't really make as much sense anymore so I'm here to talk about those. And then the Q&A.
Jason Flax: Why SwiftUI? I'm sure you all are familiar with this. That on the right there would actually be a fairly normal storyboard, as sad as that is. And below would be a bit of a merge conflict there between the underlying nib code which for anybody that's been doing iOS development for a while, it's a bit of a nightmare. I don't want to slag UI kit too hard, it actually is really cool. I think one of my favorite things about UI kit was being able to just drag and drop elements into code as IBOutlets or so on.
Jason Flax: I've actually used that as means to teach people programming before because it's like, oh right, I have this thing on this view, I drag and drop it into the code. That code is the thing. That code is the thing. That's a really powerful learning tool and I think Apple did a great job there. But it's kind of old. It didn't necessarily scale well for larger teams. If you had a team of four or five people working on an app and you had all these merge conflicts, you'd spend a full day on them. Not to mention the relationships between views being so ridiculously complex. It's the stuff of nightmares but it's come a long way now. SwiftUI, it seems like something they've been building towards for a really long time.
Jason Flax: Architectures, this is what I was just talking about. UI kit, though it was great, introduced a lot of complex problems that people needed to solve, right? You'd end up with all of this spaghetti code trying to update your views and separate the view object from the business logic which is something you totally need to do. But you ended up having to figure out clever ways to break these pieces up and connect all the wires. The community figured out various ways. Some working better for others. Some of them were use-case based. The problem was if you actually adhered to any of them, with the exception of maybe MVC and MVI which we'll talk about later, you'd end up with all of these neat little pieces, like Legos even but there's a lot of boilerplate. And I'd say you'd kind of have gone from spaghetti code to ravioli code which is a whole different set of problems. I'll talk later on about what the new better architectures might be for SwiftUI since you don't need a lot of these things anymore.
Jason Flax: Let's go over the basics. This is an app. SwiftUI.app there is a class that is basically replacing app delegate, not a class, protocol, sorry. It's basically replacing the old app delegate. This isn't a massive improvement. It's removing, I don't know, 10 lines of code. It's a nice small thing, it's a visual adjustment. It sets the tone I guess of for the rest of SwiftUI. Here we are, @main struct app, this is my app, this is my scene, this is my view. There you go, that's it. If you still need some of the old functionality of SwiftUI, or sorry not SwiftUI, app delegate, there is a simple property wrapper that you just add on the view, it's called UI application development adaptor. That'll give a lot of the old features that you probably still will need in most iOS apps.
Jason Flax: Moving on, content view. This is where the meat of the view code is. This is our first view. Content view as itself is not a concept. It happens to be when I'm in my view, it is very descriptive of what this is. It is the content. Basically the rest of the SwiftUI presentation is going to be me stepping through each of the individual views, explaining them, explaining what I'm doing and how they all connect together. On the right, what we're building here is a reminders' app. Anybody here that has an iPhone has a reminders' app. This is obviously, doesn't have all the bells and whistles that that does but it's a good way to show what SwiftUI can do.
Jason Flax: The navigation view is going to be many people's top level view. It enables a whole bunch of functionality in SwiftUI, like edit buttons, like navigation links, like the ability to have main and detailed views and detailed views of detailed views. All the titles are in alignment. As you can see, that edit button, which I am highlighting with my mouse, that's actually built in. That is the edit button here. That will just sort of automagically enable a bunch of things if you have it in your view hierarchy. This is both a really cool thing and somewhat problematic with SwiftUI. There is a load of implicit behavior that you kind of just need to learn. That said, once you do learn it, it does mean a lot less code. And I believe the line goes, the best line of code is the one that's never been written. So less code the better as far as I'm concerned so let's dig in.
Ian Ward: That's right.
Jason Flax: It's one of my favorites. Cool, so let's talk about the VStack. Really straightforward, not gong to actually harp on this too long. It's a vertical stack views, it's exactly what it sounds like. I suppose the nice thing here is that this one actually is intuitive. You put a bunch of views together, those views will be stacked. So what have here, you have the search bar, the search view, the reminder list results view. Each one of these is a reminder list and they hook into the Realm results struct, which I'll dig into later. A spacer, which I'll also dig into a bit, and the footer which is just this add list button and it stacks them vertically.
Jason Flax: The spacers a weird thing that has been added which, again, it's one of these non-intuitive things that once you learn it, it's incredibly useful. Anybody familiar with auto layout and view constraints will immediately sort of latch onto this because it is nice when you get it right. The tricky part is always getting it right. But it's pretty straightforward. It creates space between views. In this case, what it's literally doing is pushing back the reminder list results view in the footer, giving them the space needed so that if this... it knocks the footer to the bottom of the view which is exactly what we want. And if the list continues to grow, this inner, say, view, will be scrollable while the footer stays at the bottom.
Jason Flax: Right, @State and the $ operator. This is brand new. It is all tied to property wrappers. It was introduced alongside SwiftUI though they are technically separate features. @STate is really cool. Under the hood what's happening is search filter isn't actually baked into the class that way. When this code compiles, there actually will be an underscore search filter on the view that is the string. The search filter you see here, the one that I'm referencing several times in the code, that is actually the property or the @State. And @State is a struct that contains reference based storage to this sting that I can modify it between views. And when the state property is updated, it will actually automatically update the view because state inherits from a thing call dynamic property which allows you to notify the view, right, this thing has changed, please update my view.
Jason Flax: And as you can see on the right side here, when I type into the search bar, I type ORK, O-R-K, which slowly narrows down the reminder list that we have available. It does that all kind of magically. Basically, in the search view I type in, it passes that information back to state which isn't technically accurate but I'll explain more later. And then will automatically update the results view with that information.
Jason Flax: The $ operator is something interesting out of property wrappers as well. All property wrappers have the ability to project a value. It's a variable on the property wrapper called projected value. That can be any type you want. In the case of @State, it is a binding type. Binding is going to encapsulate the property. It's going to have a getter and setter and it' going to do some magic under the hood that when I pass this down to the views, it's going to get stored in the view hierarchy. And when I modify it, because it holds the same let's say reference and memory as @State, @State is going to know, okay, I need to update the view now. We're going to see the $ operator a bunch here. I'll bring it up several times because Realm is now also taking advantage of this feature.
Jason Flax: Let's dig into custom views. SwiftUI has a lot of really cool baked in functionality. And I know they're doing another release in June and there's a whole bunch of stuff coming down the pipeline for it. Not every view you'd think would exist exists. I really wanted a simple clean Appley looking search view in this app so I had to make my own custom class for it. You'll also notice that I pass in the search filter which is stored as a state variable on the content view. We'll get to that in a moment. This is the view. Search view, there's a search filter on top. This is the @binding I was talking about. We have a verticle stack of views here. Let's dig in.
Jason Flax: The view stack actually just kind of sets up the view. This goes back into some of the knowledge that you just kind of have to gain about how spacers work and how all of these stacks work. It's aligned in the view in a certain way that it fills in the view in the way that I want it too. It's pretty specific to this view so I'm not going to harp on it too long. HStack is the opposite of a VStack, is a horizontal stack of views. The image here will trail the text field. If you have a right to left language, I'm fairly certain it also switches to which is pretty cool. Everything is done through leading and trailing, not left and right so that you can just broadly support anything language based. Cool.
Jason Flax: This is the image class. I actually think this is a great addition. They've done a whole bunch of cool stuff under the hood with this. Really simple, it's the magnifying glass that is the system name for the icon. With SwiftUI, Apple came out with this thing called SF Symbols. SF stands for San Francisco there, it ties to their San Francisco font. They came out with this set of icons, 600 or so, I'm not sure the exact number, that perfectly align themselves with the bog standard Swift UI views and the bog standard Apple fonts and all that kind of thing. You can download the program that lets you look at each one you have and see which ones you have access to. It's certainly not a secret. And then you can just access them in your app very simply as so.
Jason Flax: The cool thing here that I like is that I remember so many times going back and forth back when I was doing app development with our designers, with our product team of I need this thing to look like this. It's like, right, well, that's kind of non-standard, can you provide us with the icon in the 12 different sizes we needed. I need it in a very specific format, do you have Sketch? You have Sketch, right? Cool, okay, Sketch, great. There's no need for that anymore. Of course there's still going to be uses for it. It's still great for sketching views and creating designs. But the fact that Apple has been working towards standardizing everything is great. It still leaves room for creativity. It's not to say you have to use these things but it's a fantastic option to have.
Jason Flax: This is your standard text field. You type in it. Pretty straightforward. The cool thing here ties back to the search filter. We're passing that binding back in, that $ operator. We're using it again. You're going to keep seeing it. When this is modified, it updates the search filter and it's, for a lack of better way to put it, passed back between the views. Yeah. This slide is basically, yeah, it's the app binding.
Jason Flax: Let's dig into the models. We have our custom view, we have our search view. We now have our reminder view that we need to dig into to have any of this working. We need our data models, right? Our really basic sort of dummy structures that contain the data, right? This is a list of reminders. This is the name of that list, the icon of that list. This is a reminder. A reminder has a name, a priority, a date that it's due, whether or not it's complete, things like that, right? We really want to store this data in a really simple way and that's whee Realm comes in handy.
Jason Flax: This is our reminder class. I have it as an embedded object. Embedded objects are a semi-new feature of Realm that differ from regular objects. The long story short is that they effectively enable cascade and deletes which means that if you have a reminder list and you delete it, you really wouldn't want your reminder still kind of hanging out in ether not attached to this high level list. So when you delete that list, EmbeddedObject enables it just be automatically nixed from the system. Oops, sorry, skipped a slide there.
Jason Flax: RealmEnum is another little interesting thing here. It allows you to store enums in Realm. Unfortunately the support is only for basic enums right now but that is still really nice. In this case, the enum is of a priority. Reminders have priorities. There's a big difference between taking out the trash and, I don't know, going for a well checkup for the doctor kind of thing. Pretty standard stuff. Yeah.
Jason Flax: ObjectKeyIdentifiable is something that we've also introduced recently. This one's a little more complex and it ties into combine. Combine is something I haven't actually said by name yet but it's the subscription based framework that Apple introduced that hooks into SwiftUI that enables all of the cool automatic updates of views. When you're updating a view, it's because new data is published and then you trigger that update. And that all happens through combine. Your data models are being subscribed to by the view effectively. What ObjectKeyIdentifiable does is that it provides unique identifier for your Realm object.
Jason Flax: The key distinction there is that it's not providing an identifier for the class, it's providing an identifier for the object. Realm objects are live. If I have this reminder in memory here and then it's also say in a list somewhere, in a result set somewhere and it's a different address in memory, it's still the same object under the hood, it's still the same persisted object and we need to make sure that combine knows that. Otherwise, when notifying the view, it'll notify the view in a whole bunch of different places when in reality, it's all the same change. If I change the title, I only want it to notify the view once. And that's what ObjectKeyIdentifiable does. It tells combine, it tells SwiftUI this is the persisted reminder.
Jason Flax: Reminder list, this is what I was talking about before. It is the reminder list that houses the reminders. One funny thing here, you have to do RealmSwift.List if you're defining them in the same file that you're importing SwiftUI. We picked the name List for lists because it was not array and that was many, many years ago but of course SwiftUI has come up with their own class called Lists. So just a little tidbit there. If you store your models in different classes, which for the sake of a non-demo project you would probably do, it probably won't be an issue for you. But just a funny little thing there. One thing I also wanted to point out is the icon field. This ties back to system name. I think it's really neat that you can effectively store UI based things in Realm. That's always been possible but it's just a lot neater now with all of the built in things that they supply you with.
Jason Flax: Let's bring it way back to the content view. This again is the top level view that we have and let's go into the results list, ReminderListResultsView and see what's happening there. So as you can see, we're passing in again that $searchFilter which will filter this list which I'm circling. This is the ReminderListResultsView, it's a bit more code. There's a little bit more going on here but still 20 lines to be able to, sorry, add lists, delete lists, filter lists, all that kind of thing. So list and for each, as I was just referencing, have been introduced by SwiftUI. There seems to be a bit of confusion about the difference between the two especially with the last release of SwiftUI. At the beginning it was basically, right, lists are static data. They are data that is not going to change and ForEach is mutable data. That's still the general rule to go by. The awkward bit is that ForEach still needs to be nested in lists and lists can actually take mutable data now. I'd say in the June release, they'll probably clean this up a bit. But in the meantime, this is just kind of one of those, again, semi non-intuitive things that you have do with SwiftUI.
Jason Flax: That said, if you think about the flip side and the nice part of this to spin it more positively, this is a table view. And I'm sure anybody that's worked with iOS remembers how large and cumbersome table views are. This is it. This is the whole table view. Yeah, it's a little non-intuitive but it's a few lines of code. I love it. It's a lot less thinking and mental real estate for table views to be taking up.
Jason Flax: NavigationLink is also a bunch of magic sauce that ties back to the navigation view. This NavigationLink is going to just pass us to the DetailView when tapped which I'll display in a later slide. I'm going to tap on one of these reminder lists and it's going to take me to the detailed view that actually shows each reminder. Yeah.
Jason Flax: Tying this all back with the binding, as you can see in the animation as we showed before, I type, it changes the view automatically and filters out the non-matching results. In this case, NSPredicate is the predicate that you have to create to actually filter the view. The search filter here is the binding that we passed in. That is automatically updated from the search view in the previous slides. When that changes, whenever this search filter is edited, it's going to force update the view. So basically, this is going to get called again. This filter is going to contain the necessary information to filter out the unnecessary data. And it's all going to tie into this StateRealmObject thing here.
Jason Flax: What is StateRealmObject? This is our own homegrown property wrapper meant and designed in a way to mimic the way that state objects work in SwiftUI. It does all the same stuff. It has heap based storage that stores a reference to the underlying property. In this case, this is a fancy little bit of syntactic sugar to be able to store results on a view. Results is a Realm type that contains, depending on the query that you provide, either entire view of the table or object type or class type that you're looking up. Or that table then queried on to provide you with what you want which is what's happened here with the filter NSPredicate. This is going to tie into the onDelete method. Realm objects function in a really specific way that I'll get to later. But because everything is live always with Realm, we need to store State slightly differently than the way that the @State and @ObservedObject property wrappers naturally do.
Jason Flax: OnDelete is, again, something really cool. It eliminates so much code as you can see from the animation here. Really simple, just swipe left, you hit delete or swipe right depending on the language and it just deletes it. Simple as. The strange non-intuitive thing that I'll talk about first is the fact that that view, that swipe left ability is enabled simply by adding this onDelete method to the view hierarchy. That's a lot of implicit behavior. I'm generally not keen on implicit behavior. In this case, again, enabling something really cool in a small amount of code that is just simply institutional knowledge that has to be learned.
Jason Flax: When you delete it, and this ties into the StateRealmObject and the $ remove here, with, I suppose it'll be the next update, of Realm Swift, the release of StateRealmObject, we are projecting a binding similar to the way that State does. We've added methods to that binding to allow you to really simply remove, append and move objects within a list or results depending on your use case. What this is doing is wrapping things in a write transaction. So for those that are unfamiliar with Realm, whenever you modify a managed type or a managed object within Realm, that has to be done within a write transaction. It's not a lot of code but considering SwiftUI's very declarative structure, it would be a bit frustrating to have to do that all over your views. Always wrapping these bound values in a write transaction. So we provided a really simple way to do that automagically under the hood, $ property name.remove, .append, .whatever. That's going to properly remove it.
Jason Flax: In this case because it's results, it's going to just remove the object from the table. It's going to notify the view, this results set, that, right, I've had something removed, you need to update. It's going to refresh the view. And as you can see, it will always show the live state of your database of the Realm which is a pretty neat thing to sort of unlock here is the two-way data binding.
Jason Flax: ReminderListRowView, small shout out, it's just the actual rows here. But digging into it, we're going to be passing from the ForEach each one of these reminder lists. Lists is kind of an unfortunate name because lists is also a concept in Realm. It's a group of reminders, the list of reminders. We're going to pass that into the row view. That is going to hydrate this ObservedRealmObject which is the other property wrapper I mentioned. Similarly to ObservedObject which anyone that's worked with SwiftUI so far has probably encountered ObservedObject, this is the Realm version. This does some special things which I'm happy to talk about in the Q&A later. But basically what this is doing is again binding this to the view. You can use the $ operator. In this case, the name of the reminder list is passed into a TextField. When you edit that, it's going to automatically persist to the realm and update the view.
Jason Flax: In my head I'm currently referring to this as a bound property because of the fact that it's a binding. Binding is a SwiftUI concept that we're kind of adopting with Realm which had made things work easy peasy. So stepping back and going into the actual ReminderListView which is the detailed view that the navigation link is going to send us to, destination is a very accurate parameter name here. Let's dig in. Bit more code here. This is your classic detailed view, right? There's a back button that sends you back to the reminders view. There's a couple other buttons here in the navigation view. Not super happy that edit's next to add but it was the best to do right now. This is going to be the title of the view, work items. These are things I have to do for work, right? Had to put together this SwiftUI talk, had to put together property wrappers. And all my chores were done as you saw on the other view so here we are. Let's take a look.
Jason Flax: Really simple to move and delete things, right? So you hit the edit button, you move them around. Very, very similar to OnDelete. SwiftUI recognizes that this onMove function has been appended to the view hierarchy and it's going to add this ability which you can see over here on the right when the animation plays, these little hamburger bars. It enables those when you add that to the view. It's something throws people off a lot. There's a load of of stack overflow questions like how do I move things, how do I move things? I've put the edit button on, et cetera. You just add the onMove function. And again, tying back to the ObservedRealmObject that we spoke about in the ReminderListRowView, we added these operators for you from the $ operator, move and remove to be able to remove and delete objects without having to wrap things in a write transaction.
Jason Flax: And just one last shout out to those sort of bound methods here. In this case, we hit add, there's a few bits of code here that I can dig into later or we can send around the deck or whatever if people are interested in what's going on because there is sort of a custom text field here that when I edit it's focused on. SwiftUI does not currently offer the ability to manually focus views so I had to do some weird stuff with UIViewRepresentable there. The $ append is doing exactly what I said. It's adding a brand new reminder to the reminder list without having to write things in a realm, wrap things in a write transaction, sorry.
Jason Flax: What I've kind of shown there is how two-way data binding functions with SwiftUI, right? Think about what we did. We added to a persisted list, we removed from a persisted list. We moved objects around a persisted list, we changed fields in persisted objects. But didn't actually have to do anything else. We didn't have to have a V-model, we didn't have to abstract anything else out. I know, of course, this is a very, very simple application. It's a few hundred lines of code, not even, probably like 200. Of course as your application scales, if you have a chat app, which our developer relations team is currently working on using Realm in SwiftUI, you have to manage a whole bunch more State. You're probably going to have a large ObservedObject app state class that most SwiftUI apps still need to have. But otherwise, it doesn't seem to make much sense to create these middle layers when Realm offers the ability to just keep everything live and fresh at all times.
Jason Flax: I'm going to kind of take a stance on architectures here and say that most of them kind of go away. I'd say many people here would be familiar with MVC, right? There's a view, there's a controller, there's a model. But even just briefly talking a look at these arrows and comparing them to the example that I just went through, these don't really apply anymore. You don't need the controller to send updates to the model because the models being updated by the view, right? And the views not even really updating the model. The models just being updated. And it certainty doesn't need to receive State from the view because it's stateful itself. It has it's state, it is live. It is ready to go. So this whole thing, there is no controller anymore. It eliminates the C in MVC. In which case I say dump it. There's no need for it anymore. I'm over it, I don't want to hear it MVC again. I'm also just kidding. Of course there still will be uses for it but I don't think it has much for us.
Jason Flax: MVVM, same thing. It's a bit odd when you have Realm live objects to want to notify the models of updates when nine times out of 10 you probably want the model to just immediately receive those updates. There are still a couple of use cases where say you have a form, you want something not persisted to the Realm. Maybe you want to save some kind of draft state, maybe you don't want everything persisted immediately. Or maybe your really complex objects that you don't want to automatically use these bound write transactions on because that can be pretty expensive, right? There are still use cases where you want to abstract this out but I cannot see a reason why you should use V-models as a hard and fast rule for your code base. In which case I would say, throw it away, done with it. Again MVVM, not really very useful anymore.
Jason Flax: Viper is another very popular one. I think this one's actually a bit newer because not really anybody was talking about it back when I was doing iOS around a few years ago for actual UI applications. It's view interactor presenter entity router, it certainly doesn't roll off the tongue nicely though I suppose Viper's meant to sound bad ass or something. But I actually think this one worked out pretty well for the most part for UI. It created these really clear-cut relationships and offered a bit of granularity that was certainly needed that maybe MVVM or MVC just couldn't supply to somebody building an app. But I don't really think it fits with UI. Again, you'll end up with a bunch of ravioli code, all these neat little parts.
Jason Flax: The neat little parts of SwiftUI should be all the view components that your building and the models that you have. But creating things like routers and presenters doesn't really make sense when it's all just kind of baked in. And it's a concept that I've had to get used to, oh right, all this functionality is just baked in. It's just there, we just have to use it. So yeah, doesn't remotely sound correct anymore for our use case. I don't generally think you should use it with SwiftUI. You absolutely can but I know that we actually played with it in-house to see, right, does this makes sense? And you just end up with a ton of boilerplate.
Jason Flax: So this is MVI, Model View Intent. If I'm not mistaken, this slide was actually presented and WWDC. This is what I'm proposing as the sort of main architecture to use for SwiftUI apps mainly because of how loosely it can be interpreted. So even here the model is actually state. So your data models aren't even mentioned on this graphic, they're kind of considered just part of the state of the application. Everything is state based and because the view and the state have this two-way relationship, everything is just driven by user action, right? The user action is what mutates the models which mutate the view which show the latest and greatest, right? So personally, I think this the way to go. It keeps things simple. Keeping it simple is kind of the mantra of SwiftUI. It's trying to abstract out two decades, three decades of UI code to make things easier for us. So why makes things more difficult, right?
Jason Flax: Thank you very much everyone. Thanks for hearing me out, rambled about architectures. That's all. Just wanted to give a quick shout out to some presentations coming down the line. Nichola on the left there is going to give a presentation on Xamarin Guidance with Realm using the .Net SDK. And Andrew Morgan on the right is going to show us how to use Realm Sync in a real live chat application. The example that I've shown there is currently, unfortunately on a branch. It will eventually move to the main branch. But for now it's there while it's still in review. And yeah, thanks for your time everyone.
Ian Ward: Great. Well Jason, thank you so much. That was very enlightening. I think we do have a couple questions here so I think we'll transition into Q&A. I'll do the questions off the chat first and then we can open it up for other questions if they come to you. First one there is the link to the code somewhere? So you just saw that. Is it in the example section of the Realm Cocoa repo or on your branch or what did you-
Jason Flax: It is currently in a directory called SwiftUI TestToast. It will move to the examples repo and be available there. I will update the code after this user group.
Ian Ward: Awesome. The next question here is around the documentation for all the SwiftUI constructs like State, Realm, Object and some of the property wrappers we have there. I don't know if you caught it yet but I guess this hasn't been released yet. This is the pre new release. You guys are getting the preview right now of the new hotness coming out. Is that right?
Jason Flax: That is correct. Don't worry, there will be a ton of documentation when it is released. And that's not just this thing does this thing, it will also be best practices with it. There's some implicit reasons why you might want to use StateRealmObject verses ObservedRealmObject. But it's all Opensource, it's all available. You'll be able to look at it. And of course we're always available on GitHub to chat about it if the documentation isn't clear.
Ian Ward: Yeah, and then maybe you could talk a little bit about some of the work that the Cocoa team has done to kind of expose this stuff. You mentioned property wrappers, a lot of that has to do with not having to explicitly call Realm.write in the view. But also didn't we do stuff for sync specific objects? We had the user and the app state and you made that as part of ObservableObject, is that right?
Jason Flax: Correct, yeah. I didn't have time to get to sync here unfortunately. But yes, if you are using MongoDB Realm, which contains the sync component of Realm, we have enabled it so that the app class and the user class will also automatically update the view state similar to what I presented earlier.
Ian Ward: Awesome. And then, I think this came up during some of your architecture discussions I believe around MVC. Question is from Simon, what if you have a lot of writes. What if you have a ton of writes? I guess the implication here is that you can lag the UI, right, if you're writing a lot. So is there any best practices around that? Should we be dispatching to the background? How do you think about that?
Jason Flax: Yeah, I would. That would be the first thing if you are doing a ton of writes, move them off to a background queue. The way that I presented to use Realm and SwiftUI is the lowest common denominator, simplest way bog standard way for really simple things, right? If you do have a ton of writes, you're not locked into any of this functionality. All of the old Realm API is still there, it's not old, it's the current API, right? As opposed to doing $ list.append or whatever, if you have 1,000 populated objects ready to hop in that list, all of those SwiftUI closures that I was kind of supplying a method to, you can just do the Realm.write in there. You can do it as you would normally do it. And as your app grows in complexity, you'll have to end up doing that. As far as the way that you want to organize your application around that, one thing to keep in mind here, SwiftUI is really new. I don't know how many people are using it in production yet. Best practices with some of this stuff is going to come in time as more people use it, as more ideas come about. So for now, yeah, I would do things the old way when it comes to things like extensive writes.
Ian Ward: Yeah, that's fair. Simon, sorry I think you had a followup question here. Do you want to just unmute yourself and maybe discuss a little bit about what you're talking about with the write transaction? I can ask to unmute, how do I do that?
Jason Flax: It seems the question is about lag, it's about the cutoffs, I don't need a real time sync. Okay, yeah, I can just answer the question then, that's no bother.
Ian Ward: I think he's referring to permitting a transaction for a character stroke. I don't know if we would really look to, that would probably not be our best practice or how would you think about that for each character.
Jason Flax: It would depend. Write transactions aren't expensive for something simple like string on a view. Now it seems like if, local usage, okay. If you're syncing that up to the server, yes, I would not recommend committing a write transaction on each keystroke but it isn't that expensive to do. If you do want to batch those, again, that is available for you to do. You can still mess with our API and play around to the point where, right, maybe you only want to batch certain ones together.
Jason Flax: What I would do in that case if you are genuinely worried about performance, I would not use a string associated with your property. I would pass in a plain old string and observe that string. And whenever you want to actually commit that string, depending on let's say you want every fifth keystroke, I wouldn't personally use that because there's not really a rhyme or reason for that. But if you wanted that, then you monitor it. You wait for the fifth one and then you write it to the Realm. Again, you don't have to follow the rules of writing on every keystroke but it is available to people that want it.
Ian Ward: Got it. Yeah, that's important to note here. Some of the questions are when are we going to get the release? I think [crosstalk 00:42:56] chomping on the bit here. And then what version are we thinking this will be released?
Jason Flax: I don't think it would be a major bump as this isn't going to break the existing API. So it'll probably be 10.6. I still have to consult with the team on that. But my guess would be 10.6 based on the current versioning from... As far as when. I will not vaguely say soon, as much as I want to. But my guess would be considering that this is already in review, it'll be in the next week or two. So hold on tight, it's almost there.
Ian Ward: And then I think there's a question here around freezing. And I guess we haven't released a thaw API but all of that is getting, the freezing and thawing is getting wrapped in these property wrappers. Is that what we're doing, right?
Jason Flax: Correct, yeah. Basically because SwiftUI stores so much State, you actually need to freeze Realm objects before you pass them into the views? Why is that? If you have a list of things, SwiftUI keeps a State of that list so that it can diff it against changes. The problem is RealmObjects and RealmLists, they're all live. SwiftUI actually cannot diff the changes in a list because it's just going to see it as the same exact list. It also presented itself in a weird way where if you deleted something from the list, because it could cache the old version of it, it would crash the app because it was trying to render an index of the list that no longer exists. So what we're doing under the hood, because previously you had to freeze your list, you had to thaw the objects that come out of the list and then you could finally operate on them, introduced a whole bunch of complexity that we've now abstracted out with these property wrappers.
Ian Ward: And we have some questions around our build system integration, Swift Package Manager, CocoaPods, Carthage. Maybe you want to talk a little bit about some of the work that we've done over the last few months. I know it was kind of a bear getting into SPM but I feel like we should have full Swift Package Managed Support. Is that right?
Jason Flax: We do, yeah. Full SPM support. So the reason that that's changed for us is because previously our sync client was closed source. It's been open sourced. I probably should not look at the chat at the same time as talking. Sorry. It's become open source now. Everything is all available to be viewed, as open source projects are. That change enabled us to be able to use SPM properly. So basically under the hood SPM is downloading the core dependency and then supplying our source files and users can just use it really simply. Thanks for the comments about the hair.
Jason Flax: The nice thing is, so we're promoting SPM as the main way we want people to consume Realm. I know that that's much easier said than done because so many applications are still reliant on CocoaPods and Carthage. Obviously we're going to continue to support them for as long as they're being used. It's not even a question of whether or not we drop support but I would definitely recommend that if you are having trouble for some reason with CocoaPods or Carthage, to start moving over to SPM because it's just so much simpler. It's so much easier to manage dependencies with and doesn't come with the weird cost of XE work spaces and stale dependencies and CocoaPod downloads which can take a while, so yeah.
Ian Ward: I think unfortunately, part of it was that we were kind of hamstrung a little bit by the CocoaPods team, right? They had to add a particular source code for us and then people would open issues on our GitHub and we'd have to send them back. It's good that now we have a blessed installable version of Swift Package Manger so I think hopefully will direct people towards that. Of course, we'd love to continue to support CocoaPods but sometimes we get hamstrung by what that team supports. So next question here is regarding the dependencies. So personally, I like keeping my dependencies in check. I usually keep Realm in a separate target to make my app not aware of what persistence I use. So this is kind of about abstracting away. What you described in the presentation it seems like you suggest to integrate Realm deeply in the UI part of the app. I was thinking more about using publishers with Realm models, erase the protocol types instead of the integrating Realm objects with the RealmStateObject inside of my UI. Do you have any thoughts on that Jason?
Jason Flax: I was thinking about using publishers with Realm models, erase the protocol types, interesting. I'm not entirely sure what you mean Andre about erasing them to protocol types and then using the base object type and just listening to changes for those. Because it sounds like if that's what you're doing, when RealmStateObject, ObservedRealmObject are release, it seems like it would obviate the need for that. But I could also be misunderstanding what you're trying to do here. Yeah, I don't know if you have a mic on or if you want to followup but it does seem like the feature being released here would obviate the need for that as all of the things that would need to listen to are going to be updating the view. I suppose there could be a case where if you want to ignore certain properties, if there are updates to them, then maybe you'd want some customization around that. And maybe there's something that we can release feature-wise there to support that but that's the only reason I could think why you'd want to abstract out the listening part of the publishers.
Ian Ward: Okay, great. Any other questions? It looks like a couple questions have been answered via the chat so thank you very much. Any other questions? Anyone else have anything? If not, we can conclude. Okay, great. Well, thank you so much Jason. This has been great. If you have any additional questions, please come to our forums, forums.realm.io, you can ask them there. Myself and Jason and the Cocoa team are on there answering questions so please reach out to us. You can reach out on our Twitter @Realm and yeah, of course on our GitHub as well Realm-cocoa. Thank you so much and have a great rest of your week.
Jason Flax: Thanks everyone. Thanks for tuning in.
Throughout 2021, our Realm Global User Group will be planning many more online events to help developers experience how Realm makes data stunningly easy to work with. So you don't miss out in the future, join our Realm Global Community and you can keep updated with everything we have going on with events, hackathons, office hours, and (virtual) meetups. Stay tuned to find out more in the coming weeks and months.
To learn more, ask questions, leave feedback, or simply connect with other Realm developers, visit our community forums. Come to learn. Stay to connect.