How to use MainActor with Observable Macro in SwiftUI | Swift Concurrency #19

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back everybody my name is Nick this is swiftel thinking and I'm now in the Swift concurrency playlist I'm adding a video to the end of the Swift concurrency playlist that is going to be specific to working with the new observable macro I think this is a very important video for swiftui developers who have been using at observed object and are now switching to the macro because as I'm going to show you guys in the video some of the error and the warning messages that we used to get when we were using the combine framework so when we were using the app published some of those error messages are actually not occurring anymore because of the new macro so it's not necessarily a bad thing that the error message are not occurring but it's a bad thing that the developers might not realize some of the mistakes or bugs that they're actually adding into the code and those errors are mostly around publishing from threads other than the main thread so a couple of videos back in this Swift concurrency playlist I covered how to use Swift concurrency with the main actor and one of the solutions that we came up with was putting the observable object the entire class on the main actor and that was great and that worked for a while but unfortunately we can't do that in tandem with the observable macro at least not today because the macro cannot be specific to an actor and so what we're going to do now is talk about how we can still make sure that we are updating our app our UI from the main thread even while using the new observable macro the code here is not hard but I think there are some things that are getting Lost in Translation and leading to bugs in some apps let me know in the comments below if this cleared anything up for you and I think it'll probably save you a couple bugs maybe a couple crashes because I know it did for me so it must be helping somebody else as well let's jump in xcode and check it out all right we are back back this time I am in the Swift concurrency boot camp so those of you who followed along the Swift concurrency playlist it's all about async await we did a little bit of mvvm in there but we're going to talk in this video a little bit about using the observable macro with ayle weight with actors with main actor with mvvm uh primarily because there's a couple kind of threading issues that I think most developers are overlooking when they use the observable macro I only think that because did it myself for a while and I didn't realize what was happening so I want to show you guys an example of the problem and then the quick solution here it's going to be pretty easy but I think it is worth talking about so I'm going to create a new file in my project here it's going to be a swift UI View and I will call this observable boot camp because this is the only file that we're using the observable macro in this playlist so if you don't know how to yet to use the observable macro I just did a whole video on it it is at the end of the Swift UI boot boot camp playlist just how to use the observable macro so I'm going to assume you guys already know how to use the observable macro from that video and then in this video we're going to talk strictly about some of the threading issues that come with this new setup so before we get into it let's set up our mvvm like we have been setting it up this entire playlist so I'm going to use the observed object protocol set up a quick little mvvm here let's create a class and call this observable view model and conform to observable object open the brackets inside let's put an app published let's make it a variable called title of type string and I'll set it equal to starting title and in my view I will initialize the view model with a state object we'll call Private VAR we'll call it view model and we'll set it equal to observable view model all right this is our prior to iOS 17 setup we're using observable object and not the observable macro and when this screen appears I'm going to call a task so that we can execute execute some asynchronous code and this task is going to call a function inside my view model let's create a function here called update Title open close parenthesis open the brackets and update Title is going to basically just update the title so we'll call we'll set title equal to some new title all right all right from The View we'll call view model. update Title and soon as it renders on the screen it obviously works all right I'm gonna make this the first screen in my app here so I'm going to go to the app. Swift file let's make it the observable boot camp I'm going to build this to a simulator and let's just make sure it works on a simulator real quick all right it is up in my simulator and it looks like it says some new title so clearly it works all right but now let's pretend like we're going to do some background processes let's make an actor here we'll call it maybe like title database something for now and in here we're just going to say funk get new title and this is going to return us a string let's just return some new title from that function so in my view model let's get a reference to the database so we'll say let database equals title database and then in my function I'm just going to set title equal to database. get new title now when we do this we need to await to get into that actor right if you don't understand actors you don't understand how a wait works then you haven't followed this playlist yet follow this playlist first before get into this video obviously we need to await so that means this function needs to be asynchronous so async and we will await now when we call the task down here we also need to await because this is async so we will await here I'm going to build and run this to the simulator and it works right it works some new title worked but we get this purple warning that comes through the combine framework that says publishing changes from from background threads is not allowed make sure to publish from the main thread we've seen this many times on my channel anytime you're using observable object and a p at published and you're publishing from a background thread you get this warning so this is really really helpful for developers right because we know as soon as we run this to the simulator okay there's a Threading issue here I need to make sure that this is going to be updated from the main threat this should not this is probably not a new warning to you guys and one of the ways to solve that prior to iOS 17 was making our view model conform to the at main actor and now if I run it we know that these functions are going to return back onto the main actor right and so now the warning goes away easy peasy problem that we're talking about now is actually that when we convert to the observable macro that purple warning we just saw is not going to appear I hope in a future version of switch Swift that they make that warning appear but that warning comes from the combine framework and the observable object protocol and because we're not using this protocol anymore we don't get that warning and I think that's going to cause a lot of bugs in a lot of developers apps so that's why I'm talking about it today so just to show you guys let's convert this view model now into at observable so I'm going to move quickly through this because I already did this in the swiftui boot camp video we're basically going to make this class marked as at observable we we're going to remove the observed object protocol we're going to remove our at published variables this database here does not need to publish to the view so I will make this at observation ignored State object becomes at State and we have migrated but now I'm going to build and run this to the simulator and I need to update my project here to iOS 17 again you can only do this if you're building for iOS 17 uh I'm going to build and run this to the simulator and it's going to work it's going to say some new title and we did not get any warning here that's what I'm trying to highlight we didn't get any purple warning that there was a problem right but we know that we removed the at main actor from this class so if I come in here and I print out thread. current and I build and run this we can see the the thread that's printing out is thread number five so when we updated this title we actually did it from the fifth thread not from the main thread and we didn't get a warning that we can't publish from the M from background threads that warning was very helpful for a lot of iOS developers and it kind of just disappeared with this observable macro so let's remember as devs that anytime we update the UI we need to do it from the main threat and unfortunately with the observable macro at least as it is today we can't Mark the entire class as main actor anymore it causes other problems because of the way that the observable macro compiles so how are we going to solve this there's a couple quick ways to solve this firstly let's just remember that we always want to update from the main threat so now we're going to go through a couple ways that we can solve this problem pretty easily actually first and foremost we can mark the title this property as at main actor so now anything that tries to update Title is going to get a warning that any to be on the main actor and we can see here main actor property title cannot be mutated from nonisolated Context so now the compiler knows that this is happening from a thread that's other than the main actor and it's causing a problem so one solution is we could put this entire function onto the main actor so before we had the entire class on the main actor and now instead we can just make this function at main actor build and run that looks like it worked Works print out here says thread number one so that is the main thread looks like everything is working if we don't want to mark this entire function as the main actor we could instead just get the T get the title so we can say let title equals this and then we can await main actor. run we can switch on to the main actor set self. tile equal to the title and I will just print out the thread here build and run that one more time looks like it works printing from the first thread and then one other way we can do this is If instead of making this function async if we started a task inside this function so for example if this was an on air let's get rid of the o08 here let's make this a regular function let's get rid of our main actor. run actually let's just set title back equal to the default state that we had and if we created our task inside this closure we can actually make this task run on the at main actor in this closure build and run it one more time all right and it looks like we are updating from the main thread awesome I think there's a lot of devs who are converting to observable and not realizing that there are some threading issues primarily because that purple warning that we saw at the beginning of the video is not there anymore uh that is something that I wish we still had uh I myself got confused here so I hope this solves somebody some bugs in some app uh last thing I'll point out here is that the task modifier every time that we have some sort of await to for example here we are awaiting we need to recognize await represents there's a possible switch in Threads and that means in my code I need to know at some point I need to switch back onto the main actor so either we can mark the to function as main actor we can await to switch back to the main actor or we can mark the tasks as main actor as I did before here awesome now you guys know how to use observable macro with asyn actors and mbvm thank you guys for watching as always my name is Nick this is swivle thinking and I will see you in the next [Music] video
Info
Channel: Swiftful Thinking
Views: 3,932
Rating: undefined out of 5
Keywords:
Id: 4dQOnNYjO58
Channel Id: undefined
Length: 12min 30sec (750 seconds)
Published: Fri Mar 01 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.