Swift: Build News App (2021, Xcode 12, Swift) - iOS Development for Beginners

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's going on guys welcome back to another swift video in today's video we're going to be building out a news application that incorporates a api call you're going to actually be able to pass in the country for which you want news back we'll talk about building the ui and caching these images as well as being able to open up these stories right in your application so i will have a part 2 up as well for adding search functionality so stay tuned for that but if any of this sounds good to you make sure you start by destroying the like button down below hit subscribe if you're into ios and swift that all said let's get into the video all right we're going to begin by opening up xcode and creating a new project we're going to stick with the app template under ios and let's go ahead and give this project an app name of news app make sure your language is set to swift your lifecycle is ui kit and your interface's storyboard will work programmatically but no swift ui today go ahead and create the app and first things first we are going to expand our window and close up this right panel and then we'll also jump into the view controller i'm going to select a simulator from the list up here and maybe we'll go with the 12 pro max and first things first we want to go ahead and add a title here i'll go ahead and call it news i'm also going to set a background color here and this is going to be system back round just like that let's go ahead and give this a run in the simulator just to load up our application before we go and you know build out a api to get news and searching and all that good stuff you saw in the beginning so here is our app running the next thing we're going to do is we want to embed this in a navigation controller so we get the title up here now we can do that programmatically but it's the only thing we'll do through the storyboard for the sake of time we'll go ahead and select the controller in here in the editor we'll go to uh rather in the tool par we'll go to editor and then embed in navigation controller we can then select the navigation bar here and in the attribute inspector we can open up the prefers uh large title check box and just check it and then we can jump back to our view controller so once we have this uh set up here if we think about it at a high level what are the pieces that we need so we're going to want a table view to go ahead and show our news stories we'll want a custom cell we'll want a way to call the api and we want a way to open the news story and search for news stories so it sounds like a lot but a lot of this stuff overlaps so let's do this one by one so first things first i've got my browser opened up here the website is newsapi.org and they've got a free api so you can get a free api key and here is the first url we're going to bring in it gives you top headlines in a given country i've got us in the url already so i'm just going to copy that and we're going to create a new object in here maybe we can call it api caller and this is the object as the name implies that will be responsible for hitting our api and giving us back some data so we'll create a class in here called api caller there's going to be a private initializer since we're going to go ahead and create this as a singleton so we'll go ahead and say static static let shared api caller now what we want to go ahead and do is i'm going to define some constants in here so we can say struct constants and this is going to be a top head lines url and we can go ahead and say this is a url string and i'm just going to paste in that string that i copied for the url then we want to actually create some functions on here we can call so the first one is going to be funk get top stories and it's going to have a completion handler which gives us back a result with a array if successful of our news objects we're just going to stick string in there for now since we have not created the model yet and in here we want to basically perform an api call so the first thing we want to do is unwrap the constants dot top headline url the reason we need to bind it is because the url initializer is optional now once we've gone ahead and done that we can create a url session shared.datatask with a url and a completion handler so we'll use this one here passing the url and we've got a completion handler here so there is our data our response which we don't care about we probably want to make sure we don't have an error so we're going to say if let error equals a error we know something went wrong so in the completion we can say go ahead and say failure else if let data equals data we know we got some data back so now what we want to do is basically try to decode using a json decoder the particular piece of information from the data now we want to create a actual model first i'm just going to say string dot self we'll change this in a moment we'll also want to catch if the error does occur so we'll say failure here for the error so i know i'm going pretty quickly i will explain everything once uh we kind of get to a good good middle stopping point but once we have this task created don't forget to say task.resume now we want to create some models so i'm going to stick the models right down here and if we take a look at our response here we can see the one that we care about in the response is this articles key which points to a array of these article objects so we want to basically create a response here so i'm going to first say this is a api response which is codable it's going to have a articles key in it to make sure it's spelled correctly and it's going to be of type article and we'll create an article right below it and this article will also be codable and inside of here we're going to stick all the inner keys so if we open up one of these we can see we've got a source we've got an author there's quite a few things in here so i'll uh i'll create a source maybe we don't care about the author but we definitely want the title description and url to image so we'll say this should have a title should have a description absolutely it should so we can show something should have a url which will be a string and it should have a url to image is what i believe it was and all of these i believe we saw were strings so that's looking good we might want to grab this published at also which is a date time string so we can go ahead and grab that as well if we wanted to display that and for the source here what we want to do is we want to create another object because it's a dictionary here so we'll go ahead and say source is going to be a source so we'll say source is of type source and then down here we can say struct source is also codable and the only thing i care about in here is the name we can exclude the id and now what we're going to say is the results that we should get back that we're trying to decode is a api response so what we'll go ahead and do here is i'm going to print out results.articles.count and we'll make sure we got some articles back and if we do we know that this is all working so before we give this a run to make sure that our api call works at the bottom of view did load in our controller we can say api caller shared and there's a single function on here and we'll go ahead and give it a run so go ahead and give it a run and we expect to see a print statement in our console assuming i didn't make any typos so let's see what's going on down here looks like we don't see it so that leads me to believe we have a error so we're going to switch on the result here in the success case we should have a response we'll break in the failure case we should have a error in which case we will print the error here so we actually know what has gone wrong so go ahead and give that a run and here we can see that we have an issue index 6 inch value let's see found null instead so it looks like it's trying to find a string value let's see what uh it's for it's four articles article it's value nil so let's see what i botched in our models here something is screwed up clearly so we have articles let me make sure i spelt that right looks good to me which is a array of article objects articles which looks good now we've got a title description url url to image so let's see what else is going on in here so we've got a title description url url to image so all of this is looking good so what i'll do is i'm just going to comment ouch whoops we'll comment out some of these properties and that way we'll be able to more quickly narrow it down what is actually screwing this up so looks like we've got 20 articles now so something is screwing this up so let's uncomment all of this and we'll find out if the id is the thing that's messing all this up so it looks like it's not something else is screwing it up here so we'll go ahead and let's see these ones should be good so let's go ahead and try getting the url and url to image looks like one of those is in fact the problem so let's go ahead and try it with just a source perhaps the source is the problem alright so source isn't the problem let's check our description here maybe that is the problem and there's obviously better ways to debug this i'm being slightly lazy but let's see what's going on it's saying articles into value is nil index 5 into value is 5 for the coding key coding key string value for description so what we could actually go ahead and do is we can make this optional it looks like description could be a string or an integer per the error but it looks like if we make it optional it actually doesn't yell at us which is good enough for our example today so we'll do the same thing for these here as well we'll make these optional as well i don't think we should change publish to at but let's go ahead and make sure it's not yelling at us all right looking pretty good so now that we're getting our top headlines back in our controller we want to actually render these in a table view so that requires us to create a table view so let's go ahead and do that so go ahead and say private let table view is going to be of type ui table view and we're going to create it in the anonymous closure pattern here we're going to want to register a cell to it as well we have not created it yet but we will momentarily but for now just go ahead and just register the standard base class for the cell we want to make sure we add this as a sub of use there's our table view and we also want to go ahead and assign the delegate and data source for this table view we'll want to go ahead and conform to both protocols and i'm going to stick all the table view functions down here so it's nice and organized so we'll say number of rows by default will be zero we'll change that momentarily with view models that we want cell for row at index path and in here we want to go ahead and dq a reusable cell with a id of cell which is what we registered for the given index path and i'm just going to line break all this stuff so it's a little uh a little cleaner here we'll want to go ahead and return the cell and i'm just going to go ahead and assign its text to something random here and we're also going to want to be able to select each of these cells so we'll say did select row add index path and we'll want to deselect it as well so these are the bare bones of our table views let's see why this is yelling at me this should be deselect not delete deselect row at index path all right so that's looking good we want to make sure we give our table of view a frame so let's go ahead and override view did layout sub views we'll say the frame is view.bounds so looking pretty good there and let's see we want a custom cell like i mentioned but before we do that let's actually do that first so it'll probably help a little bit in explaining all of this so we'll create a new file here it's going to be a coco touch sub class of a ui table view cell we'll call it news table view cell go ahead and create it and start by deleting all the stuff that it gives you in here the first thing we want in here is a static identifier that we're going to use to you know just register our cell to the table we'll want to override the initializer here for the table view we'll also want to bring in the required initializer so you can go ahead and autocomplete will help you out there we'll want to lay out our sub views we'll also want to go ahead and prepare this cell for reuse by overriding the related function and finally we're going to want a way to configure this cell or each of the cells with a view model now what is this view model going to be well we're going to take this and i'm going to stick a view model right up here it's going to be a class instead of a struct since we're going to want to change some stuff on it since it's a reference type it's going to have a title it's going to have a sub title and it'll also have a image url which will be of type url optional and it'll also have some image data that we're gonna use to cache basically data after we've downloaded the image so we don't have to download it over and over again so we'll go ahead and create an initializer here for it so let me just line break all this good stuff so we have a little bit of cleaner code so we'll go ahead and do that also bring in the image url and i'll bring in the image data here all right now we want the body self.title equals title self.subtitle is subtitle self dot image url will be image url and self.imagedata will be image data you actually don't even need to assign that one since it's going to start off as nil anyways so we can actually get rid of this here and just say by default this is going to be nil which is actually the default in general you can just type it for explicit typing but it's not per se necessary so let's see we can get rid of this comma here and let's see what else this is yelling about that error will go away and down here we can say this will configure with this viewmodel now we're going to want to configure this in a moment but let's create these sub views in here so we'll go ahead and say that we want a news title label which is going to be a ui label here and we're just going to create a label in here and maybe i'll make the font size a little larger since you know it is a title in fact so we'll say label font size will be system font of size and weight maybe we'll say 24 weights we'll say maybe medium and i'm just going to go ahead and copy and paste this and the next one here will be the sub title label only thing that's different here is the weight will be regular and the size will be perhaps 18 and then we also finally want a image view here so go ahead and call this news image view this is going to be a ui image view and uh we basically don't want much in here maybe we'll set a background color just to start off so we can actually see you know where our image views frame is so we'll say background color is maybe system red pick whatever color you want really doesn't matter we also are going to assign its content mode to be scale aspect fill so the image keeps its aspect ratio but fills the image uh in his view let's go ahead and add all of these sub views to our content view so we'll say content view let's see what's going on looks like we forgot to line break correctly so content view content view add sub view sub title view man my typos today are not uh not ideal subtitle label that's what i'm looking for content view finally add sub view for our image view here which is our news image view this one should be our news title label and uh let's see so before we go ahead and continue here in the configure function we're going to say news title labels text is going to be view model view model dot title the sub title labels text is going to be view model dot description perhaps dot let's see subtitle is what we called it actually and uh what else do we want here now we also want to configure the image so we're going to say if we have uh data for the image we'll say if let data is view model dot image data we can go ahead and use that to assign the news image views image we can say this is ui image with data like that otherwise in the else here we want to actually fetch the image but before we do that since we wrote out so much code already let's go back to our controller and actually uh give this a run to see what we've got so we want to register our new cell with its identifier back in the controller here we also want to go ahead and dequeue the appropriate cell with the correct identifier we're going to cast it here to the given cell we'll make this a guard and instead of doing this here we're going to say cell dot configure and we're going to pass in a view model at the nth position now we don't have this array of view models yet so let's come up here and create it we'll say private var viewmodels as a array of news table view cell viewmodels and basically the premise is once we get our results back here we can actually go ahead and pull out view models from the articles so this should give us articles back and if we come back to our api caller we'll adjust this function in the signature to give us a array of articles back and instead of printing here we can go ahead and say completion and we can say success is results.articles back in the controller now what we want to go ahead and do is from those articles we're going to create our view models so we'll go ahead and say weak self here and we'll go ahead and say self.viewmodels viewmodels is going to be dot articles.com map we're going to convert each of these into a news table view cell view model the title will be dollar zero dot title the subtitle will be dollar zero dot description and the image url will be a url with a string which will be dollar zero that url to image and since it's optional we'll give it a default value of a empty string so description here is also optional so we'll say in a default value no description just like that and we'll also go ahead and line break all this just to make it look a little bit nicer let me move this parenthesis back up here since that's where it belongs and uh once we've got our view models created we should tell our table view to go ahead and refresh itself so we're gonna say self.table view reload data the number of rows will now be viewmodels.count and i promise now we'll go ahead and give it a run and let's see what happens so bear with me here we should be getting articles back it looks like we have our title showing but where the heck is our uh where the heck is our uh table view cells well we're actually seeing them here what's happening is we haven't actually laid out the sub views so we don't actually see them so what i'm going to go ahead and do let's see let's go ahead and go back to our table view cell and let's start giving our sub views a frame so in the uh layout sub views we're going to say the news title labels frame will be cg rect and we're going to save this as maybe five zero content view dot frame dot size width minus perhaps i don't know give it an arbitrary number we'll say maybe 120 and the height here will be contentview frame and we're going to use its size height divided by 2. we'll actually bump the x to be 10 and uh you might be wondering how i'm calculating this it's all relative positioning you could also use constraints if you so choose to but uh we're just going to stick with this for now and if we come back to our view controller we want each of these uh cells to be a little taller than the standard height so we're going to say height for row at index path and i'm going to go ahead and return maybe 150 so we end up getting a taller cell so go ahead and do that and boom we've got our headers here our headline titles i should say and what we want to then do is we want to add an image on the right hand side and we're going to add a description label right below this one here so let's go ahead and uh and do that so let's come back to our table of view cell i'm actually gonna copy and paste this so we can just do the subtitle right below it so we'll go ahead and grab that and do that and instead of having the width be minus 120 maybe i'll say minus 200 same thing down here just so we have a larger image view space the thing that i'll change here is the content views uh subtraction of the title label height so this will be the subtitle label this y is going to maybe change to be 70. we'll change the height of this guy to be 70 here and let's go ahead and add in our image views frame as well so i'm going to copy and paste this and this is going to turn into a news image view the x is pretty simple it's going to be content view dot frame size with subtracting perhaps 200 and the width and height is going to be this the width will be definitely 190 and the height is going to be the whole height of these cells so maybe the height minus 10 will give it a 5 point margin at the top and bottom so i'll make that 5. so keep in mind that we're not going to actually see the image yet because we're not downloading it down here but we should see a color so cool we're definitely seeing a color image is kind of large maybe 200 is a little aggressive you might want to tone this down a little bit maybe we can make it like 170 this could also be 170 and the width instead of being 200 or 190 we could make this 160 and this will x will be subtracting maybe 170 and the other thing i forgot to do up here is on our labels we're going to end up saying number of lines is going to be zero so it goes ahead and line wraps so go ahead and do that and give it a run once more and let's see if it's looking any better all right much better our image view is touching our label doesn't look too hot so let's go ahead and add a little spacing there so we need to change the x of the uh image so we'll say maybe subtracting 160 so there's a 10 point buffer between those elements and i think this is looking a lot better you might actually even want to do like 150 but but before we run it again let's actually go ahead and download our image so else if let we're going to make sure we have a url we'll say else if let url is view model dot url or image url i should go ahead and say if we have it we can try to go ahead and download the image from it so we'll say url session shared data task with a url and completion handler basically what we did for our api call we will validate that we don't have a error so we'll say guard let data equals data we do have data and the error is in fact nil and we'll return if such is not the case aka we didn't successfully download the image and uh if we did on the main thread we can go ahead and assign the news image views image so we can actually take the same code up here and we can drop it down here and we want to go ahead and say this is self optional so we don't cause a memory leak so we'll capture weak self there and on this whole thing go ahead and say resume now we also want to cache the data that we got back here so we can also go ahead and say self self.viewmodel self. rather instead of self.just viewmodel.imagedata will be data and the beauty here is the next time the cell comes into view it's not going to actually go ahead and download the image again so a couple issues i still see the image view is getting clipped off the edges so we are going to say this image view clips to bounds so it uh you know stays within its uh boundary and we'll also go ahead and get rid of the red background color maybe we'll make it something like system secondary or we can say secondary system background so it's like a nice light gray color and we also never implemented this prepare for reuse basically in here we just want to go ahead and nil out all of our properties that we assign between different uh cells so we'll go ahead and get rid of the image and i just realized that i spelt this incorrectly so let's go ahead and just do a quick find and replace to fix up our uh spelling there because we know how to spell on this channel so let's go ahead and give it a run once more and let's see what it looks like so look at that we've got a pretty full functioning news application now let's go ahead and hook up actually tapping on one of these articles and opening it up so let's go ahead and jump into our view controller it's pretty trivial to do this we already have a function which gets basically which view model we have selected so we can actually just pull that out here we can say index path dot row now the view model doesn't actually hold on to our urls so what we could do is we could hold on to the articles as well so we'll say self optional articles is going to equal our articles here and just like we have this array we'll go ahead and create another one for articles of type array of article objects and now down here we can come and get the given article that we you know went ahead and tapped on now from this article we're going to grab the url string so we can try to say guard let url is going to be the article dot url which is optional so we'll go ahead and give it a default string value and if we get the article we're going to use a built-in mechanism which is called a safari controller to go ahead and present the news article so we'll import safari services here and down here we're going to say let vc is sf safari view controller with this url being passed into its initializer and finally we'll say present to this vc animated true so let's go ahead and give this a run and see where we land so we're going to go ahead and hopefully see all of our news stories and this should work in both light mode and dark mode so if i put into dark mode here you can see everything is still working if i tap on this you'll see it'll open up the news article and boom there it is texas judge blocks nba or nra rather from declaring bankruptcy very interesting totally random here now this video has gotten way longer than i anticipated so what i am going to go ahead and do is i might do a part two but before i do that let's take care of the styling here so the description is a little bolder than i think would look nice so if we come back to the sub title label here let's go ahead and actually make its uh weight light and it'll actually decrease its font size even a little more and this part is you know at this point it's very subjective of how you want it to look i would even argue that the font size of 25 here is big we'll make this 22 and let's try semi-bold and let's see what that looks like because you want a little bit of spacing between everything to have your uh you know you have some room for things to breathe we can also add you know some spacing in the right side of this image view and a nice corner radius so for the imageview's width we can actually say this is uh 150 here since we are subtracting 150 we actually want 140 this will give it a 10 point buffer on the right and i'll actually also give it a nice rounded corner so i'm going to say the corner radius is perhaps you know six or seven give it whatever you want whatever looks nicest to you and make sure you say masks to balance is true so go ahead and do that and let's see what we uh what we're at so this is uh what our app is looking like i think it's looking pretty nifty we can tap into any of these and read the articles but we don't have a search functionality baked in here yet it is pretty simple to add but i think this video was fast enough so i'm gonna probably drop it here and i'll do a part two to add search so uh yeah i mean just to do a quick recap we've got a table view cell here which really is pretty verbose but all it has is a three table view cell sub views for the two labels and the image we've got a view model which uh also holds our image view data and url and we cache it once it's downloaded so it doesn't you know need to download again when i scroll the cell off screen then come back it uses the cached version we've got an api caller which is a singleton with a single url request in here a single network call to fetch top headlines in the in the us we've also got our models defined in here for our response article and source and finally we've got our view controller here as well with our table view functions here delegates and data source functions our pretty basic view to load here we can actually move this api call to its own function we can say fetch top stories and just to keep our code nice and modular so we can say fetch top stories and we'll go ahead and paste that in sort of line break at least paste that in like that uh and yeah that's basically our news app in a nutshell so it looks like we have an issue now what the heck did i break in the last two seconds all right let's try that one more time looks like a transient issue yep looks like it went away and it succeeded so yeah that's all i've got for you guys today if you haven't destroyed the like button already make sure to do so i know this video was a bit faster i expected to do this and the search stuff in one sitting which is why i was slightly rushing but uh go back and see the parts that you might be confused about leave a comment if you have any questions i'm gonna take my time with part two i probably should have taken my time more so here as well but i digress if you enjoy ios and swift subscribe to the channel i try to post daily here and you know we're growing this community together so let's grow it together and continue uh onwards and upwards so thanks again for watching i'll see you in the next one you
Info
Channel: iOS Academy
Views: 10,038
Rating: undefined out of 5
Keywords: swift build app, swift tutorial, ios tutorial, how to build an app, how to make an app, swift, swift 5, swift ios, swiftui, swift 2021, 2021 swift, swift 5 tutorial, swift beginners, swift basics, swift for beginners, swift tutorial 2021, 2021 swift tutorial, swift beginner, swift tableview, swift api, swift json, swift custom table view cell, swift news app, build app swift, swift safari, swift webview, swift table view, tableview, swift tableview 2021, ios app, ios, app
Id: V2IfBdxjWs4
Channel Id: undefined
Length: 34min 7sec (2047 seconds)
Published: Thu May 13 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.