Download JSON from API in Swift with Combine | Continued Learning #23

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up everyone i'm nick this channel is swiffle thinking where we cover all things swift and swift ui related and i am super excited to share this video with you guys we're gonna do essentially the same thing that we did in the last video if you're with me except in this video we're gonna write the code a little differently because we're using the combine framework this is a new framework from apple that takes advantage of using publishers and subscribers so before we actually get into the coding i'm gonna briefly walk you guys through what combine is why it is so important and then of course we're gonna jump into the code and we're gonna actually download the same data that we did in the last video and i'm doing this on purpose because at the end of this video we're going to compare the method that we used in the last video versus the method we're using in this video i think by the end of this video you'll start to see how the combine framework could just be so powerful and is so useful because the code is sleek it's elegant it's short and condensed and as developers we love that apple has given us this new framework so if you've been following my channel normally i like to slowly introduce you guys to new frameworks and new components but in this one exception we're just going to jump right in because i think that is the easiest way to learn this combine framework all right i hope you guys are excited i'm excited let's jump into xcode and take a look all right welcome back everyone uh super exciting video today we're gonna get into the combine framework and oftentimes when i'm introducing new frameworks we kind of start from the ground up we kind of start very slowly understand the basics and then get into some of the cooler stuff but with combine we're going to kind of do the opposite and we're just going to jump in and start downloading data with combine so we're going to get a real feel on how cool this is and if you're with me in the last video which i have up here we basically downloaded data from an api using the ad escaping completion we checked that we had good data and then we put that data into our app and in this video we're going to basically do the exact same thing except the functions we're going to add are using combine instead of this ad escaping and some of this other code and the reason i taught this way this ad escaping way first is because we didn't have combine until ios 13. so if you are building an app that is going to be compatible with older operating systems before ios 13. we actually need to download this way with the ad escaping but if you're building a newer app that is ios 13 compatible or higher then combine is probably the way to go because as you'll see it is very very efficient and the code is pretty sleek so let's get into it let's right click the navigator let's create a new file it's going to be a swift ui view and we're going to call this download with combine go ahead and click create once you're inside click resume on the canvas and let's get ready to get coding and now before we even begin let's do some setup here and we're going to pretty much mimic what we did on the last video so in the last video we downloaded some data from this json placeholder and i'll link that url below in the comments again of this video basically that is this website here it's coming from a json placeholder website which is basically a free fake api for testing and prototyping and it's super handy for obviously development purposes i will link this below and if for some reason this ever shuts down i will link something else to use an updated version that you guys could use instead but on this website there are a bunch of resources that we can use with fake json apis so if i click on this posts we have basically a url we can use here where we can start to download all of this json data and this json data has a user id an id a title and a body and going back in our last video we created a struct with exactly this data and it conformed to identifiable and it conformed to codeable and since we're downloading the same data we're going to use the same struct so i'm going to copy the struct from the last video and i'm going to comment it out in the last file and let's just paste it into this file for now so if you're just joining you need to create this struct here and in the last video i also went over if if you had some of this data and you had trouble creating a struct from it there is a website called app.quicktype.io which i will also link below and in that website you can paste in your json data and it will give you a struct of that data which is super helpful and handy if your data is much more complicated than where we're at right now with that said i don't want to get into all that again but we have this post model and we want to put some post models onto our screen so let's first create a new view model we'll create a class we'll call it download with combine view model we'll make it conform to observable object and we'll open the brackets we'll create an at published var we'll call it posts and it'll be of type array of post model we'll set it equal to a blank array for now and then let's initialize the viewmodel with an at state object var vm for viewmodel equals download with combine viewmodel and then very simply just like in the last video we're going to create a list open the brackets and we're going to do a for each we're going to loop and we're going to use the first completion here we're going to loop on the vm vm.posts the content it will be for each post and for each post we'll create a simple v stack open the brackets and it'll have a text with the post dot title and a text with the post dot body let's make the title font headline and let's make the body foreground color gray pretty much the same view we had in the last video um the only difference is we're going to download the data a little bit differently so in our view model let's create an init and then let's create a function to get posts open close parenthesis and open the brackets in our init we'll call get posts and the first thing we need is obviously the url just like we did in the last video so we'll say let url equals url and we're going to pass in a string here so that website url i will post below we're basically just going to post the url of this website and into this string here so when we create a url like this it is optional and let's just make sure that it is a valid url with a guard let statement we'll do else return we know this won't fail i'm going to hide the canvas because we're not going to use it for a little while and then we need to write a function here to actually download the data from this url and this is where the combine kind of comes into play and before we actually write some code i want to talk a little bit about combine and publishers so if i type in the combine framework on google come to this page here from the apple developer documentation that basically talks about combine is a way to handle asynchronous events by combining event processing operators the main thing that we think about is publishers and subscribers in the real world if you were to subscribe to a book publisher or a magazine publisher every time they publish a new book a new magazine they would send it to you and a publisher is the same way it's basically an object that is going to deliver us some values over time so we can create publishers and then we can subscribe to publishers so that every time this publisher produces more data and it publishes a new piece of data we can then use that in our app so going back into our code here there is a a lot of ways to think about this and it took me a little while to get used to under really understanding combine and i'm gonna try something a little new here i have a metaphor that i like to use i think will help you guys understand all the pieces to what we're about to do and the situation i'm thinking of is in real life if you were to sign up for a package to be delivered to your house on a monthly subscription because there are a lot of those subscription companies out right now so if you were to sign up for that package the first thing that would happen would be that you would sign up for a monthly subscription for package to be delivered after signing up the second thing that happened was the company would make the package behind the scenes so the factory is going to go ahead and make the package that they're going to be shipping to you they're going to ship the package and you're going to receive the package at maybe your front door after you get it you're going to check the box make sure the box isn't damaged and make sure it may be that the box is actually delivered to you correctly and then once you have the box you're going to open and make sure the item is correct right you're going to make sure that this is exactly what you ordered finally after you have the item of course it's you can finally use the item and this entire process this package subscription is cancelable at any time right because you can cancel at any time that's pretty common these days so this is how i think about the code that we're about to write so first we're going to create the publisher in real life obviously the company already exists that we're signing up for but in our app we need to create the publisher ourselves and we do that by calling url session just like we did in the last video dot shared dot datatask and this time we're looking for the one with a publisher so we're going to use the publisher for url here and we can see that this returns us a url.datatask publisher so it is a publisher and because it's a publisher we know it's going to publish values over time let's hit enter on that and of course we're going to pass in our url all right so this is number one we first created the publisher the second thing we need to do is basically put this publisher onto the background thread because a couple videos back i did a video on background threads and how that can make your app much more efficient and when we are doing tasks like downloading from the internet it's pretty useful to do that on the background thread so we're going to subscribe the publisher on background thread now this is actually done by default in the data task publisher this automatically goes on to a background thread so we don't explicitly need to do number two but we're gonna do it anyway just to go through the motions here so we'll call dot subscribe on and we're gonna put it on a dispatch q dot and we'll go down to the global quality of service and we're going to use the background again we don't actually need this line because this data test publisher is already on the background thread but sometimes you're going to create publishers here and they will not explicitly be on a background thread so you'll want to subscribe them on there by calling this line so now we have number two the third thing is to receive that package at your front door and in our app that basically means we want to receive on the main thread because that's where the ui can be updated from so two so number three will be receive on main thread we call that by very simply calling receive on this will be the dispatch q dot main again if you're unfamiliar with these dispatch queues the background thread and the main thread i did a video on those a couple videos back just go watch that one it will explain all of that that's why i did that before this video number three is down number four is to make sure the box isn't damaged and in our code our number four is going to be a try map and basically this is check that the data is good and we did this in the last video as well and the check will actually be fairly similar so i'm going to call dot try map and click enter i'm going to click enter on the completion here and there are two pieces that we get in this completion here we first and we can see that it's separated by the comma so we're going to call the first one the data and then the second one will be a response and a couple videos back i covered what map is and in my arrays basically we are taking uh some input which in this case is this potential data and we want to return out of this map with some object and we're going to make it type data that is optional all right and the first thing we're going to do is check that this response is an http url response and that it is a valid response so we will say um guard let response equals response as http url response comma and then we're going to check the status code of that response so we'll say response dot status code is greater than or equal to 200 and response dot status code is less than 300 and we will say else so if that fails we can then throw an error so in here we will throw a url error and we will open the parentheses and we're going to use i'm going to press the period here and it's expecting a url error.code and if i click enter on this and i right click and jump to the definition we can see a whole bunch of url error codes where are they we can scroll down here and we can see a whole bunch of the url error codes so there's all types of things for a timeout a bad url cannot connect to host i'm going to use the bad server response so in here i'm going to put dot bad server response and that's the error we're going to throw all right so we're going to check that we have the good data and then if we do we will just return the data all right so try map takes our inputs which is the data and the response make sure it's a good response and then we return that data back out of this function and sorry let's actually make this explicit data here we want to make sure that we are getting data from this function we don't want it to be optional all right so that's number four and then we need to open and make sure that that the item is in the box is correct and here now that we have data we need to make sure that it is actually an array of post models because after all we are trying to download a bunch of post models so we're going to decode this data and so number five will be decode and that will be decode data into post models and to do that we very simply write dot decode and the type is of type decodable protocol and if we look at our post model it already conforms to codable if you don't know what codable is i did an entire video on it maybe two videos back where we covered it in detail it basically lets us decode and encode from json data or any other data into post models so we can actually use this post model here we will call post model dot self and if you remember correctly if we look back at the json placeholder this is actually an array of post model it's not just one that we're downloading so we really want to download it into an array of post model and the decoder here is going to be a json decoder we'll open and close the parentheses all right and now that we actually have an array of post models hopefully we can finally number six use the item and for number six we're going to sync and that will be put the item into our app and basically what this is just taking our post models and then using them in our app so we will call dot sync i will press enter here and we have the completion and the values so first i'm going to click enter on this received completion i'll call this completion and then we have received values should be an array of post model so first in this completion let's just print out the completion we'll print completion colon backslash open close parentheses we'll print out the completion and this will also tell us if we threw the error here this will also tell us that there was an error and that it failed but if it was successful we're going to receive a value that's an array of post models so we're going to say returned posts and we will set the posts the post variable way at the beginning that we made we'll set posts equal to return posts and we're going to get the error here that posts requires explicit use of self and we've seen this now for a couple videos straight so you should be familiar with it and the easy way to fix it is to just put self dot posts but if you've been following along when we do this self.post it creates a strong reference to self and there are situations in our app where we don't want this strong reference because that will keep the that will keep self in memory a lot of times when we don't want it or need it to be so to fix that we can simply add in in the square brackets weak self right here and then self will be optional if you're confused on this week's self i also did a video on week self about five videos back that i highly recommend checking out all right and finally the subscription is cancelable at any time and here we can call store and this is where we can cancel subscription if needed basically we need to store it somewhere like storing the receipt for our subscription so that we can cancel it again if we want to cancel it so we will call dot store and we're going to use the one with a set and when we click it we need a set of any cancelable so we don't have that yet so back up in our view view model here we're going to create a var we'll call this cancelables and i'm going to set it equal to a set that is of type uh any cancelable and any cancel is actually not coming up in my code and that's because we have not yet imported combine into our app here so we're going to import the combine framework so we can access any cancelable and then we will open and close parentheses to initialize a new one so now we have this set and this is basically a place that we will store this publisher so that if we wanted to cancel it in the future we could access this variable and then call cancel basically but for right now we are just going to store it in cancelables all right that was a lot of talking and a lot of code to get where we need to be but now i think it's time to actually test this out so let's first make this a multi-line comment and i will call this uh combine discussion then i'm just gonna close it down with the command option left arrow just so we get rid of some of that on the screen real quick and let's take this download with combine view let's jump into our app.swift file let's make this the first file in our app and let's run it on a simulator and see what happens and jump back into our code here and simulator should pop up i'm going to close down the navigator and i actually got a funky error message here uh basically cannot load because it cannot it does not conform to the ats policy which is which is the app transport security policy and it requires the use of a secure connection so this is actually my fault i simply forgot to add the s in our url apple wants the s for security reasons for all of your urls let's run it one more time hopefully that we don't get that error message again and when our app loads this time hopefully we see some data we get all the data in our app which is exactly what we want we are downloading this data from the internet it's showing up and the completion was called so if i have this completion down here it called finished which is exactly what we were looking for all right i'm going to make our v stack alignment leading so it looks a little bit better and let's make the frame max with infinity alignment leading as well just to push it to the left side here and as i mentioned before we actually don't need to subscribe on the background thread because it automatically goes on to the background thread but as i've said for the last couple videos it is important that if you're on a background thread that when you do receive the data and you go to update the ui it needs to be done on the main thread so that's why we have this receive on the main thread here and if we did not call this and i run my app again we should get that purple warning message that we cannot publish changes from background threads so we know here that we are on the background thread when we shouldn't be and as i mentioned before we can always we can always add checks into our code with the thread dot is main thread or thread dot is dot current to check that that we are on the main thread or or to make sure that the current thread is thread one which is the main thread but basically again if we're going to update the ui we need to receive on the main thread all right so if i run this one more time now that we're back on the main thread here when we're receiving on the main thread it should work without the error message all right and we actually don't need this to print out because we know it is becoming successful in your actual app you'd probably put some logic here that if it wasn't success if there was an error you would want to handle that but for our purposes let's just delete that because we don't really need it right now and the bulk of our code right here is this try map call so i'm actually going to take this try map and make it a function so back up here when we called try map and i click and we clicked enter it was of type url urlsession.datataskpublisher.output so i'm going to copy that and we're going to create a function down here we'll create a func we'll call it handle output and this will take a parameter called output of type urlsession.datatestpublisher.output and again just like when we called this try map here this was supposed to throw so this will throw will add throws down here and it will return and of course in our actual code we are returning the data so this is going to return data open the brackets i'm going to copy this guard statement and the return data here i'm going to paste it down here and of course we don't have this response anymore but we have this output so instead we're going to call output.response and for this data we're going to call output dot data and now in this try map we will very simply call our new function handle output and we can get rid of this parameter here and i can get rid of this try map as well and our code is now short and condense and i am loving it let's run it one more time to make sure it still works we're still getting our data and that is the whole gist of downloading with combine um so you can see here just how quick and easy this would be if you knew what you were doing you could write this code in under a minute right this is very short and efficient coding and just to take a look if you're with me in the last video i'm going to pull up side by side both methods here so i'm going to click this little plus on the right side of xcode here this add editor on the right let's go full screen for a second and while i'm clicked on this left side i'm going to open up the download with escaping and on the right side we're going to have the download with combine and i'm going to zoom out just so we can see so if you weren't with me basically in the last video we called this get posts we created a url and we had this function and download data and we didn't use any publishers here we used that we used this escaping closure which you can see here and we called the completion handler and then in the completion handler we decoded into post model and then we went on to the main queue and updated our posts and in our combine method we're doing essentially the same exact thing except this code looks so much easier to read and sleeker than this whole hunk of code right we are still using the same url we have the same url here we're going on the background thread using a data task but this is a datatask publisher first last video we used just a regular data task both the datatask publisher and the regular data test go on to the background thread and when it comes back we had to check that we had good data so we did all this extra guard data here and we did that same thing here so when we got some data back we tried to map it using our handy handle output function where basically this code and this code is very similar we're just making sure that the response was a valid response it was a good response and after we had good response we then decoded that data into an array of post model so after we had good response here we called the completion handler and then we added a json decoder to decode into an array of post model so we did that on both of these methods and then finally we called sync so that we could receive a value and update our posts and here we didn't have to call sync but we updated our posts this way and we had to jump back onto the main thread before we updated the ui and in our combine we actually didn't have to explicitly jump back on because we had already decided that we were going to receive on the main thread the main difference between the code is that this publisher has to be cancelable because technically a publisher could publish values over time so so if this was downloading something that would come from the internet and every minute or every five minutes it would publish new data this would keep running every time that it published new data because of that we need to store it as something that is cancelable so that we can cancel it at any time for our purposes though we know that this is only going to return one time so we're not really worried about canceling it in this video but regardless we have to store it in a cancelable set all right guys i am actually back in the project um while i was editing this video i realized a couple things that i wanted to point out that i didn't cover so i am back in here real quick and i just want to show you guys that if we did want to use this completion here because it does throw this error and in your app you probably want to handle those errors the best way to handle this completion is to actually use a switch statement so here we can call switch and we can switch on the completion and then we'll open the brackets and if we press case dot we can see that the completion gives us two cases it gives us a finished and a failure so for finished we will just add the colon and then if it's finished we're not going to do anything but here we'll just print finished however the more important case here is case dot failure and if it's a failure we can get that error so remember that error is going to be the error that we are throwing so here we are throwing that url error.bad server response and in your app you might add other reasons to fail for example if the data was wrong or it was different data or you couldn't convert the data for whatever reason you could add all different errors and that error is going to come out here and you can make this a variable we'll say let error and then we'll add the colon and then here we can handle those errors so for now we could just print there was an error and then we could print out that error of course if this was your real app you probably would want to show an alert or something on the screen to handle this error and the other thing i want to show you guys quick is that in some scenarios you either don't have errors or you don't really care about the errors so if we didn't care here that we got an error we actually wouldn't need the switch statement at all and we would just leave it like this as we did before but we can take it one step further and actually remove the error completely and so before this sync i can actually call dot replace error and this is a pretty handy function here so if there was an error in getting these post models instead of returning nothing in this received value and failing the completion we could instead just give it give some test data we could give it some default data or more likely you could just give it a blank array and if we use this replace error we actually don't need this part of the sync call because we don't actually have a completion that will fail so we could instead just call sync with the receive value only parameter and this here is going to be our returned array so if it's successful it would be the actual data but if not if there was an error it's going to be this array which is just a blank array and again we could call this return posts we could add in our weak self in here and we can set up our posts just like that and we can get rid of this so it's another way to do it just to replace that error if you don't want to deal with the errors this comes in handy sometimes but personally i like to throw the errors so that we can handle them and as the developer obviously if there are errors you want those printouts but anyway this is a nice little trick that does come in handy sometimes all right guys i hope you stuck with me hope you're excited about combine because this code is so sleek so smooth and if you understand this you are on your way to becoming a very expert swift ui and swift developer thank you guys for watching as always i'm nick this is swiffle thinking and in the next couple videos we are going to jump farther into combine and look at some of the really cool things we can do with these publishers hope you're excited because i am excited and i will see you in the next video
Info
Channel: Swiftful Thinking
Views: 3,070
Rating: undefined out of 5
Keywords: SwiftUI Combine, Learn Combine, Combine SwiftUI, Swift what is Combine, Swift how to use combine, Swift download with combine, SwiftUI combine publisher, SwiftUI combine download, SwiftUI combine data task publisher, How to use Combine in SwiftUI, What is combine in SwiftUI, SwiftUI how to download json, SwiftUI how to download from API, SwiftUI download JSON, SwiftUI downloading with Combine, SwiftUI async download, SwiftUI async code, AnyCancellable SwiftUI
Id: fdxFp5vU6MQ
Channel Id: undefined
Length: 34min 43sec (2083 seconds)
Published: Mon Apr 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.