Swift: Building Stocks App (2021 Swift) ✅ | Afraz Siddiqui | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Swift: Building Stocks App (2021 Swift) ✅

teacher avatar Afraz Siddiqui, Engineer | Designer | Teacher

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

36 Lessons (7h 8m)
    • 1. Course Overview

      2:16
    • 2. Setting Up Project

      5:35
    • 3. Removing Storyboard

      3:52
    • 4. Setting Up Managers

      12:34
    • 5. App Icon & Launch Image

      4:08
    • 6. Search Controller

      6:04
    • 7. Custom TitleView

      5:47
    • 8. Search Results Controller

      10:11
    • 9. Stocks Search API

      26:47
    • 10. Select Search Result

      5:50
    • 11. Introduction to Child Controllers

      6:25
    • 12. Create Floating Panel

      9:13
    • 13. Create News Controller

      8:11
    • 14. News Header View

      14:19
    • 15. News API Call

      12:09
    • 16. News Custom Cells

      23:12
    • 17. News ViewModels & Wire Up

      5:58
    • 18. Opening News

      4:09
    • 19. Watchlist Defaults

      13:16
    • 20. Market Data API

      20:22
    • 21. Watchlist Cell & ViewModel

      34:34
    • 22. Completing Cells

      20:28
    • 23. Swipe to Delete

      10:09
    • 24. Add to Watchlist

      6:56
    • 25. Watchlist Interaction

      5:18
    • 26. Create Stock Detail View

      18:33
    • 27. Metrics API Call

      18:28
    • 28. Metrics View

      15:26
    • 29. Create Chart View

      15:02
    • 30. Chart ViewModel

      7:26
    • 31. How Much iOS Pays

      7:28
    • 32. Documentation

      31:17
    • 33. Haptics

      5:54
    • 34. Introduction to Unit Testing

      14:55
    • 35. Optimizations

      13:44
    • 36. Thank You!

      1:36
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

69

Students

--

Project

About This Class

f0452dfb.png

Welcome to Building the Stocks App in Swift!

In this class you will learn to build a fully functional, high quality, and beautiful Stocks application for iOS with Swift 5, UIKit, and Xcode. You'll master several skills including the following:

  • Strong design skills for UI and architecture
  • Deep understanding of Swift and UIKit
  • Creating User Interfaces programmatically
  • Writing testable, clean, and documented code
  • Configuring and fetching data from remote API
  • Much More

Throughout our lessons, we will iterate on build the app together. You'll get a step by step walkthrough from Afraz, your Teacher, as to how to build each piece.

Alongside the video lessons, you can participate in the Class Project and build your own Stocks app. Share it here on Skillshare for everyone else to see! Don't forget to customize your project however you'd like to stand out and put those newly acquired skills to the test!

Let's get building.

Meet Your Teacher

Teacher Profile Image

Afraz Siddiqui

Engineer | Designer | Teacher

Teacher

Hi there, I'm Afraz!

I've been writing code, building awesome software, and designing creative projects for over 12 years. If you are interested in

iPhone or Android App Development Website Development / Design Cloud Computing Photoshop / Adobe Suite Tech In General, Just Improving Yourself

you are certainly in the right place!

I have taught hundreds of thousands of people just like you how to succeed in a variety of disciplines through actionable content, interactive feedback/help, and straightforward walk throughs. With a background in technology and entrepreneurship I have successfully navigated several complex challenges and learned a lot along the way - now it is my time to give back.

I am currently leading Software @ Microsoft and previously comp... See full profile

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Course Overview: Welcome to Building the stocks app. This is a class where you were going to build, you guessed it, a beautiful stocks application. Our app is going to be fully functional, interactive and look like the real deal once we're done with it. Now let's get into the specifics. In this class. We're going to first start with the watch list. The watch list is this awesome list here with the companies that we care about, we're going to be able to see the relevant information, the mini chart, the price change, and some more information. Well then venture into interacting with our watch list, otherwise known as deleting entries and adding entries. From there, we're going to segue into the news panel. The news panel is going to show us irrelevant articles, top stories and company-specific news that's moving the markets. We'll talk about downloading images, persisting information, opening the news in-app and so much more. After news, we're going to definitely dive into search. Because what would a stock's application B, if you couldn't search for, other companies, will talk about how to get accurate, relevant results as the user types for the optimal user experience. Then we're going to jump into the stack details UI. On this screen we're going to see these large form charts which are beautifully designed to reflect the price change with the axes and the legend. Under this, we're going to see relevance news in Add To Watch List button if appropriate, and a whole lot more. Now who am I? My name is a fries and I've been building apps for more than 10 years now. I really enjoyed building apps since you can run it and distribute your work in the App Store and show millions of people what you have built. I enjoy teaching app development just as much as I enjoy writing the code and building my own work. I'm so excited to see you in the class and I'm really excited to get started on our project, on our app. If you haven't seen the class project yet, we're going to be building this app together. We're going to walk through every components together, find any bugs together, fix them together, and at the end of the day, master all of these skills together. So thanks for being here. I'm looking forward to getting started. Let's get into it. 2. Setting Up Project: All right, Welcome to the first technical video in our course. In this part, we're gonna go ahead and create the Xcode project that we're going to be building out. So this is executed 12.5. Go ahead and downloaded and opened it up and we're going to create a brand new project here. You want to stick with the app template under iOS, and let's go ahead and title our project stocks. You wanna make sure your language here is set to Swift lifecycles, UI kits, and interface is Storyboard. Not to worry, we are going to be working programmatically, but we want to make sure we don't select Swift UI. So go ahead and continue save the project wherever you'd like. I'll toss it onto my desktop and we have some housekeeping to do before we go further. So first and foremost, we want to change our minimum iOS target here, our deployment targets. So what actually is this? This is basically the minimum version of iOS that our users are going to need to have on your device to installer app. We're gonna go with iOS 13. So that'll include everything 13 and up. The next thing we want to do is we're going to uncheck iPad. Our app is only going to be compatible with iPhone. And we also want to go ahead and uncheck both landscape options here, since we're only going to allow for a portrait. Next up, we want to store cleaning up our project structure on the left-hand side here, since we've got a bunch of files we'll start off with, but they're not really organized for us. So we're gonna be using the MVVM architecture in our application. So Model View, ViewModel. So let's go ahead and create three folders that we want. First and foremost, the first one will be models. Next step, we are going to have views. Third, we're going to want controllers. Now we're going to actually put the view models phi in the files where they are next to the views for which those view models belong. So we're not going to create a separate view model folder just for simplicity, but we definitely want these three. Now we're also going to want to more folders. One of them, I'm gonna go ahead and call Managers. And this will basically be anything to manage, anything in our app like APIs and whatnot. And then finally we want one more folder. Whoops, not a file, one more folder here. And this folder is going to be other, and you guessed it, anything that doesn't fall into these four will shove it into other. So let's go ahead and categorize this step. So AppDelegate seen delegate, definitely other candidates. Viewcontroller, we're going to toss into controllers. Now assets. I like to put this into other subjective or you put it on people or put it into views. Now we're actually going to get rid of the main storyboard and the, we're going to create our UI programmatically. But for now, we can go ahead and do is select a boat, launch into main storyboard and drop them into our views. And this is basically our project structure. Now before we move on, let's go ahead and select a simulator here, maybe the 12 Pro Max. Go ahead and hit that run button and it makes sure that your app is building and able to run in your simulator. We're just going to use the 12 Pro Max for the duration of our course and building this app up. But feel free to use your any other simulator or your own personal device as well. So here is our app. I believe my simulator is in fact in dark mode, which is why we see a black background, but it is in fact building, which is a good start. Now what else are we going to need? So in this video, before we wrap it up, I just want to stub out some files at a very high level. We'll talk about the things we're going to build. So first and foremost, ViewController as a class name is terrible because it's super generic and very vague. I'm going to actually rename this to be our watch list view controller. And it's going to represent basically the watch list for the users, stocks, anything they have in their watch list respectively. I'm also going to go ahead and rename the file here, and we're going to create a couple more files. All right, so I'm going to right-click controllers Cocoa Touch Class. And this is going to be a UI view controller subclass. And the next controller I want to create here is going to be a top stories news if you controller. Now this is going to show basically trending news top stories, not company-specific. We're not going to modify any code. Plus is create a couple of more files here. The next thing we're going to go ahead and create is going to be a search results ViewController. And that's pretty self-explanatory what it's going to do for us. And I think we want one more. And this one is going to be a stock details view controller. And this is what we're going to use to render out details about a given stock that we tap. So its graph, it's related news and all that good stuff. And right now if you actually run your app after making these changes, you're actually going to make C, you're gonna see a mistake, are going to see that your app is crashing. And that is actually expected because we renamed the ViewController file here to watch list view controller. We're going to be getting rid of the storyboard in the next videos. So if you have any issues at this point, not to worry, It's expected bear, that's all I've got for you guys in this part. Hopefully we're off to a good start. I will see you guys in the next part where we'll get rid of that ViewController and be fully programmatic. Alright, I'll see you guys in the next one. 3. Removing Storyboard: Welcome back guys. In this part we're going to be getting rid of our storyboard file. I previously mistakenly said ViewController. What I meant is our Main.storyboard. And the reason we're getting rid of it is because we're going to be building all of our user interface out programmatically. And right now, the app template actually gave us his main storyboard file because Apple things were incompetent, but we're going to learn how to build otherwise. So how did we get rid of it? It's actually pretty simple to get rid of it. You just right-click it, deletes, and then you do move to trash. Now you might be under the impression that that's all you need to do. It is not There's a few more steps. So the next thing we want to go ahead and do is jump into our info P list. Now what is this file? This file is basically a list of properties. Hence P list, property list that configures your application and it holds a variety of data. One of those pieces of data being the name of our storyboard file, which is right here, and one that I've highlighted, which is called main storyboard base name. We want to select that row and hit backspace and you'll see it go away. One more thing to remove in here, if you open up application, see in the manifest. And he started to open these drop-downs all the way to the very bottom. There is a storyboard name option here, which is also once again mean selected Backspace and it'll be deleted. Now if you go ahead and run your application, you'll notice something strange. Well, you might not notice it, but let me what's changed? What's changed something. So our main application should launch up to the watch list of view controller here. So I'm just going to come in here and set a background color to its view. Maybe we'll make it red. And when we launch our app, we should see a red background. But what you'll notice is we don't see that in fact we see nothing at all. So why is that? The reason that is, is because now that we've gotten rid of the main storyboard, we need a create or applications window and the first controller ourselves, that needs to happen in the scene delegate, particularly this first function here, which is seen will connect to session. So let's go ahead and write this out and then I'll explain it right afterwards. So first we're going to change this underscore to be a window scene. And now we want to create a window for our application. So we're going to say let window is a window with a Windows scene. And we'll conveniently past that guy in at the very bottom here we'll say self.name window is window. And in the middle here we want to actually configure the windows. So first we want to create our watch list ViewController. We're going to be wrapping it inside of a navigation controllers, will instantiate a navigation controller here and pass in the root view controller as the VC right above that we declared. And now most importantly on the window we're going to say its root view controller is the nav VC. And we're gonna say window, make key and visible. And this will basically make this the primary window and make it visible and you can see it at that point, hence the name. And at the bottom here we retain the window with this property window right here. Now if you launch your app, you'll see now you start to see the red background color as well as this title bar up here, since we nested this inside of a navigation controller. Now of course we don't want the background to be read. So let's jump into our watch list controller and let's change this to be System back round and give it a run. And now we will continue on to the next part. Should be a white background. If I hit Command Shift a go to dark mode, you can see that we definitely do see our watch list controller. Nothing too exciting going on here, just quite yet. But that said, I will see you guys in the next part. 4. Setting Up Managers: All right, welcome back guys. In this part we're going to start putting together some of our manager classes that we briefly mentioned in the first video when we set up our projects. So go ahead and jump into your project and let's open up our managers folder and start creating some files. So in our app, we are going to watch three main managers and we're going to create a new file here. And the first one, we're going to go ahead and call it API color. Now you can go ahead and call it API Manager, call it whatever you'd like. But the point is, this object is going to be responsible for, you guessed it, calling our API. So let's go ahead and actually even before we start writing some code in here, Let's go ahead and create the other to manage your files will want. So one more new file. This next one we're gonna go ahead and call Persistence Manager. And it's going to manage basically persistence in our application. So saving the user's watch list and any other caching we'd like to do. The last one here, we're gonna go ahead and create is going to be a haptics manager. And the haptics manager is going to manage basically playing haptics upon different user interactions in our application. Now let's go ahead and write a little bit of code and each of these just to get them ready for what we're going to want to do. So first up, the most important one arguably, which is our API color, which is how we're gonna get any and all of our data in our application. So we're going to create a final class, gonna go ahead and call it API color. Now we're going to want it to be a singleton so we can access it the same instance of it anywhere to our, our, our app. So we'll go ahead and create a static property. We're going to privatized the initializers. And then when does any funny business? Now let's talk about what we want in here. So generally speaking, you want to have some public functions in your manager. And these are gonna be things like gets a, get, get stock info or maybe search for stocks and so on and so forth will create those functions iteratively as we continue to build out. We're also going to want some private functions or private components and our, and our object here, which are going to be internal to this API color class. So this might be things like your endpoints, right? So what's created a Enum? And this is going to be our API endpoints. So let's say there is an API endpoint for search. We're gonna put all that in here, since nobody outside of our API color really needs to know about the endpoints are what API we're calling. I'm also going to create one more function here. And this one is going to create our URL for a, give me an end point. And you'll see why we are doing this as we progress. Basically, it'll simplify the amount of code we have to re and reduce it actually. So we're gonna say for endpoints, and we're gonna go ahead and also say query params, which is going to be a dictionary of strings and string. By default, it'll be a empty dictionary just like that. And as the name implies, this function is going to creates and returned to us a optional URL. So let's go ahead and do that. And for now we'll just go ahead and save return nil here. And we're going to want to fill this out with our different options, with our base URL and our different endpoints. But we'll get into that in a later video. The next function I'm going to put in here is a generic way to make API calls. And I'm going to write this out first and then we will explain the function. So we're gonna say private func request. And the request function is going to take in t, which will be coachable. And what we want to go ahead into here. So we're gonna say perform a request with a URL which is of type URL optional. And we're gonna say expecting T dot type. And this is going to have a completion handler. And let me sort of line breaking some of this so it's a little more legible in nice and organized. And the completion handler of any request is going to be escaping. Like so and it's going to return to us a result. And in the success case of the results we want T. Otherwise we're gonna get an error back and this whole thing returns void. Before we implement this function, Let's talk about what the heck does T businesses. So essentially we're going to want to make a variety of API calls, which are network calls to get data from the Internet, right? And all of those API calls are going to result in a couple of redundant interactions, right? So we're gonna wanna URL, we're going to try to reach out and get some data from that end points. And once we get the data, if we get it, we want to convert it to a particular type that is quotable, which is how you convert JSON into objects. And then we want to return a result. So by using this t notable thing here, which is a generic, we can actually simplify the times we have to write out that redundant code. What I mean is the following. So first we're going to want to verify that our URL is not actually nil. So we'll go ahead and do that. And if it is nil, we want to call a failure handler here. Otherwise, we're going to want to create a URL session shared task. And this is going to be a data task with a URL in the completion handler. So we'll pass in the URL. Completion will bring us back data, a response which we don't care about it in error. Now we're going to want to make sure our data is in fact not nil and our error is nil, aka nothing has gone wrong elsewhere, going to return. And down here we're going to want to try to decode our data to the given type that we are expecting, which is what we have here expecting. So we're gonna go ahead and say, let's result is going to be try to use the JSON decoder to decode expecting from the data. And if we are able to do this, what we want to go ahead and do is we want to return it back to the actual completion handler. So we'll go ahead and say completion here. We'll say success and pass in the results. And in this case, if something has gone wrong and the error was thrown, we're gonna say completion. And in here we're going to drop in a failure and pass back that error. Then most importantly, a lot of people forget to do this. Make sure you do a task dot resume, super misleading terminology because this kicks off your task. Now we went to handle a couple more edge cases. Now, if we didn't get data, but we do in fact have a error here. We went to once again called completion and say failure and pass in that error. And we also want to pass in a error here, we'll say in that valid URL. So how do we create our own custom errors? Well, similarly, it wants to be private, rather we should make it private, I should say. So we're gonna say enum and this is going to be, we'll say API error of type error. And there's going to be cases that we dropped in here. So I'm going to say in a valid URL. So now in here we can go ahead and say call the completion handler with failure. This will be an API error and there's only one case on there at the moment, which is this one here. And we'll go ahead and also toss this here into the else case. And we'll go ahead and add another case to our API error here. And we're gonna say this is a no an error. Or maybe it will say no data responded, no data received. And let's make sure, let's go ahead and actually call this something else. I don't like no data received. I'll say no data returned, which is why I was considering what's a rename this. So let's go ahead and call that here. So instead of invalid URL, in this case, no data was returned. And this is now the code to make any of our API calls. We just pass in a given URL expecting and our completion handler. And as we iterate, you guys will see this in action. It will make a lot more sense. But for now, this is our API callers, private functions. One more thing I'm going to toss in here, and I like to do it at the top. And that's going to be a struct which is going to hold it some constants for us. So constants will be things like our API key. It'll also be things like our sandbox API key. Don't worry if you don't understand API keys are what the sandbox businesses, we'll talk through it. We'll also want to have a base URL, which is going to be a string as well. And we'll fill this stuff in as we go along. But I think that's enough for our API color. Let's focus on these other ones here. So Persistence Manager, so this is going to, as the name implies, handle all of our persistence. So we're gonna go ahead and say Persistence Manager. And just like our API color, we're going to want to make this a singleton. So I'm going to add a static property called shared. And it's just going to be an instance of our Persistence Manager. We're going to privatized the initializer. And on here. Similarly, we're going to want some private functions, and we are also going to want some public functionality. So what's on the functionality? Do we really want on here? Well, we're going to want to things like add to the users watch list, removed from their watches, get their current watch list, et cetera, et cetera. So let's just stub some of those outs. So we'll go ahead and say we want the users watch list and maybe that's an array of strings. And let's make sure we spell this correctly for now, we'll go ahead and just return an empty array. We're also going to want to things in here like add to watch list. So we'll go ahead and say add to Watch List. And now we're going to want to pass in some company or symbol presumably, but for now we'll leave it empty. And we'll also go ahead and say Remove from watch list and what goes in our private. So inner private, maybe we want things like has on boarded, meaning the user has launched the app more than once and we'll go ahead and return false. Now you might be wondering, where are we actually going to save all this information? We're going to save it into user defaults. So we're gonna go ahead and create privates. Let's user defaults is going to be of type UserDefaults, and it's going to be standard user defaults. Similarly to the API color, I'm also going to toss in a constants struct here. And this constant struct is going to hold a bunch of different constants. That way if we have strings and whatnot, we don't have to worry about making brittle typos. So that's pretty much it in a nutshell, how our Persistence Manager is going to look from here on out, we're going to add more stuff to it obviously, but this is the basic skeleton. Let's go ahead and do our haptics manager and then we will wrap up. So now this is going to be once again a final class. And for those of you who aren't familiar with final, this term basically means that no other class in our project can subclass haptics manager or anything that's final for that matter. So we'll go ahead and create a haptics manager here. We're gonna privatized the initializer. And we're going to want, in this case new private functionality, but we will want some public functionality. Will also want to go ahead and import UI kits into this manager. Will just go ahead and step out one function so you guys can get a glimpse of what we're gonna do in here. We're gonna say public funk, vibrate for selection. And basically we are going to want to vibrates lightly for a selection and tap interaction in this function. Now we're going to want a, another function here later on as well. This is going to be vibrate for a type, and we'll go ahead and build this out once we get to integrating our haptics and making everything feel really, really nice and premium. So that's all I've got for the managers. We've got I did skeleton, especially for our API color where we are going to spend quite a bit of time. Let's go ahead and wrap this up here and I'll see you guys in the next part. 5. App Icon & Launch Image: What's going on, guys? Welcome to the next part in our section. In this part we're going to put together the app icon and the launch image. So I just google to the stock iOS app icon here and you can grab it pretty easily, pretty easy to find. Of course it's available in the application that you can download. The source code is available as a part of the course. You can grab it there as well. So now that we have the image, we want to convert this to an asset catalog, since that's how Xcode expects our app icon. So there are a variety of ways to generate that asset catalog is free websites to do it. But there's also this really great application in the App Store called asset catalog creator. There is a free and a paid version of this, and this video is by no means sponsor, but it's just a really great tool to make your life easier with. It's stuff that you take the image, you drag it on here, you hit under iOS, you want an app icon, and you hit this big created by n and boom, just like that, it went ahead and created this asset catalog folder here. We can go ahead and quit out of assets catalog creator. And we can simply go ahead and drag in to our Xcode project if the folder, so I'm gonna go ahead and open this up. We're going to find our exceed assets in here. So let's see. I believe we threw it under other has assets. Now notice this folder's name is the same as this one. So instead of dragging in the whole Assets folder, when I like to do here is just drag in the app icon. And actually before we do that, you'll notice we have an app icon already. So go ahead and select it and hit Backspace so it deletes it. And then boom, drag it in and you should be good to go. And we can actually delete this folder here. The other thing that I like to do is drag in the actual logo that we used to generate the image so we can use it in our launch screen. Now, you'll notice here we have a 1 x2 xn and a3x, and we don't want one X2, X3, x and all cases, we're going to open up the attribute inspector. We're going to select, I believe under scales and we're gonna go to single scale. And now iOS will use this image and scale it up and down for all the different display resolutions. So that should give us an app icons. Let's go ahead and make sure we see it will go ahead and hit the Run button, pop into our simulator. And we should see our app icon reflect here. It'll take a few seconds to build, since we just brought it a ton of images. But once it does, you'll see your app icon just like that looks pretty similar to Apple's. Actually should be identical. But now we've got to work on our launch screen because a blank screen is not doing it for me. So let's go ahead and jump into our launch storyboard, which is under theory tossed and we put it under views. All we're gonna do here is we're gonna take our app icon and we're just going to pin it in the middle of our launch screen. So I'm going to hit the plus here. Search for an image. We'll go ahead and toss it right there. We're going to open up the attributes inspector, and I'm going to search for our image, which I called logo. Go ahead and select it. And most importantly, don't forget to add constraints here. So those of you that are not familiar constraints are a way to specify rules to lay out your view. In this case, we want this to be horizontally and vertically centered in our container. And we also want to set a fixed width and height. I'm going to go ahead and do 150 by 150. Go ahead and hit Enter. And now if we go ahead and stop our application or run it once more, you should see when the Apple launches, you get your launch him Is that looks just like that. And actually, you can also go ahead and hit Command Shift a to put this guy into a dark mood and launch it once more. And you should see your launch image. It launches extremely quickly, so it's a little tough to see, it flashes there, but as we build out, I'm sure you guys will end up seeing it plenty of times. So this is the end, I believe, of this section. We've got our basic app skeleton in place. We created a bunch of files. We've got our awesome looking app icon looks super official. Now, I'll see you guys in the next part. 6. Search Controller: All right, Welcome to the next parts in our series. In this part we're gonna be putting together the search controller. And by the end of this video, we're going to have a pretty sweet search bar at the top of our UI here. So let's get into it. So we're going to want to add that search controller to the watch list. So if you guys recall, when we launch our app, what we see here is the Watch List View Controller. So how do we add a search controller? Well, the first thing we want to actually do is create a set controller. We can either do that in the global space here or we can write our own functions. So I'm going to opt to write our own function. It tends to be a little cleaner. So we're gonna go ahead and say set up search controller. And at the bottom of viewDidLoad, we're simply going to go ahead and call this function like so. And what we wanna do in here is create two things. First step, you want to create a result of ViewController, and this controller will actually render our search results. If you guys remember from a couple of videos ago, we had created a stock's result controller. Here are search results controller, I should say. We're just going to create an instance of this here. We're gonna go ahead and say this is a search results controller just like that. And the next thing we wanna do is create the actual search ViewController. And this is going to be a UIs search controller. And we're going to pass in the search results controller just like that, and we actually called it results VC. So let me go ahead and update that like so. And let's see, so now that we've got these created, what do we wanna do? We're gonna wanna go ahead and say the navigation item has a search controller and this guy will be our search VC. So go ahead and give this a run. And now you'll notice is you should see a search bar at the top of your UI. So we definitely have the search bar. We can tap on it. Enemy, we get the cancel button, anything that's expected with the search controller, you'll notice you don't actually see the results controller because we haven't actually presented it or search for anything yet. Let's hook up the way that we're gonna get whenever the user taps a key on the keyboard. So the CRT controller here actually has a property. So we're gonna say search VC. And I believe it's called something like result updater. So we're gonna say search results updater. And this is going to be self. And via this updater will be able to get every single time the user taps a key. So I'm going to add an extension here. And this is going to be a results updating. And this has a function in it called search results or update search results for CRT controller. And what we wanna do in here is we want to get the current tax that the user has typed in thus far. The way we do that is by saying guard, let query is going to be the CRT controller dot search bar dot text. And we also want to validate that our query is not empty. So we're gonna say query, we're going to trim out all the whitespaces in case the user just hit the space bar a couple times and we're going to validate that it isn't empty. And if it's not for now, what I'll go ahead and do is we're going to actually print out the query. So we can see as we type along what we're actually picking up in that function. So let's go ahead and launch our app. And I'm just going to type in I O as academy. And you can see as you continuously type, this function gets called every single time a per keystroke, which is exactly what we want. And this is how we're going to build out our search APIs. So as a user types similar to autocomplete on Google or Facebook or any of the other apps that have any decent set of search controls, how they function, where you'll get progressively more accurate results. Now, basically this implies that we're going to want to call our API here to search. And we're also going to want to do a little bit of magic to make sure we reduce the number of API calls that we make. So what do I mean by that? So presumably when we type out iOS Academy, we get one to probably like ten different function calls here. Now, our API is going to have a limit as to how many times we can make API network calls. So we don't necessarily want to make a call per keystroke. We want to somehow figure out a little more intelligently when the user has finished typing. So we're going to look at this in the next, in another video, in a video or two. But I'm going to leave myself a comments here of optimized to reduce number searches for when user stops typing. And after we actually get some search results, we also want to update results controller. So how do we actually get a reference to the results controller? We're going to go ahead and say let results VC is going to be our search controller. And off of it we have our search results controller and we're going to cast it as our search results controller that we created right up here, if you guys recall. And just like that, we should be good to go. Let's see why this is yellow and that me and results VC. Let's see what the warning here is. Immutable variables creative but never used, which makes sense. So we never use this without warning is expected, but we will actually use it once we get here. So this is a basic setup of the actual search controller. We're not going to change up the texts in here searches perfectly fine. But in the next video we'll get into building out the results part of this whole piece. So I'll see you guys there. 7. Custom TitleView: All right guys, we'll come back to the next parts. In the last part, we took a look at setting up our search controller. And before we jump into the results controller in the next video, Let's go ahead and create a custom title view up here where we can have the title for stocks left aligned. So this is the watch list controller that we are still in this file. And right below where we had said setup search controller, I'm going to call a function called setup a title view. And just like we did down here, we're going to go ahead and create private function for setting up the title view. And a minister also adding in some of these mark comments to organize our code. Before our code starts to get larger. That way we make sure to stay organized. Here we're going to have a mark and we're going to have this one be life cycle. So cool. So title view, what do we do here? What are we trying to accomplish? What we want is we want to have a stock's label on the left-hand side here. Now there are a variety of ways you can achieve this. You can have a custom navigation bar or you can use a custom title view. We're going to opt for a title view in today's video. So we'll go ahead and create a title view here. This is going to be UI view, and we're going to set a frame on this. This will be 0, 0. We want this to be viewed at frame that size dot width, so the entire width of the view. And here we want the height to basically be the height of our navigation bar. So instead of actually doing this whole verbose navigation bar dot Vue dot height business. There is a way where we can shorthand all of this and it'll come in really handy as we progressively build our application out. And the way we're gonna do that is by writing some custom extensions. Let's go ahead and open the other folder. And I'm going to create an extension file in here. So we'll say new file. It's going to be a swift file and I'm gonna go ahead and call this extensions dot swift. And we're going to start by importing UI kits up here. Now, you can basically create extensions is shorthand things. In fact, in the entirety of the series, we're going to be creating a couple of different extensions. But here we'll get our first, first taste for a couple of them. So we're going to create some framing in extensions. So we're gonna go ahead and create an extension off of UI view. And instead of saying view dot frame, that size, that width, we're just kinda verbose. What if we have a property on here that's just called a width, which basically return the verbose version of it. And similarly we can add a couple more. Actually, we can add a Heights left, right, top, and bottom. So let's go ahead and tweak these. So height is going to be the heights like so. The left here is going to be origin dot X. The rate is pretty simple, basically here we'll take the left and then we'll add the width to it. What else do we need? We need top, which is going to be frame origin Y, which is the topmost of a frame. And then finally we want bottom and similar to right, we can just take the top, add our height to it. And now if we jump back to our watch list controller, instead of doing this whole view dot frame, dot size, dot with business, we can drop the verbose, verbose part of it and just do that. And for our height here we can go ahead and say navigation controller. We wouldn't get the bars heights now because it's optional, we're going to provide a default value of a 100. And just so we can make sure we are in fact actually seeing this, I'll go ahead and set a background color of link, which is a blue style color. And I'm gonna go ahead and say the navigation items. Title view is our title view that we are creating. So let's go ahead and give our project a run and make sure we see a blue bar at the top here. All right, awesome. So we see a blue bar here sized appropriately. It's not overlapping the notch and it looks pretty good. The next thing we wanna do is drop that background color and add our label. So we'll go ahead and say label is going to be a UI label frame is going to be CG rect x will be ten, y will be 0. Now once again, the height of this, we want to match the heights of the title of you and the width. We'll go ahead and say this is titled view dots with subtracting 20, since we subtracted time for me its side. Now this label, I'm going to go ahead and give it a text of stocks. We're going to go ahead and say title view, add subview for the label. And because of this is a title, we want it to be a little larger. So maybe we'll go ahead and bump up the font size here. I'm going to go ahead and say system fonts. And we want to select the option that takes in a size. Maybe we'll try and 32 and medium as the font weight, so it should be a little bold. So let's go ahead and give it a run and see what that looks like. All right, looking pretty good. So you can bump up the font size as you see fit. I think it might be a tad bit small, but, you know, this gets a little subjective at a certain point. So play with the numbers, use whatever you think feels best to you visually. There's no really Reimer rhythm to how to do this appropriately. So here we go. We got stocks much bigger. You can actually even drop the bold aspect, but I'm going to cube it. But this is our custom title view. So looking much better, we actually know which app or in now in the next video, I believe we're going to start looking at these search results controller, which is tied to our actual search bar here. So I'll see you guys there. 8. Search Results Controller: All right guys, welcome to the next part of our section. In this part, as promised, we're going to start to look at the search results controller, which we have created and hooked up already to our search controller. But there's not a whole lot going on in here. So let's talk about what we want to do in here. So generally the premise here is when I tap into this search field and I start searching for, let's say Apple. I would get a list of suggested stocks. And when I select the stock, we would see the details about it. So that list of selected or rather relevant stocks for my search is what this controller is responsible for. You can probably infer, we're going to use a TableView or a collection view to show those results. And the watch list controller will basically provide the results controller those results. So let's go ahead and create this. Now I know we haven't hooked up our API. It, that'll be the next section or next video, I should say, where we will actually start seeing some live data. But let's go ahead and at least stub this out so we have something to work with. So search results controller, we're gonna go ahead and first and foremost, give it a background color. That is not how you spell background colors because I have a comma there. We'll go ahead and say the background color of this guy is going to be a system background. And we're going to want to override view did layout subviews, since we are going to want to layout our TableView, which will create now. So we'll go ahead and create a table view here. It's going to be of type UITableView. And we're going to create this with this anonymous closure pattern, which allows us to configure the table and return it. So here we want to register a cell. So what kind of cell do we want to register? Whenever we see a search result, it would be pretty useful if we saw a baby, a primary label of the stock symbol. So Apple's case it would be AAPL, and then underneath it it would be nice to see the name of the actual company. So it's a Apple Inc. So there's actually a cell built-in UI kit already, which allows us to use this subtitle formats. So we're gonna go ahead and jump into our views folder. I'm gonna go ahead and open this up. And I'm going to create a new file. It's going to be a Cocoa Touch Class and we're going to subclass a UITableView cell. And I'm gonna go ahead and call this a search result table view cell. Go ahead and create it. Make sure the box for a nib file is not checked. We're going to delete all this jazz and here. And the first thing we're going to want to do is drop in identifier. This is how we're going to register the cell to the table. And we actually only need to do two things in here. First up, we want to override the initializer and in super dot in this we're going to see the style here is going to be a subtitle and the reuse identifier, just go ahead and pass that in. And then you want the other initializer here as well, which is required. Otherwise it'll yell at you, which is this required init with coder. Now that we've got this created here, we can actually jump back to our search results ViewController. And here we're gonna go ahead and say table. I want to register the search results table view cell itself for that cell, that identifier. So of course now that we have this, we wanted to create a function that's going to say set up our table. So you might have seen this pattern already, but it's generally good to create these modular functions that are isolated in what they do. So instead of putting on the Table View config code in the viewDidLoad function. You want to put it in here to make it just a little cleaner and easier to reason about. So the first thing we wanna do here is add our table view to the view hierarchy. We're gonna want to say that the TableViews delegate is self. And we're also going to want to say that it's data sources self. So the data and interactions will be handled by this controller. And you see errors there because we have nots conformed to those protocols yet, which we're doing right here. And the two minimum required functions that you need for TableViews are a number of rows. I'm just gonna say 0 for now and cell for row at index path. And in here we're gonna go ahead and dequeue our cell. So it'll say TableView. We're going to say dq, a reusable cell with an identifier, which is the cell identifier that we had created. Let's make sure we spell that correctly. Identifier. That's not how we store identifier. Let's see search. This is a ViewController. That's why it's giving me issues. So we're gonna say search results TableViewCell, a dot identifier for the given index path. Just like that. And once you've got this, we want to return, the cell will say return cell. And for now I'm just going to show some dummy data so you guys can get an idea of what this is going to look like. So maybe the wall say here apple and the detail label, which is the subtitle label is going to be Apple. Ink, just like that's number of rows, maybe we'll go ahead and say 10 so we can actually see something. And we definitely want to give our table a frame here to match the entirety of the bounds. So let's go ahead and give this a build and run. And what you'll notice is if I start to type in here, this is what our search results currently look like. So right now we tap on it, we're not handling it. And we might want to change up the way this looks, the actual look and feel of the cell. Now, I'm not gonna go too far into that at the moment, but there are some things we want to handle here before we move on further. So because the search results controller is owned by the surge controller, we want to interact with the table cell, but we want to basically use a delegates to proxy back our selection. So that was confusing. That's okay. I probably think it might be, but what we wanna do here is we want to create a protocol. And I'm going to go ahead and say that there is a delegate here of type any object. And essentially, whenever we tap on his search results, we want to pass that back to our watch list controller so we can present details about it. So we're going to have a function in here which is going to be the name of our controller, will say did a select search result. And now because we don't have a object that represents a search results yet, I'm just gonna make this a string. And on this controller we're going to have a weak property of type delegates for this controller. And now what we can do is whenever the user select, so if we override did select a row at index path, we first want to unselect, unhighlight that row, but now we want to say delegate and we went out call that function and passing in the results. So in this case I'm hard-coding it, but once we had actual data hooked up, you'll see that we pass the relevant selection back. Now once we've passed it back, we want to actually present the details about the selection. So how do we handle that? So if we go back to our watch list controller where we set up our, you know, our results controller, which is right here in the setup search controller. We can now see in here the result of VC has a delegate of self. Now this delegate is a property we just added. And of course, to make use of this, we definitely want to conform to that delegates. So at the bottom here, we're gonna say extension Watch List View Controller and we want to conform to that delegate. A has a single function that we went ahead and added, which is, let's see search results ViewController did select, and here we would present stock details for a given selection. So cool, so let's see what's going on here. Looks like this is yellow anatomy, but the air just went away. Sometimes it just takes a second or two to catch up. But let's go ahead and give this a run once more. And let's talk about one last thing. So we have our search results controller as we start typing, of course is dummy data for now. But how do we actually feed in the results? Because search result API call will be made here on the watch list controller. And we even wrote a comment here to update results controller once we have actual results. So how do we do that? So we're gonna go into the search results controller. And in here we're going to add a function which is going to be public and it's going to be updates with results. And it's going to be a collection of search results in the search results types, but we don't have that yet. So I'm just going to use string here. And essentially what we're gonna do is we're gonna tell the table view to reload. And I'm also going to hang on to the results. So I'll go ahead and here we'll say self dot results is results. And up here we're going to create that array will say privates, Var results is in array of strings. Bear in mind all of these string types that I'm using. We're going to change these objects. That's just a place holder at the moment. But now we can basically call this function from our other controller. So we have a reference to result VC. So we can actually go ahead and say update with results. And here we would pass it in. So maybe we would pass it in like Google, right? Whatever the results are. And that's how the interaction between the CRT controller end results is going to work. In the next video, we're going to jump into setting up our API and making our very first API call, which is going to actually let us search for actual stocks and symbols and companies. So that's all for this one. I'll see you guys in the next part. 9. Stocks Search API: What's going on, guys, welcome back to the next parts in our section. In the last part, we spent some time talking about the search results controller. And in this part we're going to actually hook up the API foundations as well as maker very first API call to get some relevant search results instead of just having a list of apple here. So that'll said, let's jump right in. So we're going to be a working primarily in the API color for the majority of this part. And then we'll hook it up to our controller. So just to do a quick overview of what we've got going on in our API color this far. So we had created this. We've got a couple static constants here that are just empty strings. We're going to want to fill it in, in a second. We're going to have some public functions here. I'm going to get rid of these comments now that we've got some private things as well. So we've got an endpoint enum, we've got some errors. We've got this function which is responsible for creating and returning a URL. And then we've also got this generic request function, which basically performs an API call for the past in URL. And it tries to decode the response to the given model type that we pass in, and then there's a completion handler. So with this or said the first thing we want to actually do is visit our API. So the API we're going to use is phi1 hub dot io, that's phi double n hub dot io. They have a wonderful free API. You can go ahead and create a free account. And once you have an accounts, this is the dashboard you're going to get. There's of course a ton of literature about their API documentation. So once you've got an account, comes to your dashboard and we can jump right in. So the first thing you'll see here is that you have a email here. You've got your API key, and then you've also got a sandbox API key. So we're going to want to copy both of these are sandbox API key. It lets us make more calls to their service without getting rate-limited. Generally, in my experience, you can get away with using the normally PI key, but you might want to have both on hand. So I'm going to hit this Copy button for our sandbox 1. And we're gonna come up here to our constants. And I'm just going to paste it in right there. And then we'll come back here to this guy and copy our API key. And we're going to paste that in right there. So cool. So now that we've got this, the next thing you wanna do is actually make our API call. So we're going to jump to the documentation and we'll talk about how we actually go about doing this. So there's a couple of things to understand. The first thing you want to understand is that the API has a base URL. So it tells you the base URL is right here. So it's slash api slash v1. And if we continue to go down, it talks about authentication here and how we went to authenticates with either a header or a token parameter, which we'll talk about in a second. And then there are a ton of different APIs. So let's go through this one by one. So the first thing we care about today is going to be a stock lookup. So on the left here I'm going to scroll down to stock fundamentals. And there is a symbol lookup here. And if we go ahead on the ratio, we've got this URL and then just copy this base URL, and let's toss it into our constants here. So in our constants we have a base URL and I just copied HTTPS fin her bio api slash v1. Now if you take a look here after this is the actual API endpoint, which in this case is search. And you guys might recall, I already actually created this one. So in our endpoints here, we have a search case and it's a raw value as a string, we'll basically by default be Search. Now, the reason I include it like this because it's redundant, but that's basically the explanation behind that. Now that we've got those two pieces, you can see here that we need to supply a query, right? In this case it's Apple as well as our token. And this is the response we expect to get back. Now we want to build this out in a generic way where we don't have to hard code everything each time. And this is why we put together this URL function here. So the way that we're going to create a URL is as follows. We're gonna say var URL string is first and foremost going to be our base URL string. Then what we're going to want to do is append onto this our endpoint. Now, because our base URL already ends with a slash here, we don't need to add another one. We can now add simply, just say take the end points raw value, which is what we are passing in here, which is our endpoints dot-dot-dot raw-value, and stick that to the end. Now, after we've done that, we want to append on our query parameters, otherwise known as these keys and values here, such as token and then my token here, or Q and the word apple here. So how do we do this? So we know that every single API call will need to actually have that token. So we're going to add at the very end of the logic here, we're going to say add any parameters to the URL. And then here we're going to say add token. So what I'll go ahead and actually do is create a array here we'll say query items is going to be an array of URL query item, which is basically it consists of a value and a name. So down here I'm gonna go ahead and say query items. And we're going to append a single item in here, we create it with a name and a value. The name is going to be token. And in this case we're gonna say this is going to be our constants and we're going to pass in our API key. So cool now that we've done that, how do we handle a passing in a one-off query items? In other words, this particular API call requires us to pass in q for query. But let's see, we're getting some other API call data. So for example, maybe we're getting news, right? Maybe you don't need to pass a Q and a value for it. That's where the parameter comes in to play for query params. So right now we default this to a dictionary that's empty. But let's say we actually had stuff in here. What we want to go ahead and do is we're gonna say for key and value in query. And we want to go ahead and say query parameters, make sure you use a correct one and that query items accidentally dat, enumerated. And let's see if we can get away with this at c. So in this, let's actually go ahead and append to our query items, a new instance of a query item with a given key and value. So the name will be the key, value will be the value in if you want to actually be even cleaner here you can maybe call this name and value, and then they'll match up this point. We have a array created with all of our key value pairs that need to go in the URL. Now before we actually go ahead and create the URL, it actually do it right now. We'll create it with the URL string and return it. We want to convert query items to the suffix string. So basically what I want to go ahead and do here is first we're gonna say, we're gonna say query string is going to be query items. So let's see if I can find that we want to say a query items. And we want to convert this to a array strings. So we're going to first say here that from each of these elements, take the name and assign it to dollar value. And then $1 at this point basically refers to the nth element. Now value is optional, so we can go ahead and give it a default value of a empty string like that. Now let's ignore this warning is just saying I have not used it yet. Now that we've got an array, what we wanna do is we want to join each of these elements with a symbol. So we're gonna say join with an end that A-star and end. And once we have this done, but we can do is we can say URL string. We want to append the following question mark plus the query string. And if you want to be a little more fancy with this, or you can even get away with doing is shorthand this and drop it right there and get rid of those extra lines. And boom, we should have our URL put together. Now let's actually test this. So we want to be able to search for particular companies or symbol. So I'm going to have a public function here called search. And it's going to take in a variety of parameters. First one being query, which will be our actual string. Next, we want to actually have a completion handler which is going to be escaping. And we're gonna say pass back a result of some model. I'm just going to make it a string for now. We'll go ahead and talk through that in a moment. And this whole thing returns a void. Now what I want to go ahead and do is I want to create a request with a given URL. So let's just talk about the URL piece first. So I'm going to say guard, let URL is our URL function for a given endpoints. And that endpoints, all we have a, now a search and there's a query params argument that it takes that we created. And I'm simply going to come into here and say, let's just line break all this good stuff. And we're going to say there's one that parameter in here, Q of type query, which is the parameter we passed in. And now that one function of URL is going to take care of creating the entire URL for us. And we're just going to print out the actual URL here. And actually instead of doing it on a one-off basis, let's print out the URL down here and go ahead and say print what, a line break. And then in the middle here we'll go ahead and do this. So now that we've got this, how do we actually test it out? So I'm going to hit Command Shift O, which allows you to search for different files in your project. And we're going to jump into the app delegates. And when the application launches, it comes to this function here, which is application did finish launching. And we're going to try to call this function here by saying API color shared. And I'm gonna go ahead and say search for maybe Apple. And the completion here we're just going to disregard for now, go ahead and give your app a run and let's see if we get our URL printed out. Alright, so it looks like we're getting something, prints it out. So let's take a look at it. So we've got HTTPS Hub API v1. There is a query, there is a token, so it looks like it's looking pretty good. So let's come to our browser and I'm just going to go ahead and paste on in that URL. And just like that, we actually get a response. The next thing we want to actually do is perform an API call with that URL and convert the results to this response. Now to convert the results to this response, we need a relevant model. And this brings us to our very first model in our series. So we're gonna go ahead and open up our model's folder here, and we're going to create a new file. And I like to name things as descriptive as possible. So we're gonna go ahead and name this search response. Maybe we'll go ahead and call this a search response. Now there's going to be a model in here called search response and we want to make a decodable. So for those of you, unfamiliar quotable allows your JSON that you get back from the API call to be mapped to this object so long as the keys match and the value types match what is in your structure. So in this case we have a count and a results. This has integers, and this has an array of these result objects. So we're going to want to create each of these. So first we're going to have in here count type int, and we're going to have a results and notice it's not plural in the response, so we wanna make sure we keep it as such. And we're gonna come in here and we're gonna go ahead and say this is an array of search results. What the heck is search results? Well, we're going to create a right now. So we're gonna say search results is going to be coachable. And I went ahead and copied one of the elements in that results. So we can actually do, let's be lazy, let's copy this whole thing here. We can paste it on in. And if you're clever, you can hold Option and get multiple cursors and do this business. And we're going to create basically a property for each of these and make sure the types match up. So this one looks like it's a string, and this one looks like it's a string as well. And I believe they're actually all strings. So we'll go ahead and say this one is a string, two. And finally, this one is a string as well. So now your arrow should go away since everything is properly syntactically correct. And now we're going to jump back to our API color. Instead of getting an array of strings back, we're going to want to get a search response back. And now that we have this URL here, what we can do is we can perform our API call by using this generic request function. And now you guys will start to see the benefit of writing that function in a reusable manner instead of using this whole guard let business here, but we can actually do is shorthanded even more. So I'm gonna go ahead and say we want to perform a request. And the first parameter this takes in is our URL, which is created by that function, is expecting a search response dot self to come back. And here is our completion handler. Now we could actually implement this here, but because the type of our completion handler will match this guy, we can simply go ahead and just pass in completion like that. And this is the entirety of performing an API call. So it takes away the heavy lifting this pattern and puts it into the URL function and this request function. So you don't have to write this URL session task over and over again because frankly it's unnecessary and it's kind of annoying. So let's go ahead and let's call this function once more in our AppDelegate, which I think we have that code already. And let's make sure we're actually getting our data back. So let's go in here. We'll stop our application. We'll give it a run once more. And let's see if we get in that data back. We're actually not printing it. So let's actually come in here and switch on the results. I'm going to say in the success case, Let's see looking at cause this results. We're going to say in the success case we should have a results or let's call it response rather. And I'm going to go ahead and print out the response dot result I think is an option off of its re, see response dots. I will say we're getting an array of those back. So let's see what we wanna do. In this case we have failures. Take care of this easy stuff first. We're going to print an error here and let me actually just go ahead and print out the whole response. So let's see what's going on because something looks a little weird here. So we'll go ahead and say print out the response, drop, that trailing period. And I suspect we're going to get an error. Maybe. And we'll see why that is yet. So we definitely got a error here. Let's see what's going on. So it's saying we're not able to get a proper decoded response. So let's see why that's happening. So cool. So now that we've consolidated how our API looks, this is saying we expect a search result back, where in fact we actually want a search response back. So we're gonna say search response because the response is a thing that contained in array of results. So just be careful with your naming there you guys saw my own slip up. Let's try that one more time. And now this response should have a result object which will be an array of multiple results. So it's a mouthful. Let's go ahead and give it a run. Let's say we have an error somewhere. Let's see what's going on. I'll write this is completion. And let's see what's happening here. So this one should also be search response. Otherwise it's going to yell at you that the types don't match. Go ahead and give it a run and let's see hopefully our list of results here. So boom, there we have, there's a whole long list of results and these are our actual models now that we can feed into our search results controller instead of hard-coding everything to be Apple. So let's see, that's a pretty good nutshell. In a nutshell overview of the API color. Let's go drop that from the actual AppDelegate. What I'm gonna do here is we're going to delete this. And for testing purposes, I'm going to create a function called debug. And in this debug function, we're going to maybe test out our API calls as we build alone. So go ahead and do that. These comments are bugging me, so we're going to delete them. And let's actually hook up our API to our search results. So we want to do that in the watch list controller. So in the watch list controller, we have this function here where we have actually said we want to first make this API call. So we're gonna say API color shared, and we wanna go ahead and search for the given query. And this is going to give us a result back. And we want to switch on the result because it could be a successful results with a response, or it could be a failure with an error. If we do get a failure, I'd like to print it out. And if we get a success, we want to update the results controller with the appropriate results. So here I'm going to say prince with our other up-to-date with a response dot result, which is an array of results types. Now you're gonna see an error here and that's expected because we originally had said that it wants a string. Now before I fix it, One thing we're gonna do here is we are going to go ahead and say do this thing on the main thread, because any UI update needs to be on the main thread. And the next thing we wanna do is actually update our search results types. So this update is going to take in is search results. And we want an array here to also be an array of search results. And down here we can actually say show a number. The number of rows to show should be our results dot count. And for the given cell, we're also going to say we get the irrelevant results, which is going to be from the results collection, the nth element. And instead of hard-coding, Apple will save results singular dot, and there should be a symbol off of here. So let's see what this gives us. This text should be a search item. So let's see, this is a collection. Let's actually give it a better name. Let's call it a model so it doesn't conflict in the naming here. So here we'll go ahead and say model, display symbol and here model.fit description. So cool. And then once we select actually a search result, we're going to get the model out again, and we want to pass it back via this delegate here. So make sure you come up here and also update this protocol to pass back a search results. Now if you go ahead and build, you're going to see you still have an error or two. That's because this guy needs to also be updated to be a search results. And I'm going to print out here, did select, and we're just going to print out which result was selected. So I'll say search results, which should be lowercased data, display symbol. So whole lot of edits there, but everything should be working. Now we don't have this optimization quite yet, but let's go ahead and give this a run. And let's see if we're a business. So I want to search for maybe Google or Microsoft search for any company, maybe we'll search for Facebook. So you'll see here as I start typing, we start seeing all of these results here. So there we have Facebook, we've got the stock symbol as well as the longer description. Now when I select one of these, you'll see we get the result printed out. But there's also one more weird thing going on here. The weird thing is we just need a ton of API calls. That's not good because we're basically pounding the API every single time the user presses a key on their keyboard. So how did we do this optimization piece? It's actually pretty simple and pretty clever. I think so At least what we're gonna do is we're going to leverage a timer. And we're going to say once the user presses a key and comes to this function, send that API call in, maybe like 2.5th. And if the user taps another key, reset that timer. So basically if someone's typing in a long name, but we're going to reduce the number of calls that we make and it's really, really easy to set up. So the first thing we want to actually do here, and we're going to declare a timer. So we'll call this a search timer of type timer. And what we want to go ahead and do down here. Let me go ahead and cut this whole thing. I'm going to go ahead and say the timer is going to be not the title, the search time or I should say, is going to be a timer. And we are going to schedule it with a time interval. And let's see what we actually want to do here. So we're gonna say execute after maybe 1 third of a second. Is it going to repeat? No, it's not. And the block is basically going to be where we actually make this API call. So paste everything in there. And now every time this function is called, we wants to invalidate the timer. So reset timer here, kick off a new timer. So what this lets us do basically is if the user is typing quickly, we're not going to make an API call if the amount of time between every keystroke is 0.3 of a second or less. And this will dramatically reduce the number of calls are actually making and it won't destroy your rate limit. So go ahead and give it a run, and let's see how many URL prints we get down here. So maybe I search for Google here. You can see here we actually only called the API one time. And it's because the mechanism that we have in place for the timer new to reset itself, It's we'd every character and it only called once the entire Google word was spelt out. Now obviously if you're a slow typer, it's going to be a little different. So if I clear this out here, if I go ahead and search for apple, you'll notice me there. If I search for a slowly rather I should say, you'll notice that we make multiple calls. If I do a a PAL, you'll see for each one we have a call. But the point is, this very simple little tweak here does improve your overall number of calls. So two more things that I quickly like to touch on before wrapping up this part. What happens if our user types in a space in the search, search here? So let's go ahead and type in maybe the Boeing Company. You'll see we don't have any results. What the heck? So first of all, we probably don't have results because the Boeing Company is not the whole name of it. But the larger issue under the hood here is we're not accounting for spaces. What we want to actually go ahead and X2 is we want to create a safe query, which is going to basically say query. And we want to add percent escaping with particular title. We're going to say URL query allowed. So what this is basically going to do is it's going to add escaping characters for anything like a space or any character that's invalid for a query, we want to use that here instead of just the standard query. Otherwise we run the risk of malformed URLs, which is not good. You're not going to actually get a response back. So that's how we take care of that. The last thing that I'd like to talk about is in the search results controller. So generally what we're going to see in our app is the watch list is going to appear here with our symbols and prices and graphs. And when we click on Search, we don't want the search controller to overlap it. In other words, we want the TableView in the search results controller to be hidden unless there are results. So I'm going to jump into search results. And where you're going to say this TableView is hidden equals true. And we're only going to unhide or show the TableView in this update function if our results aren't empty. So here I'm gonna go ahead and say our TableView, dots is hidden, is going to be results that is empty. So if this is empty, table is hidden. If it's not empty, the table will be shown. So pretty simple. The last thing we're going to go ahead and do. The actual last thing I promise, is in our watch list, in the failure case here, all we're doing is printing out our error. We probably also want to reset our results to take in a empty collection of results to show the user basically their search yielded and no actual response coming back, fix that typo there and we should be good to go. So let's go ahead and give it one last run. Make sure our APIs, our API calls were actually gone through. And then we'll continue along with the next part. So all right, so here I'm going to search for Microsoft and you can notice was pretty cool. Actually, I didn't talk about this, but this search endpoint allows you to search for company names or symbols or anything. So it's not just limited just to the stock symbols. So now that we've actually selected a item here, we've selected Microsoft for printing it out here, but we actually want to do here, and we'll maybe do the next video and a couple of videos we actually want to present this are presented details about this particular company, which is Microsoft. So that's all I've got for this part. We did a lot. We set up our foundation for all of our API calls to come. I will catch you guys in the next part. 10. Select Search Result: What's going on, guys? Welcome to the last part of this section. In this part, I wanted to talk a little bit more about this result protocol delegate that we very quickly glossed over in the last video. So we do have a setup already, but I definitely wanted to talk about it a little more sense, it's pretty important and a pretty critical pattern in iOS. So what did we actually do here? So we have our results controller and this watch list. Now there's watch, this controller actually goes and performs this API call with our query that we have typed in. And if and when it gets results and updates the search results controller with empty results or are given results here. The problem now that arises in the results controller is when the user selects one of the rows that we see in the UI, we want to present a controller. But the issue was this results controller is not the current controller on the UI such that the controller that needs to present any other UI needs to be the original one, which is in this case the watch list. So this begs the question of, okay, we tapped on a row in this controller. We want to tell this watch list controller what did we tap on and then that controller will respectively handle what to do. This is where we enter in a delegate. So the concept of a delegate, it's nothing more than a protocol, some contract, the interface that we have an instance of, in this case it's called delegates common naming pattern. And we have a function here that basically says Search Results View Controller. It did select the given search results. We basically tell whoever our delegate is at this point in time. Hey, I just went ahead and received a selection of this search results, whether it's by user input or otherwise. So all we do here in the table view function as we say, Hey delegate, we just selected this model. Now notice it's a delicate question mark, aka optional, aka might be nil. So if we come back to our watch list controller and go all the way up to where we configured our results controller. You see here before we actually pass it on into our search controller, we say results VC delegate itself. So what we're saying is that controller's delegate will be myself in this case, we're watching this controller. So whenever we call that delegate function, we end up in here where we have conformed to the search results view controller delegate protocol, and we have its function implemented. Now we're just presenting rather printing, I should say, the symbol. But what we actually want to go ahead and do is we would want to create a detail view controller. So I'm gonna go ahead and create a detail view controller. And from here we can actually go about presenting it. Now let me also wrap it inside of a navigation view controller. And we're going to say the root controller is Vc. I'm gonna go ahead and say that VCs title is going to be model rather search results is what we called it, the inbound parameter description. And then finally, we're gonna go ahead and say presents the navigation controller with an animation, which is true. Now we haven't built out this detail controller, but that's besides the point at the moment. Let's go ahead and give it a run. And let's see what this actually looks like in practice. All right, so I'm going to search for maybe Alpha bad software stuff that correctly, which is what Google trades under. So there is alphabet and we see the first one Goog and I click on it and we get our detail controller presented. Now it looks a little funky because we don't have a background color. But if I go back and dismiss it, we're back at our search results. Now, one other thing we wanna do aside from adding the color there is we went to dismiss the keyboard when we tap on one of the results. So now that we're in the search, rather the watch list controller, we have access to that particular search bars. So we're going to see navigation item. We're gonna go to search controller, grab its search bar and we're gonna say resign first responder, since we now have access to it and that all dismissed a keyboard. Let me jump into this stock detail controller and just set a background color red here. And let's go ahead and do that. We'll set this up right up here. We'll say view dot background color. And this is going to be a system back round and just like that. Now what we end up creating this more in detail in the later sections, we're going to want to pass in the symbol, the company name, and optionally any chart data we may have. So we're not going to do that just quite yet since we've got a lot of other stuff to go through first. But let's go ahead and give this a run and let's see if we see the keyboard getting dismissed and the details controller being presented. So let's go ahead and search for, search for snap, because everyone loves Snapchat. Let's go ahead and open it up and boom, we get snapping ink. The a is for Class a shares. That's what it actually trades under. And if we dismiss this, we actually don't know the keyboard anymore either. So looking pretty good. So that's all I got for this part. Wanted to make sure that delegate protocol we're nice and clear for everybody. Let me know if anyone has any questions. Very critical pattern in iOS. And we're going to leverage this as we progress in the next sections and parts. So that's it for this video and the section. In the next section, we're going to start building that news floating panel that everyone knows and loves. And that I think looks pretty darn good too. So I will see you guys there. That next part. 11. Introduction to Child Controllers: What's going on, guys? Welcome to Part 1 of the news section. In this section we're going to build out the floating panel and use UI component that you see at the bottom of the stocks app. That's pretty cool-looking and also pretty versatile and usability. In this video in particular, I wanted to do an introduction to child view controllers. It's a concept that's used pretty commonly when you start to deal with larger application where professional projects. It helps with modularity of your design. And it's pretty easy in terms of a concept, but a lot of people just don't explain it. So let's jump right in. I'm going to open up my controllers folder and we're going to jump into the watch list view controller. Now, we're going to be using a third-party dependency for the floating panel. But not because we don't know how to build it ourselves, but because we don't want to redundantly write our own code, and it actually has a lot of like polishes that would just take us 30, 40 videos to do. But I do want to at least cover how you would build it from scratch. So let's create a function called set up child. And let's talk about what a tiled controller is and why is it useful? So if you think about a floating panel, whether it's in the news app or, you know, the stocks app or apples on Maps app. What it's basically doing is it's showing a view hovering over this view and is controlled by a different controller. So let's, let's do an example and I think it'll be easier to understand. So we're gonna create a new file here. And it's going to be a Cocoa Touch Class. And maybe you'll go ahead and call it a panel view controller. Go ahead and create it and will save in the default location. And the first thing we're going to want to do in here is we're going to go ahead and simply set a background color. So I'll go ahead and say the background color maybe is a system of blue color. Now, how do we get this controller show up in the line on top of this watch list controller without presenting it. This is where we get into child's controllers. So in this function here, I'm going to create an instance of this panel controller. And I am going to grab its view. And before I actually do that, I'm going to say Add a child. We're going to pass in the VC. We're adding a child to this controller which is watch list. We're gonna say VC, did it move to parent, which is self. And in the middle here, all I'm gonna say is Vue add sub view, VC data view. So go ahead and give that a run and let's see what it actually manifests too. Well, you'll notice is we don't actually see our watch this controller now. So what the heck is going on? Basically, the blue panel controller is now a child of this watch list, but we need to set its frame. So let's go ahead and do that. We're going to say VC dots rather VC dot view dot frame is CG rect. Now I'm not going to mess with the width. It'll still be Vue dot width. This will still be Vue dot heights and the x will be 0. But the y, we're going to say view dot height divided by two. And if we go ahead and give that a run, now you'll start to see that this is starting to look more like a floating panel. Now, we don't have any content in here, but the way you would build this out is let's actually make this a secondary system background. Whoops, that's not what we want. We want a secondary system, a background like so. And let's go ahead and add in a grabber view is what it's called. So I'll call a grabber view, kind of a strange name for a view, but you guys will get why it's called that in a moment. We'll make its background color, the label color. And we'll say view that, add subview grabber view me, give this a frame as well. This will be 0, maybe it will make this 0 a 100 and maybe 10. And essentially what we wanna do here is we want to center the sky. So we're gonna say CG points, x is going to be Vue dot center dot x and y is simply going to be maybe five. So we'll go ahead and give this a run. And now you'll see that little white bar hopefully in the middle of our panel here, just like that. And you can presumably grab it and drag. Now how would the drag functionality work? The drag functionality, you would use something like a UI swipe gesture or a pan gesture. But the thing that I'd like us to continue to focus on here is the fact that we've added this panel controller as a child and it's view as a child to the watch list. So they're managed by different objects. But visually, you one would think that it's a part of the same screen, that same view, which because it visually is right. But the important piece, the takeaway here is that the panel controller is completely independent of the particular parent that it's a part of here. So that's the premise of how this panel works. Now there's a couple of different ways you can continue to build this out. You can use a pan gesture, you can use a custom presentation controller. And it's particularly straightforward, however, polishing out the, you know, the niceties. So let's say if you add a TableView in here and you wanted to have it pull down the panel as you scroll or you want a different positions like halfway 1 third full. You gotta build all that out separately. And now that you guys have hopefully a solid understanding of how this works, these panel and our child controller components, we're going to bring in in either the next are the following video, a floating panel, which uses the exact same mechanism under the hood. And we're going to leverage of floating panel from there because we don't want to redundantly write code, but we definitely do wants to understand the code that we are writing. So I'm gonna go ahead and delete that. Controller will delete this file here as well, and we'll delete this setup child's here. So that is a ChildController in a nutshell. Hopefully that all made sense. Are you guys in the next part? 12. Create Floating Panel: What's going on, guys, welcome to the next parts in the news section. In the last part, we did a quick recap or intro, I should say, of how ChildController is work. And in this part we're actually going to be bringing in the floating panel I had previously mentioned now that we understand the premise of child controllers. So the first thing we're going to want to go ahead and do here is actually close up Xcode and I'm going to open up a terminal here. We wants to cd into our project and we're gonna do a pod init. This initializes Cocoapods, which is a mechanism to bring in dependencies into our project. If you're not familiar, I'm going to toss a link down below how to install this onto your Mac. It's very straightforward and there's not a whole lot to it. Once you've got CocoaPods initialized, you have a new pod file. And now that you can go ahead and open up. And in here we're going to bring in a dependency and it's super creatively called floating panel. I believe it is singular. Go ahead and make sure you lowercase the P, Otherwise you'll see an error. And in here we can go ahead and run a pod install. And once you run it, you should see the dependency floating panel successfully installed. And now you can close up your terminal. We can go ahead and open up our project here. And we can go ahead and jump into the XY workspace. Make sure you open up the workspace. If you open up just the execute proj, you're going to run into a whole lot of errors. So let's go ahead and expand our executed when do here. First things. First, let me go ahead and try to run this in our simulator to make sure that nothing just broke as a result of bringing in that dependency. We're sticking with the 12 Pro Max. Go ahead and give that a run the first time it builds after a dependency. It could be a little slow. It looks like it was not for me, which is great. I'll take it and let's go ahead and create this floating panel. So we're going to jump into Watch List View Controller at the bottom here I'm going to say set up floating panel. And we're going to create this function right here. I'll say private func setup floating, floating panel. And let's talk about what we wanna do and how we want to do it. So I'm going to have a global instance here. And there's global instance is going to be of type panel and rather called panel of type floating panel view controller, I believe is what it's called. The reason it will not autocomplete is because we wanna make sure to import floating panel, the dependency we just brought in. Let's make sure we get the correct one here it is a floating panel controller. And now we need to actually create this floating panel controller. So we can create a here we're going to say a panel is going to be, and that's not how you start. Panel is going to be a floating panel container. Let's see. Let's try that again. Floating panel controller, not containers, what I'm looking for. And we're just going to create this like so, right? We don't need anything in the initializer. We're going to create it like that. And the first thing we're gonna wanna do here is simply say are the last thing. We're going to have stuff in between here is we're gonna say add panel to self. Now you can notice rather to parent, which is self. And they'll notice this is similar to how we looked at our child controllers. Now before I further continue, let me go ahead and assign a surface view background color. So we're gonna go ahead and make this a secondary system background. And let's just give it a run and see what that looks like. This add panel to parents should look somewhat familiar from the ChildController video we just went through. And similar to what we had, this is the floating panel at, but what's nice is they've got the gestures baked in already so we can expand it to full screen, halfway. And then what they call the tip, where just the bottom is showing. It's looking pretty darn good. So we do need to customize a couple of things here. So we'll watch to actually pass in the controller that will supply the content here. So on this panel there is a variety of functions and properties you can sets. So there's toolbar items you can set editing, you can set the content which is not popping up here. So I'm just going to type it out. Contents view controller and we're going to create it up here. So I'm going to say, let VC is going to be our top stories ViewController. And for those of you who might have forgotten, we had created this and one of our very first videos here. And there is absolutely nothing in here, and we're going to build this out later on, so we're going to keep it that way. And now that we've got this setup here, the other thing that I'd like to do is when this panel gets all the way to the top, I want the title for stocks to go away because it doesn't look super nice. And that's kinda what happens when you go to the normal stocks app. You can maybe swap this out for a different looking view with an animation. But how do we figure out these different events on this panel? So the panel actually has a delegate, which you guys might have seen it when I created this here, you can actually pass in the delegate to directly into here as well. Either or are perfectly fine. We'll do it this way. So we're going to want to add an extension to our watch list of ViewController, which will be the delegate here. And all the functions are optional, but the one that we care about is did move to a particular state. So let's see floating panel. Did it move? And let's see if there isn't one with a given state. So there's We'll begin did change state is actually what I'm looking for. And we're going to say that the title view or the navigation, I should say item dot title of view is hidden, is going to equal whether the floating panel controller dot States is equal to, let's see, I believe what they call it is full. So if the state is full, we're going to set the title view hit into true. Otherwise it will be false. So if you go ahead and give that a run, what you'll start to notice now is the panels starts off in this half position and I get up here and boom, or title goes away. Get back to half, comes back, get back to the very edge, comes, stays back as well, stays in the visible position. So that's how we can leverage this floating panel delegate. Now there are a ton of functions off of the floating panel delegate where you can really use it to customize the look and feel of everything. Mostly the defaults work for 99.9% of use cases. But just, just to let you guys know this stuff is available to you. The last thing we'll do here, even though we're not going to implement it too far, we are going to use a table view to implement our news. So we're going to create this TableView here. And the reason I'm creating it now is because we wanted to say in our floating panel where we create it, see if I can find it. In our floating panel creation. We want to say go ahead and track the VC dot table view. And we're gonna wants and make it public actually so we could access it. And we're tracking actually means is when the table view has actually gone ahead and scroll all the way to the top. When we further scroll down on it, we don't want the TableView to bounce in the normal balance interaction. What we want to see happen is we want the table view or the panel rather to swipe down. So it's a lot easier to see when there's actually content in the table view here. So we can go ahead and take a look at that thereafter. One thing I just noticed here, which is kinda strange as this panel is behind the search bar. And presumably we can actually put this title view configuration after the panel. And hopefully the bar will be behind the particular petal. But if it's not, that's okay. We'll go ahead and fix up the bouncing on this. There's a couple of parameters that you can configure on this floating panel. So I'll just click into it so everybody can take a quick peek. So there are different content moves or static, There's fits to bounce, there's a delegate here. A SurfaceView backdrop view is basically the, you know, what's behind the panel itself. And then there is the pan gesture. There is that pan gesture I was talking about the state is, you know, how how are the state of the panel looks a half or full or tip. There's a layout behavior. You can create a totally custom behaviors here if you want to, et cetera, et cetera. There's actually a pretty long list, so not going to go through all of this right now, but you guys hopefully get the points. So yeah, we've got a floating panel now and this is our foundation to start to set up our news as well as hookup then News API. So that's all I've got in this video. I'll catch you guys in the next one. 13. Create News Controller: What's going on, guys, welcome to the next part in the news section. In the last part, we brought in our floating panel dependency and started to actually see our panel here in our simulator. And this part, we're going to start to build out the news controller that's going to represent the content. And here, it's basically built that it's foundation so that also, Let's jump right in. So we created a top stories ViewController news view controller. And instead of calling a top stories, which will make this be a little isolated in terms of what the functionality can do. Let's rename this to just be a news ViewController, which will allow us to use this component and the reusable fashion should we choose to extend our apple later on? Always good to make your components as reusable as possible. So cool Now that we have a news ViewController, let's talk about what we want to accomplish it here. Basically, we're going to have a table view that is going to render out stories for us. We're going to want to fetch actual news, and we want this controller to be configurable to either fetch top stories or we're going to want it to be configurable to fetch information and news about a particular company, provided that we pass in accompany symbol may be so for Apple that would be AAPL. So it's quite a bit of things we need to do. So let's jump right in. So we had created this table view here as a simple table view. I'm gonna go ahead and create it within an anonymous closure because we're going to want to configure a couple of things on this guy. Namely, we're going to want to register cells and we're also going to want to register a cell, I should say, and a header view. So here we've got a table, we're gonna say set up at the table and we're going to say Fetch and news. So we want to create both of these functions and we're going to want to lay out sat at a table somewhere to go ahead and override this guy. This is going to be Vue dot bounds to make it the entirety of the size. And in terms of the functions, we're just going to declare these like so, that's our first one. Here is our next one. Now we're also going to want to go ahead and open up different news stories within our app rates. So what we call a Safari view controller that's inside your absolute wants a function for that. So we'll say private func, open URL, which will take in a URL, and then we'll want to do stuff in there as well. So these are kind of the basics. Now how do we make this controller configurable? And what the heck does that mean? Basically, we want to have a enum on here which is going to specify what type of controller we are creating is a top stories or is it for a given company? Now you'll notice that I used these backticks to create this here. And the reason we need to do that is because the word type is a keyword in Swift with a capital T. So if you want to use the term type as a name for an enum or an object. You gotta use these backticks, which is what I hope they're called. That's the key next to year one on the left of it. And the two cases we're going to support are going to be top stories. And the other one is going to be for a given company where the company would provide a rather the color would provide a company symbol. Now we're also given a wants to show a title in this controller. And the title we're gonna derive from the particular case we're looking at. So we're gonna say, if the current case is top stories, I'm going to go ahead and return the title for top stories. Pretty simple. And in the company case, we have this symbol as a associated values. So we're going to return symbol dot uppercased. So this is how we're going to denote are noted, I should say, the different type that's available. Now we went to also forced a controller to be instantiated with a given type. Someone has said this takes in a type brightness is self.age equals type. And of course up here we want to have a instance member for the given type. We'll say type is of type, type, which is super confusing type of type type. But hopefully that this year you guys get the points. And here we want to make sure we don't forget to say super in it's nil and nil will also wanted the required initializer will say fatal error. And let's start to add in some of our mark comments since we're getting a little verbose in our code and we want to keep things nice and organized. These are initializers here. And down here we've got some private functions. Now our TableView setup function here we're going to want to do a couple of cookie cutter things, aka add it as a subview. Set the delegate to self, set the data source to self as well. And you guys know the drill. We want to conform to the delegate and datasource protocols. So I'm going to do it in an extension down here to keep things nice and organized and clean. We'll say TableView delegates. And we also want our trusty data source. Now we're going to say number rows. And here we're going to return 0 for now. We're also going to one cell for row at index path. And I'm just going to return a actual cell right now we're going to hook this up appropriately later on. What else are we going to want in here? We're also going to want a way to specify the height for row and the height we're going to presumably use off the top my head for each of these cells is 140. You can change these as you see fit will also want a way to select a given news article and you story to presumably open it. So we're gonna say de-selected with an animation. And let's see what else we want. We're going to want to have a header. So in the actual news table view, we want to have a header up here that says Top Stories. Is it for Apple? What are we seeing news for? So we are also going to want to more functions here. Let me put it right here. First one is going to be a height for header as a believe it I'm looking for here. And I'm going to return perhaps 70. I'm arbitrarily making up numbers, we'll adjust as needed. And the most important one with the header is the actual view for the header. Because what is a header without an actual header view? And in here we're going to want to create and return that header. For now I'll return nil because we'll set this up later on. So let's go ahead and give this a run. They'll hopefully we shouldn't be crushing. Let's double check that we aren't. So go ahead and give it a run. Looks like we cannot build, which is good because that means that we need to actually pass in a type here. So in our floating panel, we're going to say that we're creating this controller for not stop stories. Top stories, if I can start making typos or we go top stories, go ahead and give it a run. Hopefully everything is so building. We expect to still see an empty panel but hopefully know crashing. All right, here's one thing that we want to fix right off the bat. We see our TableView there. It's got black as a background, aka the system background. We don't want to use that. We're going to use a clear color actually because we want the panel color to bleed through. So we'll say table dot background color is clear Just like that. And we're going to have the cells not have a background color as well. So let's see. All right, looking pretty good, so we don't have a background color there. It does look like our panel here is a little lighter, so we'll we'll make sure to adjust as needed. But for now, looking pretty good, we're in good shape to progress with building out our news API and plumbing some data in here. So that's all I've got for this part. Things are sticking around. We're come in, coming along pretty nicely. I'll see you guys in the next part. 14. News Header View: Welcome back everyone. In this part we're going to continue to work on our news section, particularly, we're going to talk about the header that I had mentioned that we're going to show here at the top of our news table view. So in our header, we want to be able to show the title for whatever context we're looking at, top stories or otherwise. And later on or we talk about building the stock details screen. We're also going to reuse this component and we optionally want to show a add to watch list. But in here, if the stock we're viewing is not a part of the users watch list already. So that all said, let's build this out. Not a whole lot to it, but we'll dive into it anyways. So let's get started. The first thing we wanna do is create an actual view in here. I'm gonna go ahead and create it right here we'll say new file. It's going to be a Cocoa Touch class. It's going to be a subclass of the UI table header footer view. So let's see if I can find it. There we are. And we're going to call this a news header view. Try to name things as descriptive as you possibly can. Go ahead and create it and started by deleting this unnecessary commented code. The first thing we want in here is going to be an identifier. This is what we are going to use to actually register this particular header. We can also put a preferred height in here, which is going to be the heights that we'll use for the header, will say 70. We hard coded this in the table in the previous video, but we'll start to use this since this is going to be a reusable component. Now, inside of every view, we're going to create a view model as promised. And there's ViewModel will help us configure our particular view. So in this case we want a title. And then we also want should it show Add button, which is going to be a Boolean? And now let's talk about actually building out the rest of this particular view. So we first and foremost in here, once you always override the initializer, so we'll say emits, we're going to say in knits with a frame, if I can find it, Let's see. And it was a reuse identifier is actually what I'm looking for. So we're gonna say inits, we're going to pass the sin for the reuse identifier. Make sure you bring in the required initializer. See if we can find it that required with a coder, that one right there, decide There we go. We're going to want to lay out our subviews. So 99% of times you'll want this. And some of us have a prepare for reuse if the view is intended to be reused, generally TableView cells and other header is get reused. So now that we have this ViewModel thing here, we want to have a function on here so others can configure this view with sad ViewModel. So here we're gonna say public funk configure. And I'm going to go ahead and say configure with a view model of type ViewModel. Keep in mind this is local scope, so it'll always be this guy right here. Now, what do we actually want to show inside of this particular view? We want two things. We want to have a label which will serve as the title, of course, in the header. And the old thing we're going to wind is a button. So before we get to the end, Let's create this label here. We're going to want to probably increase the font size on it. You can play around with the sizing and the weights and all that good stuff. Maybe we'll try 32 here and see how we like it. And let's see. The next thing we're going to want is a button. And this button by default, is going to be headed and we're only going to show it if our view model tells us that we want to show it. Now, I'm going to give this a title and the title is going to be a plus sign and watch list. So basically this button is going to add the given stock to a watch list and you couldn't make it this but anyway, configurable with the ViewModel as well. But since we only need it for this purpose, we can get away with doing that. We're going to set the background color here to be a system blue. We're going to set the title color here to be a white for normal. And we're just going to pretty this up a little bit. I'm going to go ahead and give it a corner radius of maybe six. We'll also make sure the layer does in fact, mask to bounce aka will see that corner. Maybe we'll even bump this to eight here. And let's go ahead and start adding these as subview. So in the initializer here, we definitely wanna go ahead and say content view, add subview, and we went to add the label as well as add the button. Now one thing you might observe, this is kind of redundant. Why can't we just add all are sub-views in one shot? Well, we can, we're going to add an extension so we can do exactly that. So we're going to open up our extensions file. There'll be previously created. And we're going to add, like I mentioned, some more extensions to make our life. Easier just in general in terms of the amount of code that we're going to have to write. So we're going to extend the UI view class and we're going to add a function called add subviews, which will be plural. And this is going to take in views and we're gonna use something called a variadic parameter, which is his dot-dot-dot business. And it tells us that we can basically pass in multiple UIView classes. So all we're gonna do here is say Views. And all the views we're going to say for each. And this is going to basically pass us the view that we're looking out. We're going to say add sub view singular $1, which will be that particular view. And now what we can do as a result of adding those heavy dandy extension, we can just instead of doing a single view at a time, we can say add subviews. And I can chain these together a lake so it reduces the amount of code you have to rely on the color side. So I always think that's a win. So now that we've got that there in the configure function, That's pretty simple. We'll say label text is going to be ViewModel a dot, and this will be title. And we're going to say the button is hidden, is going to be ViewModel and that's gonna be should show Add button. So if this is set to true, we want it to not be hit. And so we'll take the inverse of that. So if should show is set to true, is hitting this false. So of course, so now that we've got done this stuff done in the reuse, prepare a function that gets called regolith, say text is going to be nil. Now what else do we want to do? Well, we never added in action to our button. So I'm going to say Add targets is going to be self. And when we tap on the button, again, we're going to use that delegate pattern to proxy the call to whoever the delegate is at that point. So we'll go ahead and create this. But in action here is going to be an Objective-C private selector. We'll create a delegate in a moment or just say call delegates. And let's see what else we want to do. Most importantly, we want to lay out our views. So first up, let's do the label will say CG rect will say maybe 14 from the left, 0 from the top. Width can be content view dot with subtracting 28. And the height can simply be constant of view heights just like that. And that should be good for our label. And we'll do the button momentarily. Bosses do that for now. And let me actually go and hook this up to our news controller to make sure we can actually now see our title. So we're gonna go ahead and jump into our controllers and go to our news controller to use this new header. We first want to register it. So we're going to register the news header data itself for a header footer reuse identifier, which is the ID off of this guy. Now down here, instead of hard-coding 70 for the height, we're going to say return dot preferred height, just like that. And we want to dequeue this actual header. So we'll go ahead and say guard, let header is going to be TableView. We're going to dequeue a reuseable header footer view for the given identifier. And we're going to try to cast this particular view as the header that we have created. The reason we're going to cast it here is because we need a callback configure function on it. So I'm gonna go ahead and say return nil there. And in this case or will turn the header. And here we're going to say header and we're going to say configure with the given ViewModel, which takes in a title, add a Boolean, and now the title is pretty simple. We have type on ourselves, so it'll say self dot title. And keep in mind that type refers to the enum that we created way up here. And the title is either top stories or the given symbol uppercase. And then this guy is going to be nil for the actual show's showing of the ADA. And we'll set this to true in a moment and make sure it's actually showing up. But for now, this is pretty good. Let's go ahead and give it a run and let's see if we're starting to see our header. All right, we should have one section by default and boom, we definitely see our header here. So one thing that I'm not a fan of is the way this color is looking. So what you could, what you could do is you could get rid of the background color of the header or you can set it a little optional, but at least we're getting our top stories here looking pretty swell. So let's go ahead and work on that Add button. So I'm going to set this to true and then we'll also tweak the color while we're at it. So let's jump into the header view and the background color here we aren't actually even setting. So I'm gonna say content view, that background color and we're gonna save, this is a secondary system background. Let's go ahead and give that a run and let's see if that's looking any better. Much better, okay. Now I'm happy now looks good. We don't see or ADA and just quite yet, but we're going to fix that. So we said that our shows to true, so we've definitely said is hidden to be false, but we need to give this guy a frame first. So I'm gonna go ahead and say by in size to fit, which will auto size that by N per the appropriate sizes. And then we're going to assign the frame. Of course, you can use constraints for this as well. Various objective both accomplish the same thing. So let's go ahead and line break all this stuff to make it look a little nicer. Here, we're just going to say dot heights. I want this to be a little wider than the actual desired or the minimum width, somebody say plus 8 here, not nine. So you have four points on each side. The x is going to be content to view dot with minus. But in data with subtracting perhaps for, for the buffer, but a little bit more for just the insets. And maybe we'll say 14. And the y is going to be the content view height, subtracting the button height divided by 2. In other words, we're vertically centering the actual button. If I did those calculations quickly, feel free to pause who's to check that math and let's go ahead and give this a run and check my own math. So hopefully we see a button here, which in fact we do there is R plus watch lists, but we could probably move it inwards a little bit more, a little subjective. But let's go ahead and do though it's moving and maybe to 16. But I'll leave that as is for we run it again. Let's hook this up to an actual delegates. So what we wanna do is leverage that same delegate pattern we did in the results controller. So I'm going to come all the way up here and creates a protocol which is going to be some fixed width and delegates. And we're going to extend any object. And this is going to be news header view. Did tap Add by n and we're going to pass in a reference the header view, just like that's pretty common standard for delegates. We're going to want a weak var on here, which is going to be called the delegate of type our delegates. And now down here, when we click on the button, we can say delegates, go ahead and call that function passing in itself. So in our case, on the watch list, when we see top stories, we can't add top stories terawatts list. So we're going to set this hidden to false rather to show, showing it to false so it's hidden. But when we click into a particular symbol and stock, we're going to conditionally show this if the given stock is a part of our watch list. So let's go back to our watch list controller. And we are going to say rather our news controller. And we are going to say false for our shows button here. So we'll go ahead and say false right there. And then you can also go ahead and line break there so it looks a little cleaner. Also, I shorthanded how we initialize as ViewModel. So if you're confused for any reason, basically this is equivalent to doing the header view ViewModel. So I just did it with the init since it's a little shorthanded, but it's a little cleaner to read in this case, since the dot ViewModel is a little verbose. So there you have it. That is our header. We're starting to look a whole lot nicer. Let me go ahead and run this, make sure the Add button disappears. The next thing we need to do is start to look at our data, because we need data before we can bring in any cells here. And actually even before doing that, we're gonna wants to have a array on here which all create very quickly right now, let me just move this enum all the way up. And we're going to have an array on here basically which is going to represent our stories that we're looking at in the news panels. So we're going to mark this as properties. And there's going to be a private var array called stories. And I'm just going to stick a string in here, but of course, this will have a dedicated model. So that's all I've got for you guys today. Thanks for sticking around. I'll see you guys in the next part. 15. News API Call: All right, welcome back guys. In this part we're going to continue building out the news section, aka the floating panel. And more specifically, we're going to start talking about the News API. So if we come to our fin Hub API documentation here and start scrolling down, you'll see there are two relevant endpoints that we care about. The first one is market news, which is gonna give us market related general in the US. And then right below that we have an option for a company news. So as you can imagine, we're going to implement both of these and make sure we can start to get some data back. So without further ado, Let's jump into our API color class and start implementing a function to do this for us. So here we are API color and we want to basically create a function just like we did for search. And this one is going to be called News. And I'm going to go ahead and give it a parameter. So we're gonna say news for type. And the first parameter is going to take here is the type of news we care about. So from the news controller, we're going to grab the type that we created there. Keep in mind though is either top stories or accompany. And we are going to give a completion handler here very similar to what we did for our search API call. I'm going to make it a array of strings. For now. We'll change this to a actual model momentarily, and this returns void like so. All right, Cool. So the first thing we want to actually do here is create a relevant URL. So if we come and take a look at this, the URL or the end point is simply news. So I can go ahead and create an endpoint is called news, but that might be a little misleading because news is a general term. So maybe I'll go ahead and say top stories and the raw value for it will be news just like that. And then in terms of whether this takes in a parameter or any other arguments, as, you know, query parameters to our URL. It does take a category with a value of general here that I've highlighted. So we are going to call this function now. So we'll go ahead and say let's URL is going to be URL for top stories and then query items here there is going to be a category and it's going to be general, just like that. And now that we've created and we can simply call our request function. But before we do that, let's see the response that we're gonna get back. So it looks like we're gonna get an array or a dictionary that contains multiple of these objects here, which looks to be a news story. So let's go ahead and create a model that's going to back this because we want to use it for decodable purposes to create our model from the JSON, someone to create a new file here. And I'm going to go ahead and call it a news story, got swift file. And I'm simply going to call this model a news story which will be quotable. And once we've created this, I'm going to paste on in what I've copied from the response. And we're just going to clean this up to be the actual response. So once again, you can hold the option key. Once you get this little indicator, you can get multiple lines highlighted with multiple cursors just like that. And let's go ahead and take care of these. So the category in this case, all of this stuff is going to be a string. So we'll go ahead and z, that's a string. This one is also going to be a string for the headline related, it looks like is a string sources a string we care about that summary is also a string, so I'll go ahead and drop that there. And then finally, the URL in this case is also of type string. Now the one that I obviously missed here, first of all, as images or image, and this is a string as well. This is a URL to the image. But then there's DATETIME. You might be inclined to make this type integer when in fact it should be a time interval. So you guys will see why in a little bit. But basically this is the news story that we care about. The object will jump back to our API color. And here we can go ahead and request that particular API endpoints. So there is our URL expecting an array of news stories in the completion. It will be completion. Just make sure you go ahead and update this to be new story as well. So we don't have any tightness match, aka no error there. And let's go ahead and simplify our code by just dropping that. I'm going to put that there and we're going to lie and break some of this stuff. So it's a little cleaner to read. Drop that to a new line as well, and this one as well. So cool. So now that we've got this API setup, let's jump into our AppDelegate where we had created that debug function. And let me try to call this API. So in D by Q, we're going to say API color, share and news that we care about top stories. And here is our result and we're simply going to print out set results. Go ahead and build and run. And let's see if this does what we wanted to. We expect to see a whole lot of output down here of our response. Let's see what we actually got. Yep, Looks like we are looking pretty good. So here is a whole lot of news stories for us. We've got some images in here, some titles this and that, looking at pretty darn good, right? So one other thing that we might wanna do, and why we might want to do this later on is right now in our model for our new story, we hold a datetime as a time interval. More realistically, what's helpful is for us to have a date object and to convert that date to a string, we're gonna wanna do that business logic and the ViewModel because we're not going to show a time interval on our UI because I would just be dumb. We want to actually show a nice formatted date. But before I get ahead of myself, let's go ahead and deal with the other variants of our API color here. So we actually need a switch on the type. So I'm gonna go ahead and say switch on the type. And in the top stories case, this is what we care about. But in the other case, which is what we call it, that we call the company, we get a symbol back. So we do want to do something similar in here, but it'll slightly vary because we wouldn't call it a different API endpoints. So the other endpoint we want to call once again is right below it, that's called company news. And the endpoint is company dashed news. And it takes a query item of symbol, basically how you would expect we have a from and a to where we need to specify dates. So let's go ahead and build this one out. So first of all, the endpoint that we care about, we're gonna say this is going to be company news. So we want to try to spell things correctly here. We'll say company news. So this one right there. The next thing we wanna do is specify the symbol as well as the from and to arguments. So let me go ahead and line break this a little bit more. This is going to be accompany news. We're going to line break this, this one as well. This one as well. First off, we're going to have a symbol. We're going to pass in the symbol. And now we have a from, which is going to be a string that represents a date and a two. Now we don't want to hard-code this. We want to calculate this based on the current time of day, the current date, I should say. But there's a couple of things to note here. So there's assemble a from right, which is in this format, the year, month and day and then two. So what we might want to do is maybe show the news from the last 30 days. That sounds reasonable to me. So how do we actually do this? Well, we could do all this code inline, but I'm going to create some extensions because this will greatly simplify the code that we have to write. And we're going to use a bunch of extensions on date for matters. And that'll help us also when we get to our view models to render out dates. Did formatter, we're going to have an extension on date formatter. And there is going to be a, let's call it a news formatter, or we'll say news date formatter, which is of type date formatter. And in here we're basically just going to create one of these. We'll say formatter is a date formatter and make sure you use the proper capitalization here since everything is named fairly similar for matter. And then the most important thing, the format style here is what we want to specify. So we'll say format's style. Let's see if I could find it. Might be just call date format either we are did formats and this will be year followed by the month and then lowercase Tuesdays for the day otherwise would get something different. So now that we've got this, what we actually want to do is we want to use this date formatter to get a string. So let's go back to our API color. So the two we're gonna specify today's date. So I'm going to go ahead and say date formatter, news date formatter. And we want to get a string from a particular date. And this is going to return to us a string. And we'll say from date, which is today. So I'll go ahead and create this actually up here, so it's a little cleaner. We'll say today. Also, today is a date. Maybe we'll say one month back is going to be today and then adding a time interval. And we basically want to add negative 60 times 60, which is an hour, times 24, which is the amount of time in a day. So we can actually make this simpler. So we'll say 3600 times 24 times 30. And this will give us the number of seconds in 30 days a month, just about. And we'll get this, you know, this one month back dates. And here we can say one month back and we can actually copy this whole thing is date formatter business. And we can simply pass in here one month back just like that. And this should be all that we need to do to get this working. So let me go ahead and jump into my AppDelegate. And I'm going to change this to be company news. And we're going to pass in a symbol, maybe Microsoft symbol. So we'll go ahead and give this a run. And I'm assuming the response will look similar to what the first endpoint looked like, because we didn't change that. So it looks like we are getting something back. It you saw it flashed there and then it disappeared. 30 days might be a little too much. Basically we're printing out too much stuff into the console. So the console sometimes loses its mind. But what we can actually go ahead and do is we can print out news dot count. And basically this will give us how many news stories we are getting back. But before I actually go ahead and do this, Let's reduce the time interval for which we are providing. Maybe we'll get news for the past seven days instead of 30 days. So we'll go ahead and do that. And you can actually also toss this stuff and to be a constant since we're doing these brittle calculations. And here you can see we got 256 news articles about Microsoft. So you could, you could turn this down as much as you want or subjective. Let me go ahead and toss this into a constant because there's 24 times 3600 represents a single day. So I'm gonna come up here and say static. Let a day in time is a time interval and this is going to be 3600 seconds, which is an hour, 60 seconds times 60 minutes times 24. And then we can come back down here and here we are going to say constants that day, multiply it by seven. So a week basically. And that is basically the API calls for our and news articles in a nutshell, both were top stories as well as for actual, actual companies specifically. So you can pass in a symbol, in other words, and that's all I got for you guys today. So in the next few parts are going to start to plumb the data into our UI. We're going to set up our custom cells and all that good stuff so we can actually see these actual news stories and our UI. So I'll catch you guys in the next video. 16. News Custom Cells: What's going on, guys, welcome back to the next part in the new section. In the last part, we set up all of our API goodness. And in this part we are going to build out our news TableView cell, which is going to go into our actual panel here and elsewhere in the app once we start building more out. So without further ado, let's go ahead and jump in to first our controllers folder and our news ViewController. So we created this story's thing here, which is of type string array. We want to go ahead and update this to be a news story just like that. And actually we can just keep it as a string by points here is what I would like to do is we want this to have a single string in it. So maybe we'll say first. And the reason I want to do this is because we are going to want to render out a single cells. We can see what it actually looks like. So number of rows, we're going to say stories that counts here. And instead of creating a normal TableView cell like this, even though this is not the correct way to do it, we want to create our custom cell. So the custom cell is going to reside, of course, under the views folder, since it is a view, let's go ahead and open this up. We'll create a new file here. It's going to be a Cocoa Touch Class, and we're going to subclass a UITableView cell. And I'm going to go ahead and call it a news story TableViewCell, since that's what it will represent. And let's start talking about what we want to show in here. We're going to start by deleting all this stuff. And first up we need an identifier. So I'm gonna create an identifier here. We're going to want to override the initializers. So let's go ahead and do that and get that out of the way. Pass and style for sale reuse. To reuse. We also want the required initializer here with the coder will bring that in. And there are three other functions that we want. So layout subviews, which is given at this point, everything needs to be laid out. This should be layout subviews now margins. We're also going to want prepare for reuse, super prep pair for reuse. And then finally, we're going to want a public funk. And this is going to be configure with view model. And we're going to create a view model here momentarily view model. And up here we're gonna create that view models. So it's stick it up here. View model will be a struct. And let's talk about each of these cells. So each news stories sell should basically show four pieces of information. The source, the headline, as well as a date and a image. This should tell you right off the bat that we want for subviews. So let's go ahead and create this first upbringing to have a source label. So we'll say private let source label will be a label like so we're gonna go ahead and create it and maybe we can get away with actually copy and pasting this. Now you're going to have to play with the actual font sizes here to get the look and feel that you want exactly rights. But in our case, we're going to stick with some random font sizes. Start, we'll say maybe, I don't know what start with 14 and see what that looks like. We'll make the weights maybe medium. And I'm just going to copy and paste this and change up the names. So that'll be a headline label and this is going to be a date label. So let's go ahead and change the name here. This is a data label, definitely the same size. Maybe we'll make it a light instead of a medium. This'll be irregular, perhaps a little larger and fonts and we'll go at 70 and, and change the name of it as well. It's a headline label and don't forget to do your image view, arguably the most aesthetically pleasing part of the cell. It's going to be an ImageView like so you can actually call it a story in his view, so the name doesn't conflict with the base class. And now we're going to be creating the image from a URL, right? We're going to be downloading it from there. So I'll show you guys how to download it from there. And they will also go through how to use a library to do that for you. I'll make sure you guys have both, you know, at your disposal in case you want to do it yourself. Or you would like to use a library to help you out. Before we get to all that library and downloading image stuff, let's go ahead and configure this ImageView will say contents mode is going to be skill aspect of fits. We could actually also go ahead and fill the image, just make sure it's the aspect ratio matches so it doesn't look weird. We're also going to give this a nice corner radius of maybe six. Apple uses these corner radius is everywhere radii I should say, and they look really nice. So we want to use them here as well. So cool. So now that we've got our subviews here, you guys know the drill at this point we're gonna say content, view, background color. First of all, it's going to be nil. We're going to set the background color of the normal view nil. And then we're going to say add subviews. And we're going to just specify all of a sudden view. So let's go and orders first we're going to show the source, and then the headline, and then the dates, and then the story image view. So now that we've got all of these, the next thing we wanna do is lay it out and then we're going to want to configure it here as well and update this reuse. So let's do prepare for reuse first. Since it's pretty, pretty trivial, we're just going to reset all of these labels. So here's the source headline, Here's the text label, or try that one more time. There we have it. And for our story image view image is going to be nil as well. So let's see what else do we want to do? So I am going to basically put this stuff in here as well in the viewModel. So we're going to want to configure this stuff with a source. We're going to want a headline. We're going to want a date string. And we are also going to want a image. Url should be a fully qualified URL. Maybe we'll make it optional. And we want to create this view model. And this is pretty important or as a business logic going into your ViewModel from the model. So the view model will be a derived object from the model. So we're gonna say create this with the model. And this is going to be a news story, a model for those of you guys who don't remember, this is what we get back from our API. It is a quotable object just like that. And let's go ahead and create this. So we're gonna say self.age source is going to be modeled. Dots source, self dots headline will be model.py headline. And let's see what else do we have? Dave, string is a little tricky, so I'm just going to hard code it right now for a quick second because the actual model doesn't give us a date or a date string gives us a time interval. So let's say maybe June 212021. We'll come back to this and self.name is URL is going to be nil. So now that we've got this here, we need to lay everything out which is arguably the most involved as part of this. So before I actually do that, let me go ahead and make sure we're seeing at least one of these cells in our actual table view. And actually one more thing I forgot to do here is I'm going to add a preferred height here, which is going to be a 140. That way if we use this elsewhere, we don't need to hard-code 140 everywhere. Let's jump back into our news controller and let's go ahead and do this stuff. So this is going to be the preferred height that we just brought in. The number of rows Makes sense here is the preferred height for the header. This is what happens when we select a new story. So I'll say open news storage, so you don't forget to do that. There's the header config and here we went to register that new cell that we just created. So just like we registered here, the header we're going to say Table register. They went to register the news story, TableView, news story, TableView cell itself. And we want to specify the related identifier. Now, we don't want to register it for the header typing when I registered for a cell. So make sure you use the proper API here. So this is going to be dot identifier. And let's see what else do we need. So we are going to wants a dequeue this appropriately. So let's see where we put that function. So this is where we want to fetch our data. Here we are. So here we are going to say guard and let cell is going to be TableView. We're going to dequeue a reusable cell with the given identifier for the respective index path. And this index path comes from the parameter of this function that we're inside of. So we'll go ahead and says line break, all this looks nicer. And we'll go ahead and cast. Otherwise we're gonna say fatal error here. We're going to return so and we want to configure the cell with the appropriate view model. So I'll go ahead and say, so we have an array of stories. And actually what I wanna do is I want to create a ViewModel from the given story. And I keep in mind stories as an array of strings. So let me just come up here and change this to be an array of news story. And inside of here I'm just going to create a, just a dummy news story for the sake of it, we'll say new story has a category of tech. Maybe it has a datetime of 1, 2, 3, headline of some headline. Should it go here? And let's see the image string. We'll just make this empty related, we'll say is related. And we're just filling in dummy data at this point for just to render out our cells and we can make sure it looks good. Url keep empty. In summary, we really don't care about at the moment as well, so we'll make that empty as well. Now that we have this single story in here, we should start to see a given cell. Let me go ahead and just set the cells background color, even though we didn't fill it out that way, we can make sure we see it. So we'll come into here and I'm going to make this dark pink. And we'll do the same thing here. I think System pink is actually what I'm looking for there. We have it system pink, system pink. Go ahead and give it a run and we should hopefully see one cell. We still need to lay everything out. All right, cool. We see one cell and this is going to contain our news story. Let's get to the layout and then we shall wrap it up here. So we have this configure function already, but we're not using it. It's actually before even laying out. Let's say headline label, dot title are taxed, I should say is ViewModel, it's ad headline. Next up we are going to say source label dot text is going to be ViewModel, that source, date label dot text is going to be a ViewModel, that date string. And then for the image, we want to download it. So we'll say set the image. But basically we're going to use an extension to do this under the hood, but we'll get there in just a moment. So let's do the layouts and sets a little more involved. The first thing we want to go ahead and do is create an image size. Now the image size is basically going to be the constant view heights, subtracting six. So there's three points and the top and bottom. And let's do the ImageView now we'll see the ImageView or story image view dot frame is going to be CG rect. The x is going to be the content view with subtracting in his size, subtracting ten, y will be 3. This will be image size, and this will be image size as well. Just like that, Let's go ahead and lie and break this guy and align it. Fun factor, you can do Control I to fix up all of your alignment if you were not aware. Let me also set a background color on this in his view. So we actually have something to look out. We'll say background color is going to be white, so that should be our image view. The next three things we want to lay out our, our labels. Someone has say layouts, labels, the easiest of which is the data label we're going to assign it. And actually instead of even typing it out, Let's just be lazy and copy and paste. And once again, you could use constraints for all of this stuff. I'm opting to do it this way since it's fairly simple calculations. The x is going to be the separator inset dot left. The y is going to be a content view dot height minus 40, height, you guessed it 40. And this is going to be available width. Now what is available with, we're going to declare it right up here. It's basically going to be the width of the content view, subtracting the padding and the image size. So I'm going to subtract the separator, separator in sets dot left, subtracted the image size, subtract 10, which is the right padding for the actual cell. And then we're also going to subtract perhaps a five. We can make this 15, which is our padding between the image and text horizontally. So that's our date label. And let's go ahead and simply copy and paste, do our source label. And finally down here, most important one, which is our head line label. So the width doesn't change for either of these, X doesn't change. What changes is the y and the height. So for this, I'm going to make the y four. And the height is basically going to be the amount of height that we need. So we're gonna say size to fit, and this will be this dot height, just like that. So this will basically soft size itself. And then we can figure out how high it needs to be just like that. And then the headline label, the y is going to be our source label, that bottom plus five. And the height is basically going to be however much height we have at our disposal. So we're gonna take the heights. We're going to subtract the Vz source label dot bottom. We're also going to subtract the date label dot heights, and then we're gonna subtract ten points for good measure. So we have some nice padding. So those are a lot of quick off the calf calculations. I'm hoping all my math is correct. Let's go ahead and give it a run and let's see what we are seeing in our cell hopefully doesn't look too bad. All right, looking pretty good. So we have our texts there. We've got the headline, we've got the dates. Let's get rid of the background color and let's clean up the font sizes as well as the colors. So let's see, we supplied pink in here, so I'm gonna go ahead and fill this out. Well, Mill this out as well. Instead of using white here, I'm gonna say system, we can say tertiary system, background color. And for the DFF, I'm gonna go ahead and set its text color. The text color that we are going to want to stick with here is going to be secondary label. I think thin or lights worked pretty well here. We definitely went up, bump up the font size for our actual headline here. So let's go ahead and do that. Give it a run and let's see what we're what we're looking like. All right, Looking pretty good, but one thing I forgot to do, which is supercritical. We want this headline, so line wrap. So we're gonna say number of lines is going to be 0. Let's try that one more time. The process of making UIs tedious, but honestly it's just a little bit of tweaking here and there, but now it's looking much better. There is a headline, we have a black background. So let's see why we're getting that black background, because we should not be getting any background. So let's see what happened here. We've got nil, we've got nil. And let's see what else we need to adjust here. So we probably should go with setting a secondary system background. The reason I'm milling everything out is because it's harder to track down these background images when you have things on top of each other with different shades. It's kind of a pain that but actually, but I guess like doing that made it look much nicer. We've got CNBC, we've got the headline, and then we've got our date, which is looking pretty nice. So now that we have our stuff working, Let's talk about this guy as well as the image. So right now we're setting the date string with a hard-coded value. But what we want is we want a way to convert its time interval two in appropriates looking string. And we're going to leverage to extensions to do this. The first one is going to be a pretty date formatter. Call it whatever you want. I think Corey date formatter works well. I'm going to come onto here and set the date style to the medium. And the other thing that we want as an extension on strings. And you can quickly start to see why we created a separate file for extensions because it makes your life a whole lot easier. When it comes to just like doing redundant work. You don't have to write the thing out over and over. So I'm gonna go ahead and call this string from time interval. And we're going to basically allow the color to pass in a time interval here, and we're going to pass back a string. So the first thing we want to do is create a dates with the time interval. So we'll say time intervals since 1970, we'll pass in time interval. And now we are going to return date formatter. Pretty did formatter is string from a date and boom, we should be good to go. So this is a little more verbose. But now we can use this and all of our view models and our business logic without duplicating the code. So down in here now we're gonna go ahead and actually say, what do we actually want to say? So we have a model dot datetime. So I'm going to say dot CSV string, that string from a particular time interval. We can drop that and this'll spit back out to us a nice date string. And lastly for our imageURL, we're gonna say this is a URL string. We'll go ahead and say a model dot image, image URL, I guess just image. And this is optional, so we'll need to check this once we get there. So that's looking pretty good. Let's see what else we wants to do. The other thing that I'd like to do is show you guys how to write out the image download manually before we bring in a library. So I suggest using the library because it is far simpler and cleaner to implement. But that not to worry, not going to leave you guys hanging here. We're going to write an extension on UIImageView and it's going to be set image with URL. And this is going to take in a URL. And basically we're going to download the image from the given URL and we're going to assign it. So first we unwrapped said URL. And here we are going to create a task. It's going to be URL session shared. And we're going to spell shared correctly. And here we're going to say Data task with a URL and a completion handler. Completion gives us data back and optionally an error in response, we only care about the data. We want to make sure that the error is in fact nil, we're going to return otherwise, as you will see, tasks that resume. And then finally, once we have gotten our response back, we can go ahead and say self dot image is going to be UI image, data and data. We don't want to cause a memory leak. So I'm gonna go ahead and say weak self here. And this is going to be self optional. And this whole thing, you would actually go ahead and drop into the global thread, global queue so we don't impact the main thread as mine. So we'll say quality of service is user interaction. So that's basically how you would set this on the ImageView. So if we go back to our view, well, we can go ahead and do here is we can simply say story in his view. And I'm going to say set image with the URL passing in the ViewModel XYZ image URL. Now once again, we're not going to be doing it this way. We're going to use a framework called SD web image. But this is how to manually do it, but let me just go ahead and comment it out. Manually. Set image. And now you guys know how to do that. So before we wrap up here, since we've done quite a bit, if you do give it a run again, you will see that there is a issue with the image obviously, since we're not setting its and we're going to see a completely different date here because I supplied some random time interval. But yeah, this is basically how our cell is going to look. I think it's looking pretty, pretty spiffy here. In the next videos, we'll go ahead and start to wire up the actual models to our, to our actual ViewModel and then the cell. But before we wrap it up here, let me go ahead and close Xcode and we're going to bring in the dependency I just mentioned. So I'm going to go and cd into our project. We're going to open up the pod file and we're going to bring in the dependency that we want to set images as the web image. Once again, if you want to use the manual way that we just talked about, go ahead and do that. But for me, I'm going to use this library since it is really easy to work with and it handles things like caching, which is pretty easy to do on your own as well, but we're going to be lazy. So I'll go ahead and open up our project. We can actually get rid of this image here since we brought it in already. And we'll just make sure everything is still building before we call it a, call it a video. So let's go ahead and hit that Play button one last time. And this part, everything is building, building, building. At the top of this file you probably want to bring in St. web emit also. So we'll say import st Web Image. And down here to actually use it, you can say story ImageView, SD set image. And you can pass in a URL here, which is ViewModel, that image URL and the completion handler is nil. So cool, looks like it built successfully. We'll try that one more time to make sure it's still looking pretty good and bear with us while this launches and we're in business. So that is basically how our cell is going to look. We've got our header, we've got this, of course, we can drag it up and we can't scroll further down. And this is what I meant by the TableView. Once the TableView reaches the top and we start pulling, you'll notice that it starts to impact. How are, how are floating panel starts to move down. So it's pretty cool. So that's what the floating panel tracking actually does. So that's all I've got for this part. Things are sticking around. Hopefully you guys are keeping up and I'll see you guys in the next part. 17. News ViewModels & Wire Up: What's going on, guys, welcome back to the next part in the last par in the new section here we went ahead and put together our love for our cell. In this part, we're going to actually create some few models from our models that we need to actually hook up fetching four and we'll see our news panel and it's tentative complete state. We're going to definitely polish it up, but we'll actually start seeing some real data. So let's start by jumping in to our news ViewController. The first thing we actually need to do here is fetch some of our models. And even before then, I'm gonna come up here and delete this dummy news story thing that I created because we don't need that, we're going to actually create a real models. So let's go ahead and do that. So maybe drop that. And here we'll drop a equal sign. So where do we want? See you fetch. So we definitely have a Fetch function already. We're going to come into here and say API color shared. And we are going to say we want news for the current given type. Remember this is self.age, which represents the type that we created this controller with. Since our API color supports both a company and top stories, we're gonna get a result as a results of the API costs, no pun intended. And in here we're going to say, let's success. We're gonna get some stories back. Otherwise, we are going to get a failure in which case we'll just print out the error and maybe we'll tidy this up with some better error handling. But now that we've got this in here, what do we wanna do? We're going to say self dot stories is going to be stories and self.age TableView. We're going to tell it to reload itself. Now we want both of these to be self optional because we don't want to cause a memory leak. So we'll go ahead and do that just like that. And let's see, we do want to also do this stuff on the main queue because it is UI work and we do always, we always do UI work on the main thread. Just like that, we go ahead and assign the stories until our table to refresh itself. And I think we should be in good shape. So let's go ahead and give this a run. Keep in mind that our view models are being created right here. We basically take v, this is the header. Actually. We actually take the cell and we instantiate a ViewModel from the story at the given position. And now if you take a look at what we've got here, we can actually start to see our images are titles, are sources. So these are top stories and these are from most recent to oldest. So today is, I believe June 27th, which is why we see some things from the 27th. Now, some things you might want to adjust here. You might want to decrease the headlines size, it actually looks a little large. Numbers are so many more in here. We might want to also go ahead and decrease the image height a little bit. So let's go and polish that up. We have an optimization section leader, but we'll go ahead and clean it up a little bit right now as it is. So the image size, I'm going to go ahead and instead of subtracting only six, maybe we'll subtract 12 so we get a 6 buffer on each side. The other thing I'm gonna go ahead and do is decrease the headline size for its font instead of 24, maybe we'll say 20 to go ahead and give it a run. We have it set to regular for the actual font weight, which I think is perfectly fine. And let's see what that looks like looking at a little better. Now, you could in fact, the height here, taller to accommodate a third line of text, but I actually think two lines is sufficient. Now as we scroll, we can see that we're loading in all of our images nicely and I was just scroll back. They're not reloading because SD web image actually is caching everything. So I still think that we need a little bit more room from the top and bottom of the cell for the image. So let's see what our image calculation looks like. So we have said that the y is 3, that in fact is the problem. What we should be doing is properly calculating this will say the height minus the image size divided by two, which is going to vertically center our image. Let's try that one more time. And we'll actually also try this with accompany as well. So they just top stories. I think that's looking pretty good. We're centered vertically. Now, you can even actually let me space these out even more and because it's bugging me at this point. So we're gonna say this is the heights maybe divided by a one points 4. And that'll always be a little smaller. Per the percentile that we've divided, you can make a half to high. There might be a little too much, but I think maybe that's looking pretty good. Not too big, not too small. And yeah, feel free to change up the, you know, the heights and weights and all this other stuff for the font sizes. I think this is pretty good as far as I'm concerned. But let's go ahead and try this out on the news controller, or rather the watch list controller from calling this API with a company. So instead of just calling it with the given type, let's see if I can find it. So here we're creating a top stories. Let's go ahead and create a for a company and maybe it will create it for Snapchat and go ahead and give it a run. And let's see if we get news for snap and what it looks like. So we'll go ahead and do that, boom, snap and we see snap related news. So apparently snap stock is lagging. The general market. I don't know, is that good, Is that bad? Let me know. So this is basically in a nutshell. So we've got the crux of this working. We've got the title, we've got the Add button, even though it's not showing up just quite yet. And we've got everything laid out and looking pretty good. In the next part, we'll wrap up the new sexually that will deal with actually tapping on these, opening up the new story but keeping the user in the app. So opening up in app for the actual articles. So thanks so much for watching. I'll catch you in the next one. 18. Opening News: Welcome back. This is the last part of the news that section in the previous video, we took a look actually plumbing our data into our cells. Here we can see some real news. In this part. We're going to actually deal with tapping on these so we can in fact open up the article and read it, since presumably that's what our users want to do. So first up, let me undo our change here that we did. So we're going to change this back to the top stories and our watch list controller. And if we jump into our news controller, that's where we are handling. Did select cell for the given TableView. Now the way we're going to open this up is really, really simple. First, we're going to get the relevant story outs from our stories collection. This is going to be the nth element and this is our model that we're going to attempt to open up rather creates a URL, I should say, from the given story, singular story aggdata URL. And if we're able to create this, we're gonna go ahead and call the open function that we wrote where, where it can pass in this URL and this open function is still empty. We haven't done anything in here yet, so let's go ahead and do that. What do we actually want to do? The first thing is import a framework that Apple gives us called Safari services. And so far as services, let's just open up what Apple calls a sf Safari ViewController right inside your app, which is basically a nice web view package to look like Safari. So we'll do that and we're gonna say it presents a VC animated will be true just like that. Now one thing we wanna do, which is important is if we're not able to create the URL, we're going to say present failed to open alerts. And this is one of those cases where I recommend, you know, like if you can't if you're not printing out an error, nothing can explicitly go wrong. Definitely handle these functions and a graceful way such that they fall back for our actual UI. Because otherwise the user, my top it and file a bug saying, Hey, your app isn't actually working when in fact it is working, but they are just like not aware that it's working. So here we're going to say alert controller. I'm going to go ahead and create this with a title I will say on able to open, the message is going to be, we were unable to open the article. And let's see, the style will be an alert at the bottom here we want to go ahead and present said alert animated, should it be true? And I'm just going to line break all this so it looks a little nicer. Let's say alert, add an action, and the only action that we are going to need is a dismiss action. So here I'm going to say dismiss and attempt to spell it correctly. Style will be cancel, a handler will be nil. So go ahead and give a command R 2 builds on a run. And let's see if we can actually open up any of our stories. Let's see if we can find a good article to read. All right, Bear with me and my simulator and we should hopefully be good to go momentarily. Sometimes if your simulator slow, it might just be a computer but should load up. So let's see how Google one over some of its biggest critics in a build something, something, something. Let's go ahead and click this one. All right, apparently Google one, some of its biggest critics and this omega campus in San Jose, we can come into here, we can read about it. Apparently Google has a mega campus. What a surprise. But yeah, and then we can go ahead and go back and we're still in our app and we don't have the user losing their place. So it's pretty nice instead of just opening up the articles and Safari, which is of course an option as well. But presumably most people want to keep users within their own app. So I think we go back 70s here for news, which looks like is a ton of news. So you might want to tone this down even more, but it looks like we get quite a few articles, which is pretty cool. So that's all I've got for this part. In this section, we've gotten news put together. Now of course on our details UI, we are going to show news, but it's going to be a matter of reusability at that point. So this is the fundamentals of what we'll need to build a vat outs. That's all I got. Thanks for watching. I'll see you in the next part and the next section. 19. Watchlist Defaults: What's going on, guys and welcome to Part 1 of the watch list section. In this section, we're going to finally builds out everything that's going to show up in this area here. So all this empty space that we've been looking at for the past two or three sections. So it'll include some default accompanies where we're going to show their name, their little graph there prize all that good stuff, as well as allow the user to swipe that deletes and edit it and add their own stocks of the watch list, so on and so forth. So that'll said, let's jump straight away into it. I just mentioned here that we're going to show something by default when the user first launches the app because it would just not be that nice if it was just empty and we were waiting for them to add something. So I've got a list of a couple big cap stocks here. So we're going to jump into our Persistence Manager. And what I'm gonna go ahead and do is we're going to create a mechanism to store some symbols as the default symbols if the user has not been onboarded yet. So you guys might recall we created a function or a variable in here called has onboarded and we simply returned false. So what I want to return here is from UserDefaults, a bool signifying if the user has onboarded. And by default this is going to be false. And if it is false, we went to set up their defaults. So here we have adding and removing from the watch list. And here we have create your getting that user's actual watch lists. So what I'm going to go ahead and X2 is when we call to get the user has watched list, we're gonna save the user has not onboarded. The first thing that we want to go ahead and do is we want to onboard them. We want to set this up to be true. So we're gonna say user defaults. And we want to go ahead and sets a particular value for a key which is going to be true for the has onboarded it just like that. And once we've done that and let's see if I need the value. I think we can get away with doing this. And once we've actually set them up to be onboarded, we also want to call another function. And this other function here is going to be basically set up defaults. And the defaults are going to be those large-cap companies, stocks that I mentioned to the user sees something when they launched the app. So we're going to say set up a defaults. And then here we're going to basically return UserDefaults. We're going to give us a string array back for our watch list. So before I go further into this, let's talk about how we're going to save our data here in the Persistence Manager. Essentially what we're going to go ahead and do is we're going to save a array of just symbols. So here we might have like Apple and we might have Microsoft, that we might have snap. And then similarly for each of these symbols, we are going to save a dictionary from their symbol to their actual long-form name. And every time the user adds or removes from the watch list, we want to edit both of these elements. So let's go ahead and build out our default watch list. So here what are our defaults getting it to be? I'm going to create a dictionary maps. So this map is going to contain the symbol. And alongside it it'll contain it's irrelevant name. And let me just go ahead and create some of these cookie cutter companies here that we all know. So we've got Apple, of course, we've got Microsoft, we've got snap. We also need a Google, of course, Let's see Google, It's Goog. And let's see what else I've got Amazon. We also might want slack, whose symbol is work? We'll bring in Facebook and let's see what else we've got. I think we can do and video, which is that symbol. Let's see what other ones I've got written down here. Let's see Microsoft maybe we can bring in Nike as well as Pinterest. So Nike is NDK E and K E. And then we'll bring in pins, which is Pinterest. So this gives us a total of 489, 10, I believe I counted correctly, which is a healthy amount. So let's go ahead and bring in their respective names. So this'll be Apple Inc. This'll be a Microsoft Corporation. This is going to be Snap Inc. Almost at Snapchat, their Snap Inc. Next step, this is going to be Alphabet, Inc. I think this was the alphabet, actually. Amazon's full name is Amazon.com Inc. Work is slack technologies. Facebook is Mark Zuckerberg, Inc. Just kidding. And video is going to be n a video. Hopefully I spoke that Rights Inc. Nike is Nike. And finally, Pinterest is pin. Tourist. Looks like I made a typo somewhere. Put a extra quote there. This is going to be a Pinterest. Ink, just like that. So now that we have a map of all of our defaults here, we want to actually persist all of this stuff. So first and foremost, how do we get all of these symbols? It's pretty simple. We're going to say let's, symbols is going to be mapped. Dot keys are all the keys and we're just going to map each of the values out like that. And we can see UserDefaults. And I'm going to go ahead and say, So actually we could have just put it there or we can create a setter and getter here. Both are valid options in the watch list. I'm going to just put it there for this particular key. So we're gonna say UserDefaults set a string array. So let's see if I can find the appropriate one. We went to set a string array. It actually doesn't matter which one you pick here because it's going to figure it out for you depending on its type. Set that string array for our watch list. And in addition to that, we want to loop over the entire map. So we'll say for symbol and name in the map symbol and the name in map. We also want to set a name for a given key which is going to be a symbol. And this is how we're going to get out of our UserDefaults the name for the current symbol. And there's an expectation that when the user adds anything to the watch list, our code should also handle or adding their particular company name. Now I've got a constants struct up here and a habit in fact used it. So what I'm gonna go ahead and do is I'm going to start to put some stuff in there. So I'll say status like key. We'll call this actually on boarded key. Makes sure we spell that correctly and I'll drop that right there. Onboarded key. We just want to update these everywhere that way we don't make any mistakes. That's onboarded key. This one is going to be constants are onboarded key as well. You can make all of these constants as well, but I won't bore everybody. But I will do it for the watch list because that's a great place where most people will maybe run into an error. Maybe it's just me. So we'll go ahead and say a watch list. Key is going to be this guy. And we're going to come down here and just update this. We'll say constants dot watch list. And same thing for our function here. We're gonna say constants, dot watch plus key. And we're just going to return a string array for that particular key is should be constants, not whatever I typed in there. And this is our watch list key. So let's see what the problem is here. It looks like this is saying, Let's see, optional type shouldn't be optional and see what the problem is. Constant. It's because this is private and that guy is Publix. If I drop that, hopefully we get rid of the issue. Let's see what the issue is. String optional, That's what the issue is. Okay? This actually can still be privates. Let's go ahead and undo that. Basically what it's saying is that I might not have a specific list setup in here. So I can say coalesce this with an empty array like that. And like this, we have our default setup. So now if I go into the Watch List View Controller, I have a function, I believe already or maybe I don't. We create a function to set up our TableView. So we're going to say setup TableView will say setup table view before we set up the floating panel. And we'll go ahead and create this function right down here. We'll say private func setup TableView, just like that. And let's see, let's see what else do we want? We want an actual table view that we can set up. We'll say TableView is going to be of kinds table view, we're going to create it here. And of course we're going to want to customize the sulfur this later on in another video and register it here. But for now, we're simply going to just create and return said at table. In the setup function, we're going to want to say add the table as a subview, assign its delegates as well as its data source, just like that. And let's see, we're getting a yelled at because we have not conform to either of those protocols. So we're going to come down here and we are going to conform to a UITableView delegates as well as a UI table view data source. And now this is where the good stuff comes in. Really say a number of rows which is going to be return. And we're gonna say watch list dot counselors is going to be Persistence Manager, shared and bringing this say watch list dot count. But instead of doing it like this, what I want to do is I'm gonna go ahead and create a watch list property in here. And we're going to create this watch list in a way where we can hold the data associated with that stock as well. So we're gonna say private var watch, list, map. And this is going to be, the string is going to be the symbol, and it's going to points. You may be an array of some data. Now we don't have it yet, but we will fill this in. And let's see. So now down here I can actually go ahead and say from the map of return the count. And let's see what else I need. We're going to want to set up another function to actually pull that data from our Persistence Manager. So after we've set up the table view, I'm going to say set up data. Maybe we can call it a watch list. Data, just like that. Here we're going to say private func, set up watch list data. Here we're going to save data is this, this is our array of symbols. Let's go ahead and copy and paste that here we're gonna say symbols. And we can go ahead and in our, in our dictionary, we can basically add each of these. I can say for a symbol in symbols in our watch list map, we're going to add our map here, or rather our symbol here, individual symbol. And I'm just going to assign this to be some string just for some dummy data. And just like that, we should be able to drop these in like so let's see why this is yelling at me for symbol in symbols. And this should just be watch list, not a count. And now down here we should say tableView reload your data because presumably we want to fetch market data per symbol. So fetch market data per symbol, and that's what we're going to save into our actual dictionary here. Hopefully everyone still with me now let's do the rest of this TableView stuff before we wrap up this video. So we'll say sulfur for row 4, row at index path. We're just going to return a UITableView cell just like that. And this one's going to be did select row at index path. And what we wanna do here is we want to take the relevant selection and we want to actually go and show the details for whatever row we have selected. So we're going to say open details for selection to psych that and we should be in good shape. Now, this might be a little confusing right now if this watch list map, so these are going to be our model objects and we are going to have separate view model objects. So here I'm going to say view models. So not to confuse the model and the view models. We are going to have a view models was for now we'll just make it a string since we're not there yet. But the data it needs to be kept here as well because we're not only going to hold the symbol name, but we're going to have the collection of market data. And we'll get to that in a minute because it gets a little involved. So that's all I've got for this part. Hopefully everyone's following along. Let me know if you have any questions. Thanks again for watching. I'll catch you guys in the next part. 20. Market Data API: What's going on, guys, welcome back to the next part in our section. And the last part we set up our defaults for our watch list here. And in this part we're going to do arguably the most important part of this whole app and that is set up the markets Data API call. It's going to return to us a bunch of information over a set duration number of days. And that's going to drive not only the watch list, but it's also going to drive the details about a stock, aka rendering it's chart. So without further ado, let's go ahead and jump into air API color here and alerts, start writing out this function. So we want basically a function which is going to give us market data. And it's going to be for a given symbol. And there are going to be a number of days. So we'll say number of days and this can be an integer and maybe we'll default, it's 230 days or maybe seven days to pick whatever you want almost Sequence 7. And we're going to have a completion handler on this guy as well, similar to all of our other API calls. And then we'll jump on over in a moment to our API Dashboard documentation to see what the actual endpoint is. So we're just going to stick a string in there temporarily while we build the rest of this outs. And let's jump to our browser. So this is the endpoint that we want. It returns stock candles, otherwise known as open, high, low, close, which is basically the pieces of data that we want. The actual endpoint is stuck slash candle. So we can simply grab this and I'm going to come down here to our endpoints enough. Let's see if I think it just missed it. And we're going to jump in here and I'm gonna go ahead and call this case market data. And we're going to drop that in like so and now appear the first thing we want to do is get a URL. So I'm going to say URL for the URL that we want to get for is market data looking pretty good. Next step we went to perform a request. Now before we perform a request, you'll see here that this takes in Apple a resolution a from and a to as four parameters for our actual URL. Resolution is just one pretty simple. We can just drop that in right away and then we'll work on the other ones in a moment. So this takes in query parameters. I'll tell you that this is going to be a dictionary. So the first one is going to be the symbol that we care about, which we simply get as a parameter looking pretty good. The next one is resolution, which is going to be one. And now once again, we have that from two business. So we actually did this up above already, so we can actually get away with probably copy and pasting it. So what I'm gonna do appear is copy this today and prior stuff or drop this right here. And let's see, let's see, let me go ahead and do that. And then in here we're using this date formatter business. So we're going to copy this. This is going to be a day from is going to be two other two is going to be today. And this one here is going to be from prior. So I'm going to call this prior. This is going to be today because that's the most recent data that we have access to. And this one is going to be prior. And basically we're going to multiply the number of days times the inbound number of days parameter, and that's how we get that dates. And once we have our URL created here, we can simply make the API call. So we're gonna say a request from the URL expecting we'll just stick with a string for a hot second and then we'll pass in completion as well. So let's see what the response of this actual API call is going to look like. So there is our URL, it looks like something is a little funky here. Let's see what the problem is. So this is yelling at me. The prior does not exist because I made a silly typo. So let's go ahead and fix that. And I'll go ahead and line break the rest of this stuff as well. I'll write it looking pretty good. Let's make sure we have no more issues. That error went away. Looks like we have a problem up here for symbol because we forgot to add a comma and we should be good to go with sick. We've got an error here. Now this number of days, it's yelling because it's an integer where we should have made it a time interval. So time interval times time interval. Otherwise we're going to get that weird error because you can't multiply two types that are not the same. And that's how we create this call now will be a little cleaner and I'll copy this URL stuff and drop it on in here. So we're all in line and we should be good to go. Let's take a look at the response that we get. Because a response frankly is kind of dirty and we're going to want to have to clean it up. So we get basically a dictionary with C, H, L, o. A, t, which is timestamp, S, which is status, and then v, which is volume. Now, these are linearly proportional arrays such that the timestamp here is the date for which we have this closed prize, this high price, low open, et cetera. But the way this data is formatted is not very useful frankly. So we're going to be creating two models here. The first one is going to be your actual API response. And then the second one we're going to create is going to be a nicer a version of that data. So I'm going to say market data response, response. And basically this is going to hold those arrays which are pretty easy to put together. We're going to say, this is, this is going to be coachable. And let's see if we can get autocomplete working. Guess not. Now this is going to have 0, which is going to be double. It's going to have C, which is also doubles, going to have h, which is an array of double. Similarly we're going to have an L which is double. I think there was an S in there for status, which is string. And then there was also a t, which is time intervals. Now the first thing you might be wondering is why the heck is it's so short-hand. There's L o sue the heck is going to remember what this stuff is. And you're right, I agree with you. So what we're going to actually do is we're going to learn about a technique where you can change the property names but still have quotable work. So we're gonna go ahead and call this open. These are going to be the close prices. These are going to be high. This is going to be low. This'll be status, and finally, these will be time stamps. Now the problem with this is when you try to use coachable, it's not going to understand that oh, maps to open. And this is where we're going to bring in a genome called coding keys. And I'm going to say it's of type string and coding key. And what you can actually do in here is you can specify each of these and what the coding key is going to be. So we're gonna say a case open is going to be 0, case low is going to be L. Case close is going to be, see, what else we have. Case high is going to be H and case status is going to be S. I believe we've got one more, which is time intervals. We'll just copy and paste data, which is case timestamps is going to be t. So now with this will allow quotable to do is it's going to look at all of these and it's, instead of looking for the same name as the property in your JSON, it's going to actually look for whatever you supplied in the coding key here, which is the, then what you would expect in the response. But our properties are named far better now, right? So they just, oh see HL, which is kind of not great practice because it's super shorthand. So now that we've got all this put together, let's see if we can get our actual data coming back. So we'll jump back into our API color. And in here we're going to say we're expecting to get back from this, our market data response.status. And similarly, this will be a market data dot just to market data response, since that's what we want and the success case. And let's go into our app delegates and let's see if we can actually call this function. So here I'm going to say API, color shared. We're going to say gets market data for Apple. And number of days. Maybe we'll just say one. And we're going to print out the result and makes sure we're getting the results here. Now once again, we're going to create another model in a moment here because we want to clean up power structuring that data. Because how you multiple arrays that are adjacent to one another is not ideal. So it looks like we're actually getting a decoding error. So let's see why that is. So it looks like it's saying no value associated with key 0. So let's see what's going on here. So it looks like we've got C, H, O, L, O, S, and T, and V. So let's see, something weird must be going on. So what I'm going to actually do is I'm going to copy this URL. And I'm going to drop it into my browser and see what we actually get spit back from this. So it looks like, it looks like for some reason we're not calling the correct. It's actually this URL. I used the wrong URL. So stock candle, we've got resolution symbol from 2021, June 26 to today's date, and here is the token. So let me grab that and paste it on in here and let's see what we get. So it say we're getting an error, wrong value in from only accepts int data type. So let's see what we have supplied in R from C looks like we have 2021, six, and then 26 and then we have a two. So it looks like it looks correct to me. Let's see what the API actually wants. It looks like actually wants a time interval. It doesn't actually want the date. So that is a mistake that we made that I mean, I should say maybe you guys caught that before I did. So instead of actually getting a particular dates from a string from the given dates, we're getting these two dates here. And what we want to actually do is get the time interval since 1970, which is the standard that we use. So we're going to save you from is going to be prior and we're going to say prior dot time interval since 1970. And you wanna make sure you wrap this inside of a string just like that. Otherwise you're gonna run into issues. And similarly down here, this is going to be today. Let's go ahead and give this a run once more. And this is why it's really important to have some test data or like some test API calls in your app. So you can make sure that things are working when you build them. So cool. So we're still getting an issue here. We're getting a silicon find. Oh, let's see what's going on now. So we're seeing time interval. It looks like it's giving us a fractional time interval though. So what I'm going to go ahead and do is we're gonna take this thing and wrap it inside of an integer so we get a whole number, so no floating point, no fractional time intervals. I'm going to guess a, That's the issue. We're going to try to run it once more. This is also a logging and printing is pretty helpful. We should see data back. We still don't see data. That's no Bueno. Let's try that again. So we've got Apple resolution is one to and from and token. So this is looking good. Let me see what's going on here. So we come to this and it's saying no data, so that's not good. So let's see why that is. I'm actually going to subtract one day from today. So I'm going to say adding negative constants that day. It might be yelling because the to-date is today and there is no data. Let's go ahead and try that one more time and we should be getting some data back and boom, we get our data because our today's needs to be prior to the current date because the market isn't even open today, given today is a weekend. And even if a was, we wanna get yesterday's data so close that we get all of these numbers back. They're great and dandy. But let's go ahead and make things a little nicer. Because if we jump into our market data here, when we went to render this on a graph or on a chart, It's just not formatted in a nice way. So what we want is we want to create a struct, which is going to represent what we call in the financial world a candlestick. Now a candlestick is going to have a high, which is a double, a low, a double, a open. Once again, a double and a close. And we also want to have a date that's tied to this data. So we'll create a date just like that. And you might be wondering what we're gonna do. It's pretty simple. We're gonna take all of these arrays that are linearly equal to each other. And instead of holding the data like this, we're going to create an array of these from that data sorted by date and then return it. So here I'm gonna go ahead and say candle sticks. And this is going to be an array of these candlestick models. And what I can go ahead and do here is I can say var results is going to be an array of these candlestick models. We're going to return set of results here. And in the middle here I'm going to say for index in 0 up until open dot count. And we can get all of this information. So for the results, we're going to say go ahead and append a model and the date we'll come back to in a second. But we can do the rest of these pretty simply. We're gonna go ahead and say from the high get the current index from the low, get the current index from open current index. And finally from the clothes get current index. And how do we get a date from a given time interval? We already have the time interval. So I'm gonna go ahead and say, we want to get a date time interval since 1970 and we're going to pass in time intervals or timestamps, I should say, with the given index. Now that we have a fully constructed array of results, what I'm gonna do is we're going to say, let's, sorted is going to be results. We're going to say sorted by, and we're going to say return this in a sort by the date. So date is less than dollar 1 dot dot dot. So we're comparing iteratively one day to the next, and then we'll return sorted data just like that. And just to make sure we're getting the most recent as the first element, I'm going to print out sorted data at position 0. So we can actually see what we are getting back. And actually I'm going to drop the other print in the AppDelegate so we don't get that monstrosity of stuff being printed out. Go ahead and give your app a run, and let's make sure we're getting something printed out. Let's see if we have any issues. Like we have a warning here, which I don't particularly care about, so we'll just cancel. And let's see, let's see, let's go back to our model. And let's see, we're not seeing anything, prints it out yet because their app is to launching, so bear with it. So this data is the most crucial part of this app because we're going to filter and sort this data. It's a plot onto a graph to actually see market data. We're also going to filter it out to see other information, et cetera, et cetera. So we're actually not see anything, prints it out. And the reason is, is because I forgot to actually print it out. So here we want to present results. So actually went to print results success case wherein they gets some data. And we're going to say candle, Let's, candle sticks is going to be data and we're going to get those candlestick models off of them. And otherwise we might have a failure in which we're going to print out the error since we don't care to handle it at the moment. So go ahead and give that a run. And we should see the first object in that candlestick array being printed out as soon as our application launches. So bear with me here. All right, so we see candlestick. Here is the date, 2021, June 25th, which is last Friday before. I'm recording this, which is the most recent market data date. So this is looking pretty good to me. We can get rid of this API call and we should it be good to go. So now it's a matter of actually calling this API from a variety of locations in our app. So of course, when we want to render a graph or when we want to populate our watch list, et cetera, et cetera. So what we can actually do before we wrap it up here, we can jump into our controllers and you can imagine where we have called this function it to setup a watch list of data. Maybe we can say fetch watch list data, so it's a little more accurate. In this function, we're going to fetch watch list data for every single one of the symbols. So I'm going to create what we call a dispatch group. And a dispatch group is going to allow us to concurrently go and fetch this data for each of the symbols. And then once we're done fetching all the data, we can try to reload the table and render the data. So I'm gonna say Group dot notify on the main thread. Once everything is done, let's try to offer time. You want a different version of that function. We want to notify on the main queue. And we want to come in here and we're gonna say weak self in. We'll say self.name tableView, reload your data. And let's see what else we need reloadData, that's what I'm looking for now in here, what we actually want to go ahead and do is fetch data, market data. So I'm going to go ahead and say that we actually don't even need this year. We can actually go ahead and say API color shared. And we want market data for a given symbol. Here is the completion pretty simple. In here we're going to say grouped. I'll leave basically once we're done executing this call and we want to switch on the results. In the success case, what I'm gonna do is we're going to get the candlestick data. So we'll say candlesticks is going to be our data dot candlesticks. That's not what we want. Candle sticks just like that. And the failure case, we're just going to print out the error. Now what do we actually want to do with this data? We actually went a hold of it in that dictionary. If you guys remember, I had set up here, we have a map and this is a map of the symbol. And now we can update it to an array of candlestick objects. And each of these represents basically something that we can plot. So now what we can actually go ahead and do is we can assign that dictionary because we have the data back here. So we'll say weak self here. And inside of this I'm going to say self dot. We have a map, which is our watch list map for our symbol. Assign the candle sticks, just like that. And boom, we shouldn't be good to go. Let me go ahead and drop the print in this candlestick thing that we added so we don't see that verbose print every single time because it's an, uh, get annoying really fast. So we'll go ahead and drop that and we should be good to go. So that's the end of this part. We still need to hook up this actual data to our watch list and render out the actual cells. The cell setup should be fairly straightforward. And then in the next sections we're going to start working on the details screen, the chart, all the really nice UI aesthetic stuff that you would expect in a stocks app. So thanks for sticking around. Thanks for watching. I'll see you next part. 21. Watchlist Cell & ViewModel: What's going on, guys, welcome to the next part in the watch list section. In the last part, we set up actually fetching a bunch of market data formatting the model, as well as making those API calls from our watch list controller. In this part, we're gonna set up our watch list cell and start to create those cells and render them with the data that we're fetching via its view model. So that said, let's jump right in. So what we're gonna do is we're going to start by opening with the views folder and I'm going to create a new file in here. It's going to be a Cocoa Touch Class, and it's going to be a subclass of a TableView cell. I'm gonna go ahead and call it a watch list TableView cell. And similar to the exercise that we did with the news that TableView cell will go ahead and start talking about the pieces that will want in here right after we created the identifier first and foremost, I'm also going to go ahead and create a preferred size will say preferred height is going to be CGFloat. Try 60s you how that looks and we'll adjust as needed. Let's go ahead and do our standard overrides. We're going to override the initializer with a style and a reuse identifier will also wanted the required initializer override with a fatal error in there, but wants to lay out all of our subviews once we have some subviews, the layout. So we'll say layout subviews will want to prepare this cell to be reused, prepare for reuse to psych vats. And most importantly, don't forget that we're going to want a public function which is going to allow us to configure the cell with a view model. So we'll go ahead and create that view model in a quick second. What's going to be local to the file is going to be its own struct or save your model. And we'll add some properties in here in a moment. So that'll said and out of the way, what do we want in the watch list cell? So let's, let's just list it out. I like how we've been doing it. So we're going to want a symbol label. We're going to want a company label. We're also going to want a mini chart view. We're going to want a price label and then we're also going to want a change in price label. So basically we're going to want a couple labels, a chart view and a, and that's it. A char view and for label is actually. So let's go ahead and start creating these. Now, the layout of this will be fairly interesting. So do stick around and stick with me and then we'll get through it together. So first up we've got a symbol label. We'll go ahead and say private. Let symbol label will be a UI. Label is what I'm looking for. Just like rats will go ahead and say this is a label, returning label. And let's see what else we are going to want to do. So on this label we can go ahead and set a larger fonts. So I'm going to say here, maybe this is system fonts of size perhaps 15 with a weight of medium. Again, play with the weights and sizes as you see fit, various objective. We'll make this one regular and make sure we rename this to a name label. We'll skip that chart view for a quick second. We're going to make the price label. So this will be the price label. I'm going to make this sky regular as well. Maybe we'll adjust that if we need to. And then we'll finally add the a price label looks like I, this one. So it would be the change labels. So this will be the change label. We'll just drop the word price here so it's not confusing. And let's see what we should be good to go. Now, the other thing I wanted to do here on the price label or the label I should say we're going to make the text color explicitly white. The chains label is going to be the green or red colored squared icon label, which is going to show, you know, how many percent the stock is up since previous, close or down. So we're going to basically take a look at how we can color it appropriately as well as have the text to be white, such that it's always white on green or white on red. So cool. So now that we have all of this, we also need that chart view. Now how are we going to create a chart view? So we're going to create the chart in another section, but we're gonna keep an abstracted such that we can create it very easily. So let's go ahead and create the view for that. It's going to be a subclass of the UI View. And I'm going to call it a stock chart view. We'll go ahead and create it and drop it in like this. And at this point, at least we have at our disposal to go go ahead and play with it. I'm gonna go ahead and override the initializers should be in it with a frame. We're gonna go ahead and say super and it's with that frame. All at that required initializers, try that again, required initializer fatal error. And then of course, just like any other view you guys know the drill. We're going to watch a layout subviews. Now when we lay it out, we're basically going to where all of our stock stuff, but for now we don't really need anything. But now that we actually had this here, we can jump back to our watch list table view cell and it here, I'm going to go ahead and say privates. Let's mini chart view is going to be an instance of our stock chart view just like that. And we can start adding it as our subviews. So here I'm gonna say. Sub views. We'll go ahead and add all of our subviews in here. Let's just start with the labels. I'm going to go with the symbol label, followed by the name label, followed by the mini chart, and then the price. And then lastly the chains label. Let's work on Prepare for reuse. And that's fairly straightforward with the labels. At least we're gonna go ahead and say prepare or they're not prepare for reuse. We're going to say symbol, label text is going to be nil. The name label text is going to also be nil. Next up, the price label text will be nil. And lastly the chains label text will be nil. For the mini chart, that view, we're going to want to add a reset function on it that we're going to build out later on. But just so we don't forget to add it, Let's go ahead and add a reset function on here. And this should reset the chart view. So cool. So now that we've got that out of the way, Let's start taking a look at the ViewModel, but we're going to want in there, Let's make sure this reset function gets picked up. Looks like it did beautiful. So basically our view model here should give us a bunch of information. First and foremost, it should give us a symbol. Pretty simple. Next, it should give us a price. And this should be formatted because our ViewModel is responsible for that formatting business logic. That then in here you can either put the color price directly or you can specify whether the price of the stock is up or down. I'm going to say change color. And we're going to put the color in here, red or green based on, you know, how the stock is doing. We're going to also go and say change. Percentage, which is going to be a string as well, needs to be formatted. And let's see. We want in here the company name, which is pretty bare bones and simple. And this I believe should be everything. So we want this and that. And then we're also actually going to want one more thing in here that I'll leave empty for now. And this is going to be a chart ViewModel. And the chart view model is going to be the stock chart view dot Vue model. And we haven't created that yet, so we'll need to come back to it. But just so you guys are aware that this ViewModel will also hold the reference to the other view model. So cool. So now that we've got this in place, let's talk about actually using this viewModel. So for configure with ViewModel, it's pretty simple. We're gonna say symbol, label, text is going to be ViewModel dot symbol. Pretty simple. We're gonna say name or label text is going to be ViewModel.com name. The price label text is going to be ViewModel, you guessed it a price. The change, the label, change the label text is going to be ViewModel, top price change or change percentage, I guess we'd call that here. And let's see. The last thing that we want to do here is configure the chart, which we'll do later on, but we want to make sure we set the background color so we're going to say change the background color is going to be ViewModel dot change color. So now that we've got all this in place, it's time to start weighing everything out. So the layout in here is going to get a little wonky. So just bear with me and we'll get through it. But before I actually even lay anything out, Let's jump back into our controller and start creating this view models from our data. So we already have this function here which is fetch watch lists data. And once we fetch this log, watch less data, we have all of our models presumably in our watch list map, but we want to create view. So I'm gonna go ahead and say self create. And we want to do this before we try to refresh our TableView, because we need remodels presumably for that TableView. So here we're going to say private func creates a few models. And any here what we want to go ahead and do is we want to create this view models from our dictionary. So it gets a little strange. So let's go ahead and do it together. So for symbol and candlesticks in watch list, map is what we've called it. Let's also create an array for our ViewModel. So I'm going to say var view models is going to be an array of watch list, TableView cell, ViewModel, which will be empty by defaults. At the end of this, we'll say self.view models is view models. Let's make sure we go up here and create an array for this. I think we created it as strings at the moment, but we want it to be the appropriate type now. And in here we wanna go ahead and say vi models dot append. And we're going to instantiate one of these ViewModel for each of these. So symbol is pretty simple. We've got symbol, which is symbol, Elsa, sort of line breaking this stuff. So it looks a little nicer. So now that we have our market data, we actually want to get some of this other information by parsing this candlestick market data. So let me just say a line, break it to make it look a little nicer. So company name is pretty simple. What we're going to go ahead and do is we're gonna say user defaults, UserDefaults. Let's try that again. User. Defaults standard and we want to get a string for the symbol. If you guys recall, our Persistence Manager saves the company name as the symbol C0. And if we don't have, when we're just going to say company. Next step, we want to get the price, but we want to show it as a string and we want it to be formatted as well. So how do we, how do we do this? So we could create helper functions, but we want to get that out of this candle, stick a ratio. So what I'm going to go ahead and do is create some helper functions down here. Otherwise it's going to get a little messy up there. So I'm gonna go ahead and say private func gets the latest closing price from data. And this data is going to be an array of candlestick models. And this is going to return a string to us, and now that string needs to be formatted. So here on this line we can save gets latest closing price from my candlesticks. And what we basically wanna do it here is pretty simple because our candlesticks for already sorted, we want to get the first element from here. So from this we can save data dot first, dot close. That is our closing price. Now it is going to be a double. And here we can return basically an empty string if we aren't able to get that data. Now we're just going to return at the moments the closing price. And you're going to notice that it's not formatted with any commas or decimals or things like that. So we'll talk about formatting and just a moment. All right, so there is, that's the next thing that we want is the change color. So this one is a little more difficult to do. We want to get the change percentage first. So right here, I'm gonna go ahead and say change. Percentage is going to be get change. And we're gonna say get changed percentage for. And I'm going to pass in this candlestick data. And this one is a little tricky to calculate because you don't want to arbitrarily get the change in the percentage of from the previous candle stick model. In other words, you might be thinking I can just grab the last or the first element and the element right after it, do a comparison and return the difference. You can't actually do that because each candlestick does not represent a single day. One day can have multiple candlesticks. In other words, what we wanna do is we want to get today, which will be dates. Now from this we want to get prior dates, which is going to be dates, adding a negative time interval. And I'm going to take a day which is 3600 times 24. And multiply this by two. So basically we're going to get the difference of a day. So two days in the past, basically. So let's go ahead and just make sure our parentheses line up here. This math part, I swear is the only math heavy part. And then we'll get into some of the more fun rendering stuff. All right, so now that we have today's date and a date from two days ago, well, we wouldn't do is get the closing date or the closing price for both of those dates. So how do we actually do that? So the first one is pretty simple. We can actually get rid of this. We can say this is latest close, which is going to be data dot first dot close, which is pretty simple. The next thing that we wanna do is we want to get the first element in our candlestick collection where the date is the same day as the prior date we've calculated. So let's create that code. I think it's easier to understand and the code. So we'll say prior close is going to be data. And we're gonna say get the first element in the data collection where the date matches. So in here, I'm going to go ahead and say calendar dot current. And there is a is same as, same day as another date. So what we care about here is dollar is 0 dot date is going to be same as prior date. So once you go ahead and do this, we'll get that data out and then from that object we want to get the closing price. So what I'm going to go ahead and actually do here is let's print out our, our two closing prices here and we'll see if we end up getting something, something useful. So let's see what's going on here. This is yelling at me because This should be a part of a guard statements. The first one does not need to be, but this one does. And we have the else statement here. So let's see, closes going to be this. We've got two warnings. Let's go ahead and print both of these out. So I'm going to say current is going to be latest clues and then we are going to have a prior, which is going to be Friar, not prior date, but rather prior close. So let's go ahead and drop that in there. And that will basically calculate the change here. And this is pretty interesting because let's actually, Let's actually have this return a double. So what we're gonna do is we're going to use that double to format the actual string. But the reason we have a double shear is we can say if the double is below 0, we're going to say show it as system read it. There was a loss and the stock, otherwise show it as system green. And here you can just pass this in like so. So this part does get a little confusing because of all the calculations, but I promise, bear with me, it gets a lot cleaner. So once we've done this, we can return that there. And here we can actually go ahead and just return 0 for the time being or returned to 0 dot 0 maybe for the time being. Because we wanted to give it a run and make sure that we actually see the difference of our two numbers here before we calculate the percentage difference. Because if our calculations are wrong and a lot of our users will be quite upset. So let's go ahead and give this a run here. And we should see our print statement here getting kicked off. So we'll see a couple of our API calls and there are all of our prints. So the current is 44 and the prior was 44, 25. Notice that this is 0.17 and this one was at 25. This one is 330. I think this is Facebook when $0.11 prior, and the prior was 344. So it looks like Facebook went down a little bit and let's see what else we've got in here. So 260, Let's see. I believe this one is Microsoft and the prior was to 65. Well, let's make sure we are calculating all this correctly. So this dates is adding time intervals. So this one gets the prior date. So we're taking the current date and subtracting two days from it. This one gets the latest close, which is the current close. And this one here gets the first model where the prior date is the nth date and the clothes. And what I'm going to go ahead and do in here is also pass in the symbol. So we'll go ahead and say symbol is symbol. Data is data because I'm curious a print outs to make sure that data actually matches what it should be. It will say symbol is a string. Because of our calculations are incorrect. We really screwed something up here, so we'll say symbol. And let's see what else we need to do. What we want to end up returning here is the prior divided by the latest, so not the prior date, the prior close divided by the latest close. So go ahead and give that a run and let's see what we end up getting. I'll re, it looks like we have an error when I screw up here. So let's see, we want to pass in a symbol. Let's try to call this function here. It's because up here this is not the appropriate thing that we want to be changing. We want to change the actual coal which is sitting up above here. We'll go ahead and change this here I'm going to say passing in the symbol and the data for the data parameter. And this guy needs to get changed to the price. This one we don't want to change, we'll just change this back chains, the wrong thing there. And let's try that one more time. So we want to say candlesticks. Go ahead and give that a run and let's see what the respective prices are down in our print statement. Right? We're still running and there are all of our changes. So let's go ahead and take a look at Microsoft here. The current price is 260 and the prior price was to 67. That does not seem correct. I'm going to open up a stocks app right here and we're gonna take a look at what we are getting and what the expected output should be. So the current price is actually to 65. So let's see what's going on and why we are getting that. So the first M and a print out here is going to be the first dates. So current, I'm going to go and print out our data at 0 dot date, just like that. And for this one I'm going to also print out prior date so we can actually see which dates the data is coming from. Because either the data from the API is incorrect, which I'm 99 percent sure is not the case, or our calculations are incorrect. So let's go ahead and search for Microsoft in here. Since I've got that one open, Let's see, Amazon. So current is 46, 21. Okay, so that's a problem. So this is the price from June 21st where a week past that. And let's see, the prior is 625. That's not good because the prior should be a data before what we're looking at here. So I suspect one of two things, I believe we might be calculating our dates backwards. So let's go into our models. Specifically, we're going to jump into our stock market data here, into our candlesticks. And we're going to flip the order that we're returning here. So I'm gonna say $1 dot data is greater than $1.1 dot date. If we go ahead and try that one more time, we should see that the current date is always greater than the prior recalculate. So let's take a look at any of these. We'll stick with the Microsoft example. And the current is 625, which is the most recent closing date, which is correct. The price is 26502 prior, we're getting 625 and we are getting the exact same price, which is not what I would like to do. So what I'm going to go ahead and do now that we're getting actually the dates in the proper order. But we want to actually do is we either want to subtract the we either want to subtract two days for the prior date or get yesterday or three days or yesterday. And the reason I say that is because today, for example, is a Sunday. And what's happening is because it's a Sunday when it subtracts two days, what it's doing is is once again getting Friday's date. So that's not actually what we want to do. So one option is we can get the latest date and we can just verify it's not the same day. So let's try doing that. So what I mean by that is we're gonna say dates is going to be from our data, the first element dot date. And what I'm going to see here is get the prior close. It's where the dollar is. 0, date is not the same date as the current state. So here we can maybe actually called this latest dates to be a little more, little more accurate. So we're gonna get the first element that doesn't have the same date as the currently the state symbol will put latest date here. And this one will be prior date. Let's go ahead and give it a run and see what it looks like. And maybe I'll split this video into two different videos, since it's getting kinda lengthy. Already. It looks like we have an error here. We're getting a prior date. Let's see. So we're actually getting a prior close at this point. So we can actually get rid of this here. Rather this year, I should say, go ahead and give it a run and let's see what we get. Ray, bear with me. All right, so we've got a bunch of data down here. Let's take a look. So the current, which is June 25th, last closing date, which is 265, and the prior is 266, 98, which is in fact correct. The stock has gone down between Thursday and Friday, so we are definitely getting the accurate prices here. So now we want to return the difference. So I'm going to say the difference is going to be this. We're going to return it's, and I'm also going to print out the symbol and the different in a percentile. So go ahead and do that. Let's see what that looks like. We expect to see a decimal awfully, right? So here we are, Here are all the changes and we have gotten the differences. So let's find Microsoft should have been a negative. And the reason that it's not a negative is because we need to subtract one from this. And that'll basically give us the proper difference in terms of the delta. So in other words, if we go from, let's say the current price is, It's also the prior price is 267 and the current price is 260. We wanted to get the difference and percentile from the seven to the 260. So if we take a look here, we know that the Nikkei Stock to not go up 98%. And we also know the Microsoft stock did not go up 0.007, 1%, it actually went down 0.07%. So in other words, what I'm going to go ahead and do here is take the difference of this and simply subtract it from one. So we'll say one minus. The difference here, and let's take a look what we end up getting. All right, Bear with me, bear with me. All right, cool. So here we're seeing that Facebook went down 0.06%. Not everything should have gone down. In this case, slack and Pinterest are both in fact up. Looks like Amazon was also demo so that tech stocks weren't in fact down. Snapchat was up 0.1%. And let me just open up Maya stock apps and verify all of these calculations and we hopefully should be in good shape. So let's see, Apple should be talented as well. Let's take a look at what Apple's giving us should be 0.02%, which in fact it is beautiful. So now that we've got these negative double numbers here, what we wanna do is we want to actually convert this to a string instead of passing it in like this. And the reason we want to do that is because it is the job of our view model to actually do those conversions before we get to the stage of supplying or view with the various properties. So now that we have this here, we probably are calculating this correctly, right? If it's less than or equal to 0 or less than 0, it'll be System read. Otherwise it'll be System green. Now, in the change percentage, we don't wanna do this. What we are going to do is we are going to use something called a number formatter. Where are we going to put the number formatter? We're going to stick it into extensions similar to how we extended the ImageView here. And then we also extended the date formatters. I'm also going to extend the number formatter here. So we'll go ahead create an extension off of number formatter. Now the number formatter we want to have to formatters. The first one that we want is going to be a percent for matter. And this one is going to do basically what the name implies. We're going to create a percentage out of a given number. So we can go ahead here and we can say let formatter is going to be a number formatter. We're going to return this guy here and we want to set a bunch of properties on here. First and foremost, the locale is going to always be the user's current. Now there's going to be a number format or format style, I believe is what it's called. Let's see if we can find it. For a matter wave. Let's see, let's see. So there should be a style off of here. Yep, a number style. We care about a percentage. And for the formatter, there is a way where you can specify the fractional digits, the maximum fractional digits we care about to fractional digits. That's how we do that. The other format that we aren't going to want here is going to be a simpler number formatter. I'll just call it number of formats. Formatter. Its style is going to be a decimal. The places that we wanted to once again will be 2. So this will be fairly straightforward, but we're going to add one more extension into the string here. So we can call this with a simpler, simpler formulas. So we can say static func. We're gonna go ahead and say give me a percentage from a double. And this is gonna give us a string back. So we're gonna first and foremost create the formatter will say formatter will be number formatter, dot-dot-dot the percentage formatter. And we are going to return for matter. And we're gonna say Give me a string from a particular number. It'll be NSNumber, value will be our double that we have passed in just like that. And I believe this return to optional. So let's see if we need to coalesce it. If we do, we can make this a optional or we can go ahead and simply coalesce this, the default value passing in the double, just like that. So let's see, I think we should be good to go with this function. We need one more here. And this next one is going to be a formatted number. And once again, it's going to take an a double. This is going to be a number formatter. And similarly, it's going to use the formatter to derive a string from the past in value, which in this case we've called number just like that's otherwise we're going to pass back the number in a string. So go ahead and hit Command B. We just did a ton of work. Let's see if everything is building and nothing is broken. If it is, I'm going to print out the view models we have to this cobbled together and I'm going to create another video after this too, so we can reduce the size of this video since it's gotten pretty long. So once we've created all of these view models, I'm gonna go ahead and print out all of them so we can see them in action. Make sure they're looking. All right, it will save you models here, add some line breaks, go ahead and give it a run, and let's make sure we're printing out appropriate view models. All right, Bear with me here. Whoops. Looks like we're seeing a bunch of things being printed out there all over view models. So let's go through this. We see Pinterest company name is Pinterest. The price is 76.5. Notice the decimal is properly formatted. The change color looks like it is a, let's see, let's see system green color because it is in fact up, it's not a negative change percentage, looks to be 0 points, some super long number. This is not good because this is not formatted. So let's start using our formatted numbers. So instead of using all of this here, what we once is in our actual change percentage, This guy's a double, so I'm gonna go ahead and say string. And from the string we wanted to get a percent percentage from a double, just like that, so we can do that. And also for the price function that we have created here, instead of just returning the price like this, we can go ahead and say string dot format ID number, passing in the closing price, just like that. And we should hopefully be in much better shape. So go ahead and give it a run once more. Let's make sure we're seeing our data formatted in the appropriate ViewModel styles, and then we'll wrap it up. All right, So there is all of our data. Let's go ahead and find the change. So there's a change color right there. Change color in this case, the system red change percentage is negative 1, 35 per cent. So the stock has gone down 1% since the previous close, which looks correct. Look at the fact that we also have commas in here. So 3400 for the price of Amazon, which is correctly formatted and having these commas and just like decimal places, just makes everything look a whole lot nicer. So you definitely want to make sure you're using for matters and not just trying to like add the commas manually because a that's not the correct way to do it and be your commas might go in different places depending on the different country that your users are working with. So just be mindful of that. That said, this video is gone long enough because of all the math that we had to do here. So I'm going to call it wraps for here. I'll see you guys in the next part where we take this ViewModel and we actually lay out all of those views and we hopefully start to see ourselves. I'll start, I'll see you guys there. 22. Completing Cells: What's going on, guys, welcome back to the next part in our section. And the last part we started to go deeper into the view models for our watch list, particularly some calculations, converting our model to the ViewModel percentages for matters, all that good stuff. In this part, we are going to wrap up our cells and specifically working on laying out the cell and rendering these view models that we've put together. So without further ado, let's jump right in. So we had already created or view models here and we're assigning or view models just like that. And then we refresh our table view. So let's go ahead and take a look down here at our TableView code and let's make sure we're using the proper models, view models. So we want to say view models that count. Let's see view models dot count for number of rows for the particular cell that we want to dequeue. We want to make sure that we come up here and register the appropriate watch list, TableViewCell. So I'm gonna go ahead and say register a watch list, TableViewCell dot self for watch lists, TableViewCell dot identifier. And now all the way back down here, instead of doing this, we can actually dequeue the appropriate cell. So I'm gonna take our left cell is TableView DQ, reusable cell with the watch list cell. And this is going to be index path. We're gonna make sure we cast this as the proper cell as well. Let's go ahead and line break all this stuff so it's a little more organized. We'll say fatal error here in case we are unable to cast, this should never occur. Then down here we're gonna go ahead and save return to sell. And we're going to configure it with a given view model. And the way we get that is the nth ViewModel in our view models collection just like that. And now what we wanna do is let's actually give it a run first. What we wanna do is we want to lay out it's everything in our watch TableViewCell. We are passing in the data successfully. We have created our views. They're primarily the labels, no chart yet, but we want to actually render it. So let's see what's going on here. So I'm not actually seeing these particular cells is should show up in terms of being selectable. Let's say a height for row at index path, we're going to return the preferred heights off of our cell which we had previously created. Let's make sure we're adding the table view as a subview, which I believe we are. My hunch is we forgot to give our tableView a frame. So what I'm gonna do is I'm going to override view did layout subviews cause super view did layout subviews. And we're gonna say TableViews frame is going to be viewed our bounds. So now if we go ahead and give it a run, we should see at least the lines for our TableView, the separators should at least be visible. And they are. So we can go ahead and actually even select these. Now we just need to actually lay out all the content on here. So let's go ahead and do that. So I'm going to jump into the views folder. We're going to jump into the table view cell here. Let's start laying this stuff out. So the first thing we're gonna do is lay out the symbol label are gonna say size to fit. I'm going to say size to fit actually for all of these. So we're gonna go ahead and say symbol, label size to fit, name label size to fit, the price label size to fit. And if you're not familiar with size to fit, it actually self sizes the frame to fit the cell, the, the labels are textContent. So it's a good way to first get started when you start laying stuff out. So the next thing that we are going to do here is we're going to lay out to the symbol and company label, company name label on top of one another. So we'll say symbol label is going to be, It's frame is going to be x will be separator insets dot left the y, we'll do in a moment, the width of this will be simple labeled our width and the height will be the respective heights. And the way that we get the Y offset, we're going to say y start is going to be CG floats. And what I'm gonna do is say content view, dad height, that height, subtracting the symbol label heights and the name label height divided by 2. That way it'll vertically be centered. This will be y start and will start to copy and paste some of his stuff. So the next one will be the name label. And the Y here is going to be symbol label dot bottom. So if we go ahead and actually before we even give it a run, let's, let's do the rest of this stuff so we can see what things look like. So one thing I forgot to do and down here is actually configure the chart. We'll do that later on. But just to, just to call it out, we still want to lay out the chart view even though we're not going to see a chart in there. So. Let's next layout at the price label and the price change labels. So this one is going to be fairly interesting for a price change in price label, we're going to say frame is going to be, once again, x is going to be content view data width minus the padding, minus the price label width. And the y is going to be something interesting, similar to what we did up above it just a second here. The height and width are pretty simple. We'll do this, start with this that hides the wire. Let me just temporarily make it 0. And you guys will see why this calculation is going to get a little more interesting. I keep saying that, but you'll see it firsthand. Let's go ahead and tweak this. And that's tweak that. And this is going to be price label bottom, just like that. And these are our four labels. Now, we still need to layout our chart, so let's do that. So I'm going to say our mini chart view dot frame is going to be x and y. We'll do in a second. So the width I'm going to actually save this is content of view dot width divided by 3 via heights is going to be content of view heights subtracting 12, the y will be six, and this is going to be the rice label left subtracting for the x, the width which is going to be content view dot width divided by 3. Subtracting maybe five or six for a little bit more padding and buffer horizontally. Now, I'm also going to set a background color on our actual chart view just so we can end up seeing it. Let's go ahead and do that. Otherwise, we won't actually see where it is. In fact, rendering, so is a good idea to set a background color. So here we'll go ahead and say chart is going to be this, going to return it here. Just like all of our other subviews. And what's let's go ahead and make sure we set what we came here to do, which is a background color. I'm gonna give it a link background color. Go ahead and give it a run and let's see what's going on. I spelt a chart and correctly. And you're going to notice a couple of things that are off that will need to clean up. And particularly I'm focused on the right side of ourselves, the price and change percentage labels. All right, so here we have it. So we have our symbol on the left. We see our company name which is getting truncated. So let's fix these up. So the company name should not be getting truncated. The name labels should have the height for itself and its own width. So that's a mistake and our copy and pays pretty simple. But the biggest thing that's off here is the width of our green and red labels here is different between different rows. Now, obviously it makes sense why they're different. It's because the size, as we go down from, let's say first we started at Pinterest and Google. Google here we have negative 0.222% where we don't have a negative in the first cell. So naturally the red label in this cell, we'll be at wider than the first one. But if you ever use an apple's app, you notice that the width is consistent for each of the rows and then look symmetrical and really nice. So how do we achieve that? Well, basically there's a couple of ways. The simplest way, which we're gonna do today is by keeping track of the maximum height that we have come across in our particular row. So we're going to keep track of it on the watch list view controllers. I'm going to say static. Var, max, change. Width is going to be a CGFloat, and by default it's going to be 0. And whatever we set this, what we're gonna do is we're gonna say TableView, self.age, TableView. It's if I could find it. We actually can't reload it from here, so, well, we'll talk about how to actually update the cell in a moment here. But once we actually go ahead and do this, once we have the statically set here. What I'm gonna do in the actual view is we're going to calculate the width relative to the prior width. So I'll tell you guys what I mean in just a second. So first of all, the width of the change label and the price label should be equal. So we're gonna say current with is going to be the watch list of view controller. And we're going to get the max change with alphabets. And essentially, what we're going to actually do is reading it the maximum between a couple of things. First, we want to get the maximum width between either the price label with or the change label with. And then we went to compare that to the maximum current running with that we're holding. And what this is going to allow us to do is we're going to be able to calculate those with. Our between multiple cells. And what I'll do here is we're gonna say, we're gonna say if this new width that we've calculated is greater than the static width that we're holding. Well, we're gonna go ahead and do is we're going to update it. So I'm gonna say this static width is going to equal our current width. So let's go ahead and run this and see what we end up getting. So there's still one more problem with this, which really high as we'll see in just a second, but we'll address it. All right, so we see that the width from this first one, this is this wide and the next one is this y. And as we continue down, what you'll notice is this red one, it got wider, this third row, then this one matched it in terms of width. As we continue down, it looks pretty good. There's a couple issues I see. First I see some inconsistency between the prior rows because rho 0 here, the first row was created before this red one. Once the width got updated in this index to the third row, the prior rows need to be updated. So we can do that with a Delegates. We can do that in a couple of different ways. But first of all, the one thing I want to go ahead and change here is the with the x-coordinate of the mini charts, are we going to say this is the instead of price label dot left, this is going to be the difference for the current width. So what I'm going to go ahead and do here is we are going to say, let's see if I can get this calculation rights. So this is subtracting based on the width here. So we want this to be with, and this to be width as well. So I'm going to say take the current width. And actually this calculation should be the same now that we've actually gone ahead and change these calculations should be correct now. But I'm gonna go ahead and do is we're gonna create a delegate for this cell and we'll work on optimizing this later on. Some of you might be wondering, Well, hey, why do we want to refresh the rows every time we find a different width, you guys will see momentarily, we'll say did update max width. And we're going to want to have a delegate on here. So we're gonna go ahead and say a week var delegate did update. Max width is going to be called every single time that we update that width, which should not be very many times. So it will come into this if block. And once we have updated it, we're gonna say delegate did update max width just like that. And don't forget that you actually need to assign this delegates and the watch list controller at the very bottom where you create the cell before returning it and make sure you assign the delegates and conform to the delegate respectively. So this'll be a Watch List View Controller or watch list controller. Let's see what I called it. And we want to conform to the delegate. And here I'm gonna say did update max width. And all we're gonna do is say TableView, go ahead and reload yourself. Now, one optimization we can make is to optimize only refresh rows prior to the current row that changes the max width. In other words, if we are on row number three, we don't need to refresh everything, including row three. We just need to refresh everything prior. So if we go ahead and give this a run now, I expect to be sizing horizontally and the width to all match up. So if you look at that, the green, the red, the green, they're all equivalent. We want to right align these labels and these blue boxes are going to actually contain the chart for our specific stock that we're looking at. That's where the chart view is going to go. So cool, We're looking pretty good. We've got our watch lists here, we see the current price and we also have the percent change. I'm going to be a little nit-picky and we're going to stylize this a little better, and then we're going to basically wrap it up. So back in the watch list table view cell, the first thing that I'd like to do is in this change our green or red colored label. One thing I want to do is round the corners. So if you ever look at Apple's app, everything is a really nice border and a corner radius. So we're going to do the same thing here. We're going to make it very subtle. It's going to be six. But to the Kenai you will be able to see it's, the other thing I'm gonna go ahead and do is set the text alignment on the change label as well as the price label to be right. That way this doesn't look so weird like this. And let's see. The other thing I'd like to do is maybe bold the symbol. So here the symbol is already set to medium and it's 15. Maybe we can make this size 16. And let's see what that looks like. We might need some bump up the weights a little bit more. Media might not be enough. This is a little subjective to your liking. It this points. But what have you? We can take a look at what it looks like and we'll need to come back to this blue, this blue colored empty chart. So this is NVIDIA inch, looks like we have inch somewhere in our code. So let's go ahead and get rid of inch, because that's not a deaf deaths are a real thing. So we'll come into inch here and I'll just get rid of this guy. And just to make sure our app actually works in terms of persistence, let's go ahead and delete this app from the simulator and we'll give it a fresh run and install. And this should account for setting up a default watch list. All right, Bear with me, bear with me. We should see our default list. It should fetch all the data. It should bring it in just like that. So looking pretty good. Now the other thing that I want to quickly go ahead and do, it's a little bit out of scope here, but it's somewhat relevant. This stock charts view we didn't have creates yet, but we are going to create in a different section. But one thing I want to do is create the view model for this. So in a given stock chart, we want to be able to configure three different things. One is going to be the actual data, which is going to be a collection of candlestick data. The next thing that we want to go ahead and do is have a Show Legend and bool. And we also want to have a show axis, bull. And this should be a bool here like that. And this'll basically you can figure our actual, it'll configure our actual chart view here. So I'm going to say func configure with ViewModel. This will be for your model just like that. And the reason I wanted to create this here is because we can jump back into our watch list TableView cell. And I'm going to tweak this as well here. So this is going to take in a char to ViewModel. It'll be a chart view model just like that. You're gonna start to see that we're going to have an error now over here because we need to pass that chart view model. And so let's go ahead and hit Fix and I'll bring it on in forests. And we're going to create this here. So we need a pass in respected data, respect, respect to data for the stock we're looking at. So we're gonna look at pass in the candlesticks. We also don't want to show the legend for the watch list. Otherwise the little chart is going to be way too busy. But there's one other thing that we're going to want to do. We're going to want to actually reverse the data here. And the reason is because currently the first element in our candlestick array is the most recent dates. And we want the first element in the chart data to be the oldest. And actually we can simplify this even a smidge more. Instead of taking in the candlestick model itself, all we really need are doubles. And these are going to represent the closing prices that we want to plot on our graph. So what I'm gonna do here is we're gonna say a reversed. And then I'm going to map this to $1 dot close. And this will basically passing that array into our view model. And if you go ahead and hit Command B, you should be good to go. Everything should be building. Let's drop that blue color that we added here on our chart to do wanna see that color anymore since we should be in good shape. Now let's see if I can find it. It's right here. Go ahead and do that. I will say on the chart, clips to bounce is going to be true. I'm going to say clips to balance on our cell here as well, just a precautionary things and make sure nothing bleeds over in case any of our calculations are in fact incorrect. We'll go ahead and assign this to true. And let's see what our watch list is looking like. We should be in good shape and we can move on forward. All right, let's see. Let's see everyone cross your fingers. Hold your breath. We are looking good. The one thing actually, I'm going to nitpick again is this is centered vertically on the left to the symbol and the company name. But on the right-hand side, the height is 0 if position on the y-axis for the price and change. So I'm gonna go ahead and tweak that. So what we are going to do here is for the change label, this is still going to be priced double-dot bottom. But the y for the price label is going to basically be concept view. Heights minus price label heights minus change label height divided by two. And that'll vertically center the two labels on the right-hand side. Hopefully Let's go ahead and take a look. And we should be good to go. All right, look in much better. Now we can tap on it and nothing in fact is happening. We have our watch list here. We also have our news and our app is actually coming together really, really nicely. So I'm a fan, hopefully you guys are as well. That's the end of this part. Hopefully you guys are keeping up with the videos and I'll see you guys in the next part. 23. Swipe to Delete: What's going on, guys, welcome to the next part in this section. In the last part, we finally got our watch list rendering here with all the width calculations and all that good stuff. And in this part we're going to start to add a way to modify our watch list. Specifically, we're going to work on swipe to delete as well as updating our persistence. So this is actually rather simple to do. We're going to jump into our watch list controller where we're going to enable the ability to do these swipe to delete. It's going to occur where our tableView functions are. I'm going to go ahead and add two functions. The first one is going to be can edit row at index path. And edit is a common term that Apple uses for editing style. Deletion is a given editing style. There's going to be editing style for index path and I lied, there's a third function that we actually need and that is to commit an editing style. So we're gonna say if the editing style is deletes, we want to do some stuff. So what do we want to actually do? What we wanna do is we wanna say tableView, begin updates, tableView and updates. And in the middle here we want to update our view models and a deletes a row as well as update our persistence. So what does this actually mean? So our view models are backing our watch list. So this is pretty simple. What we wanna do is say from our view models are remove the element at a given position. So we have the position coming in as the indexPath.row. So pretty simple. The next thing we wanna do here is say TableView. We want to delete rows at the given index path or with a automatic animation. And this is the most important thing here. We want to update to the persistence and we want to remove a element from the watch list. Now we haven't implemented this yet, but basically let's click into where what we want to happen here is we want to remove a particular symbol from the watch list. So I'm gonna go ahead and add a parameter there. And over here, we are going to go ahead and say symbol is going to be from our view models, indexPath.row, the given symbol. They, you might realize that we're removing from the ViewModel up here. So what we actually want to do because the order of these events matter is first update or persistence, then dropped the ViewModel, and then update by deleting our cell from the table. So let's go and implement this guy here. So I'm going to come into here and how do we actually remove a given element? Well, it's pretty simple actually, although we need to do is we, once it creates a new list, which is going to be a new collection of symbols. And I'm going to save for a symbol in watch list where symbol does not equal symbol. And maybe we should say, instead of symbol will say where I'll say for item in watch list. So we don't have contradictory names where item doesn't equal the current symbol. What we are going to do here is we're gonna say new list dot append, item. And then finally down here we're going to say UserDefaults set the new list for constants dot watch list. So all that we're doing here is basically we're creating a new array of strings. We're looping over our current watch list, and we're saying loop over it where the item isn't the symbol that we're trying to delete. And for each of them, simply append. And then once you're done, just save all that back to user defaults and call it a day. And that's basically all there is to deleting something from our watch list. Now the other thing you need to do, which you may already realize is if you guys recall, we were saving right here the name of the company as the value for the symbol C0. So what I'm going to go ahead and do here is we're also going to say UserDefaults set nil for a key symbol. And this will make sure that you also clear out the company name. Now if you didn't do this, the user wouldn't notice, but your unnecessarily saving data onto the user's device at that point, which is a no-no. So we're going to make sure we're good citizens and make sure to delete it. Let's go ahead and give our app or run, and let's see if we can swipe to delete. All right. See, let's see. Bear with me. So we should just simply be able to select the Delete. So let's see, snap. Snap. So we're going to slide over, we get to Leah, we can slide and basically deletes. It will be a slide to delete a couple of them. We could actually press ON delete as well and a delete quite a few from our list here. Maybe it will also delete, I don't know, apple, I can't delete. Let's keep these for us. Keep Google, Facebook, Apple, Microsoft. Go ahead and run your app again. And now you'll notice we shouldn't be getting only those four entries. And if we get more than that, then something's messed up in our persistence. So it looks like we are getting Apple, google, Microsoft, Slack, and Facebook. Let me also delete Slack and let's make sure that we are in fact a leading that one properly as well when I run the app again. So I thought I only had four, but maybe I miss counted. Let's try that. We should have a total of four whom we are still seeing, our five here. So something weird is going on. So it looks like we are in fact deleting it because we swiped in here we can see shows US company. And we've got Alphabet, apple, Microsoft, and Facebook, but we're not getting rid of it from our actual list. And let's see why that is. So let's see, we've got work, microsoft's that Amazon, these are our default ones. So something strange is going on here. So let me go ahead and delete this one more time. So now we should have created a new list where the symbol is not included. Let me find that function again. There it is. Let's go ahead and give it a run. And we should see work not be in that list anymore. All right, Bear with me. Otherwise we need to track down the bug. Probably something silly somewhere. Okay. It looks like work now got deleted. Let me go ahead and delete Google here. And let's see if we give our app or RAD, make sure that we don't have Google in the list anymore. Hopefully weeds you knots, otherwise, we're going to have to go looking for what has gone wrong. Oh no, we still see it in the list. So let's see what in fact has broken because something, something is not good here. So we're creating a new list here. And we're saying For item in watch list where item does not equal symbol. So let's go ahead and see. So I'm gonna go ahead and print out a item per new line, someone to say item. I'm also going to say new wine. And here I'm also going to go ahead and print out. We're going to print out deleting. Let's see, deleting. And we're going to put the symbol in here that we are trying to delete. Go ahead and give it a run and let's see what's happening here. So my one hunch is that we are not passing in the proper symbol to be deleted. So we're going to clear everything in the console. So that might be causing or something else because we definitely still have Google in this list here. So we're gonna go ahead and swipe. I'm going to hit the delete button. We see deleting do, and we have Apple, Facebook, and Microsoft. So let me go ahead and run the app. And now what we should only have those three in the list that deletion prints look pretty correct to me. Okay, so now we have three. So something weird happened that first time. Maybe it's a swipe to delete. So I'm going to swipe to delete Facebook. And we see we're deleting Facebook and we're only left with Apple and Microsoft. So we should only have two elements in here now. And let's go ahead and see are we only have two. Okay, So something super strange is going on. So what I'm going to actually do here is we are going to delete the app and re-install it. And while I'm at it, I'm going to jump into the API color and get rid of the URL prints out here, since it's getting a little verbose, since we know our API calls are working, we'll go ahead and get rid of that and run our app once more. I'm going to jump back into my Persistence Manager. Now we should see a full list of our default values from our, from our watch list. And I'm going to swipe to delete maybe pins here. We'll get rid of that. And here we can see that is deleting pins and it has added all of these other options into our collection. I'm going to swipe to delete. Nike. Would go ahead and do that. And now we're seeing is deleting Nike. We have Facebook and video, google, Amazon, Apple, Microsoft. And these last two here. Let's go ahead and delete some more, get rid of that's that. That's and we should only have after a delete this next one, only three left in our list. So let's get rid of that. And we only have three left, Facebook, Amazon, and Microsoft. Let's go ahead and give this a run and let's validate. We only have three in our list and being very nitpicky about this, but want to make sure that our functionality doesn't have any holes in it. All right, looking good, so we definitely are deleting those those other ones. Not sure why we had a bug in the beginning, but it looks like we have solved it. So that's all right. So that is basically swipe to delete. In the next video we'll work on how you can add to your watch list. That'll also be fairly simple, so I'll catch you guys there. 24. Add to Watchlist: What's going on, guys, welcome to the next part and the watch list section in the previous video, we took a look at the swipe to delete functionality, and we actually deleted quite a few things out of our watch list, which brings us to the flip side of deletion. We want to allow the user to add elements to their watch list. So similarly, we're here in our persistence controller. We want to implement this function here. We expected the color to provide a symbol to us as well as a company name. And just like that and just how we did the deletion right down here. All I'm going to do is essentially append to our current watch list and save that as the new watch list. So it's pretty simple. So we're gonna say current is going to be a watch list. We're going to say currents dot append symbol uppercased. Or we can maybe just use symbol with an expectation that the color will pass the proper one in. And we can say UserDefaults set the current as the key for constants dot watch list. The other thing that we want to make sure we do here is that we set the company name. So we're gonna say UserDefaults set the company name for the key, which is going to be the symbol. Now you might think that we are done and totally good and set to go. We're actually not. The other thing that we need to do whenever the watch list is updated, we want to go ahead and tell our watch list table here to fetch the new thing that we added and added to the list here. So how do we actually do that and how do we do that more over in an efficient way. So we're going to be using an extension on a notification and that notification we're going to fire whenever a new element is added to the watch list. So I'm gonna say extension on notification dot name. This is going to be did add to watch West. And basically we're going to assign this to a given notification name. And essentially whenever our Persistence Manager implements or calls this function, We're gonna go ahead and say Notification Center, and we're going to try to spell things correctly. Dot default and we're going to post a notification and this is going to be did update watch list or did add to watch list, I should say, did add to watch list with an object of nil. So who's going to be observing for this notification? So basically over here in our watch list controller, what I'm gonna do is we're gonna create an observance of that notification. And whenever it gets calls, we're going to drop all over current view models and we're going to try to fetch data again, but we're gonna do a clever optimization that you guys will see in just a second. So here I'm gonna go ahead and say set up observer. And this is going to be once again a private function here. I'm going to stick it in the private section. And basically what we want to go ahead and do is create an instance up here to hang on to our observer, are going to say our observer is going to be NS object protocol just like that. Now observer is going to equal notification center. See if I can find it. Notification center default, add, observer. And we're going to use the one that has using the foreign name is going to be did add to watch list. Object will be nil, Q will be made. And using is basically going to be a block that gets executed whenever we get this notification, whenever he gets fired more or less. And we can actually shorthand this and drop that and do this. Let's align all of our, all of our curlies here looks like this should be a curly and we should be good to go. So what do we want to do whenever we get a notification call like this? Well, the first thing we want to do is we want to say self dot view models. View models. We want to remove them all. So we're gonna say self.view models. Remove all. The next thing that I want to go ahead and do is say self. And we want to say Fetch watch list data. So let's talk about this watch list data because we're creating a group here in, we're essentially going and fetching every symbol inside of our symbols here. However, we already have data for some of these symbols, right? Because whenever we added new elements of the watch list, we met already have data for these three. Why do we need to fetch for them again? Well, the answer is we don't. So we're gonna say for symbol in symbols where our map, which we call the watch list map for the given symbol equals nil. In other words, only go and fetch where this is nil. And basically, this will allow us to reduce the number of API calls that we are making by limiting the number of requests we're going to send out here. Because if we add one more thing here, all we really need to do is fetched the fourth new element, whatever data we don't have present in our current map. And once we have it, we're gonna say, Hey, go ahead and create your view models. So this is essentially how we get away with doing minimal work and updating our actual TableView here with a notification. So let's see what we did here. So here we had gone ahead and dropped all the view models. Whoops, that's not what I'm looking for. Where is our observer? There we are. So we drop all over view models and then we fetch information again, the data, the models that's needed. And then this in turn called the tableView reload function, which is right down here. And we should see our updated UI. That the reason that we're not hooking this all up directly is because we're we're gonna be able to add a stock to the watch list from the detail screen. And we have not actually created that detail screen yet. We're going to get into that right in the next section, which I believe is the next the next video. So that is all I've got for you guys so far. This is the deletes and add functionality. We've got our watch list working. We can also go over to search and we can search for a new stock. Maybe I'll search for J and J, which is Johnson and Johnson for those of you familiar. Now tapping on it, we're showing this detail controller. Now. We need to show that detail controller from here as well. And actually we'll cover that in the next part. So thanks for watching. I'll see you in the next part. 25. Watchlist Interaction: What's going on, guys, and welcome back to the next part in our section. In the last part, we took a look at adding elements to our watch list here stocks more specifically, in this part we're gonna talk about interaction with these cells and what we wanna do when we actually tap on it. So it might be a dead giveaway already that we want to present the detail controller by wanna talk a little bit deeper in terms of what do we actually want to do? So we're going to first create the ViewController. This is in Table. You did select row for our watch list controller. And this is going to be a stock Detail View Controller. We want to wrap it inside of a navigation controller presumably. So we're going to say UI navigation controller and pass it in that root VC. And then here we want to save, present the nav VC animated true. Now let's talk about what we wanna do in here. So we're going to build this out further in the next section. But whatever we create those control or we want to pass in three things. And I want to set that up before we wrap this up so you guys can see how this all comes together. So we definitely want to pass in a symbol. We want to have a company that was passed in or the company name, I should say. And the last piece that we want it to be passed in is the candle stick data. Now this candlestick data should basically be an array of candlestick objects. And this is going to, you know, you can pass in an array and by default it's going to be empty. We want this stock detail controller to be reusable between the watch list and what a user searches for something in the search bar. When you search for something in the search bar, you don't have access to their candlestick data for the watch list you do because we actually fetch it to render this view here. Because we have a mini chart here. Keep in mind even though we're not showing you just quite yet, but we do have that data at our disposal. So let's go ahead and say super and it's nil. Nil. Also going to bring in the required initializer just like that. And we are going to hang on to these inbound, initialize our properties or say self dot that is thats. And self.age candlestick data is candlestick data. Let me go ahead and drop these properties up here. We're gonna say privates. Let's symbol is going to be a string. We're going to have this guy as well, private let, company name and this one as well, except this one is going to be immutable and you guys will see why that is in just a moment. So that's basically what's going to happen when we present this. Now let me just add some comments so we start to actually organize our code here. So we're going to have some lifecycles, lifecycle of functions, and we are also going to have these initializers. So we'll go ahead and say Mark. And it's, and then up here, these are all of our properties, so we'll go ahead and mark them appropriately as such. Let's go ahead and give our API build and run. And let's make sure we see our detail view controller and we tap on something in the watch list. So we actually see some errors here, and this is good because we expect them to be errors. So here we have the search results delegates, and then we also have an error down here when we are trying to create this controller from the watch list, It's asking us to basically pass in the parameters, right? We want to pass in a symbol, company name, and some data. So we're able to actually do this because we have access to all this information on the watch list. Specifically, what I'm gonna do here is we're first going to nil those out. So I'm going to say let's view models singular is going to be from our view models, the nth elements that we selected. Now from this view model, I can go ahead and specify the symbol. I can also specify the company name. Now what do we do for the actual data, because the data is not a part of our ViewModel. Well, we actually have access to the data and the model already so we can go ahead and get the watch list map. From that, we're going to get the ViewModel symbol. And this should be basically our data. And if it's nil for any reason, we're going to pass in an empty array. And just like that, we can pass all the stuff in. Similarly, when we try to present this controller from the search context, in other words, from the fact that we created a search results controller, we want to do that here as well. So this is going to be search results, data, display symbol. This will be search results that description. And the candlestick data was going to be nil, an empty array, I should say in this case because we don't have it, so we are going to need to fetch it. And in fact, we can just drop that perimeter because it is defaulted to be an empty array. If you go ahead and give your app a build and run, everything should successfully be compiling and we should be able to tap on something in our watch list. So we'll go ahead and tap on Amazon here and we get this controller. Now it's entirely empty at the moment. This will be the next section that we'll dive into. So that all said, that's all I've got for this part of this section. Thanks for sticking around. Hopefully you all are following and enjoying the course so far. I'll see you guys in the next one. 26. Create Stock Detail View: What's going on, guys, welcome to Part 1 of the stock details section. This is the section where we're going to build out this UI. You can get to this UI by tapping on anything in the watch list or searching for a given stocks. If I search for J and J here, and I tap on one of these results will come here to our particular results page. So that said, let's jump right in. So in this video in particular, we're going to be setting up all the components that we're going to need in the stock details, barring a few things. So specifically what we want to work on is that controllers let me go ahead and open it up and we'll jump right into it. So the stock details controller, if you think about it at a high level, it has a couple of responsibilities, right? The first thing is to show some view. The next thing, whoops, let's jump back into there. The next thing that it shouldn't be doing is it should be fetching, showing a fetching and showing some financial data. So this is things like the 52-week high load, things like that. It should show a chart. Of course, the graph, we should call a graph or chart. And it should show the user's news. So these are quite a few things that we need to do. So let's dig right in. So first and foremost, the type of view we're going to use to drive this controller is again going to be a TableView. I'm aware we're using TableViews all over the place, but it's pretty versatile and it works really well in this type of app. So we're going to create a table view here. And we're just going to create it and register two things to it. The first one is going to be our header for the news header. So we're gonna say register the news header view dot self. And we are going to register it for the identifier that's associated with it just like that. And the next thing we're going to be registering is whips table. The data register is a cell class on the detail view. We of course want to also show the relevance and news stories for a given symbol that we're looking at. So we're going to want to both of these again. Now once we have this table created there, Let's create relevant functions for all of these. So the first one we're going to have here is going to be set up table this we're going to drop right here. And let me actually mark these as private just to organize our code. Right? We're going to have setup table. We're going to have a fetch data. So I'm going to say private func that data. And fetch data is going to be responsible for fetching financial data as well as optionally fetching our candlestick data if we don't already have it for the particular symbol we're looking at. So we're gonna come in here and we're going to say fetch data. The next thing we're going to want to do, this is going to actually be created after we're done fetching data. And this is going to be render charts. And the chart is going to be, you know, take in some of the data, which is why we do it after we fetch data. And then let's see what else do we need here so we want to show the news. So this is going to be related to fetching the news itself. Here I'm going to say Fetch news. All right, so we have fetch data. We might want to go ahead and call this fetch financial data. So it's a little more clear as to what we're doing. So she will say fetch financial data. And this one down here we're going to want to say private funk, fetch news. So let's get through the news first. It's, it's fairly straightforward and this table, so we want to add this table as a subview. Now we want the singular function here. We're going to assign its delegates and its data source. And keep in mind, this is basically what we had done in the other view controller for the news, we could optionally reuse that components, but I'm just going to build that out here again, so we get a nice refresher. So here we go ahead and assign the frame. The next thing we're going to want to do is conformed to three protocols to for the tables. So here's the delegates. Here is the table view data source. And you might be wondering, well, what's the third one that we want to conform to? That third one that we're going to want is for the news header delegates. And this one has did tap on the button. And basically this is where we would add to watch lists. Again, remember this is the add button it's going to show in our news header. We'll get there momentarily. All right, so what do we do in here? A number of sections is going to be one. The number of rows that we're going to have. We're going to return stories, dot counts. Keep in mind we're going to create this collection right now. Stories is going to be a array of news stories or a private var. Stories is going to be an array of news story objects. It's going to be empty by default. Looking good, looking good. Next up we're going to say cell for row at index path. Here we are simply going to creates and cast a cell and then return it. So that's not the right function. We want the other one cell for row at index path. Let's see if I can find the proper function. This is the one that we're looking for. And in here we're gonna go ahead and dequeue the irrelevant cell for the news TableViewCell dot identifier for the given index path. And we're gonna go and cast this as the irrelevant identifier. Then we're gonna come down here and return its cell dot configure. We're going to instantiate a ViewModel from the given model. Pretty simple, looking pretty good. The other thing that we wanted to make sure we don't forget to do is do height for row at index path. So we're going to return the news a TableView cell dot preferred heights. Pretty, pretty simple. And this is what we'd need to do for the specific, we can actually delete this for the specific immune cells, but we want the header to also show up. So we're gonna say View for header and we want it. So let's see what function we want. We want this one here. I'm going to go ahead and say guard, lets header is going to be the TableView. We're going to dequeue a reuseable header footer view with an appropriate identifier. This is going to be the news identifiers. The news had arise under fire, I should say. We're going to go ahead and cast this for not able to. We'll return nil here. We're going to vendor down here, return the header. And I'm going to return a header dot delegates will be self. And we're going to say header dot configure. And we want to configure this now with something. So we're going to create this with a title. Now this is going to be the symbol that uppercased. And in terms of showing the Add button. And now we're just going to hard code this to be true, but we want to conditionally show this based on whether or not the current symbol reviewing is in the user's watch list. We'll talk about that momentarily, but let's just get this all rendering first. We also want height for a header, will say heights for header and we're going to return the news header, dots preferred heights. Let's go ahead and give this a run and let's see how we have done actually we never fetch the news. So before we actually run, let's go ahead and write our function to fetch the news. So we have fetched news here. We're gonna say API color, shared. We're going to say give me news for a given company with the particular symbol. Here we get a result back and we're going to switch on the results in the success case. We're gonna get a bunch of stories back that we will go ahead and hang onto. In the failure case, we definitely had something go wrong, so we're just going to print out the error. Now we wants to go ahead and say self question mark there for self optional. And I'm gonna go ahead and say weak self so we don't cause a memory leak. And here we're gonna say a table view reloadData, since we do wants to do that on a main thread after we have set the stories. So let's go ahead and give it a run. I know I blew through that kinda quickly. So let's see if we have any errors. It looks like we do. So let's see what has happened here. So this should be fetched financial data, but we need to get rid of the duplicate parabens. Let's get rid of those and give it a run. So this should all be hopefully a recap that we are going through because we're building out the news that we built off the news controller. Nothing too different here I'm going to click on Amazon. And boom, we see the header and the particular Amazon related stories. So looking pretty, pretty good. So this is why reusability comes in super-duper handy. Now when I tap on this, nothing actually happens at the moment. But we only want to conditionally show this if we're not in the watch list already now we clearly came here from the watch list. So we'll, we'll need to adjust this. So now that we have actually created the news piece here, Let's go and let's work on selecting these news stories to open them as well as conditional is showing that Watch List button. So for selecting the news stories, It's pretty simple. We're going to say TableView did select row at index path. The next thing I'll do is say de-select at the particular index path. And you guys know the drill at this point, we're going to use Safari services to open up the particular URL in the in-app browser. So I'm gonna say guard lets URL is going to be stories at the nth elements, dots URL. Now we want to actually create a URL instance from this, instead of having just a string. Otherwise we are going to return. Next up, we want to create the relevant view controller here. So we'll say SF Safari view controller. And we wanted to present said VC and not the URL with an animation. And that's how we'll be able to open up our particular news stories. Now how do we conditionally show this Add button, add to watch less fun? Well, that's actually pretty simple too. If you think about it. If you take a step back and think about it, we basically want to function in our Persistence Manager, which is going to tell us if this watch list I've contains a particular symbol. We can just say watch list. We'll say a watch list contains. And we can say symbol here, which will be a string. And I'm simply going to return this and if it contains the symbol. Now, the other thing we can do is coalesce false here. Actually it's not even nil, so we don't even need to do that. We can just drop that. We could have just used as contains check on the watch list directly. But I personally like adding these APIs so everything stays in its appropriate class. In this case, it's Persistence Manager. And what I'm going to go and do now on the stock detail controller, instead of arbitrarily say yes here in terms of showing the button, what I'm gonna do is we're only going to show the button if we don't, aka the exclamation points already have this particular symbol in the watch list. So we'll say if Watch this contains the symbol and that equals false, we'll go ahead and show it. Now what needs to happen when we actually go ahead and tap on this particular Add button. So we're passing in a reference to the header view. The other thing I'm gonna do it here is dropped the privates on the button because we're going to actually end up hiding the button once the user taps on this. And the reason we want to hide it is because we don't want the user to be able to tap the button more than once. Otherwise, we'll have duplicates and our watch list, so we're going to hide the actual button. The next thing we're going to do is in our Persistence Manager, we are going to add to the watch list with the proper symbol and company name. These are both properties on our current controller, which is the stock detail controller. Once we've done that, we probably want to let the user know that, hey, we've added this company, it's your watch list, so we'll go ahead and create an alert in here. And it's going to have a title and it's going to say added to watch list. Now the message here is going to be we've added the company name to your watch list just like that. And now in here we can say the style is going to be alert, go ahead and fix all of these up. We're gonna go ahead and say it presents the alert animated will be true. And here we're gonna say alerts, add action, UI alert, action. The title is going to be dismissed style cancel handler nil. So go ahead and give that a run and let's make sure we're seeing the button where appropriate and not in the places where we already have something in our watch list. So we'll come in here, I'm going to select Amazon. We should not see that, but in awesome, looking great. Now I'm going to search for a different company and maybe we'll search for Microsoft and we get the symbol here. Now let's see, we don't see it here, which leads me to believe we have that in our watch list as well, which in fact we do. So let's search for snap, which we don't have in our watch list. And boom, you get the button. If I tap on it, it tells me that it's been added in. The button has disappeared. Let's verify it's on our watch list and boom, just like that Snapchat is in fact in our watch list, looking awesome. So cool is that this is our details so far, the most important piece is still missing. And we're going to add it here with a table header where our graph is going to go along with some of our financial information. So we had created a function, I think in here. Let's see, we have Render chart. So now render chart. So let me back up a little bit. So in this fetch financials, we need to fetch candlesticks if needed. We'll also need to fetch financial metrics, which we will need to regardless of where we come from. If we come from search, we don't have this candlestick data. If we come from the watch list, we do. And then after both of those are done, we wanna go ahead and render out the chart. Now what I'm going to go ahead and do before even diving into that, we're going to say TableView, table header view. And what I'm going to go here and do is create a basic UI view with the frame 000 view dot width. And the height will be viewed out with times 0.7, which is 70% of it. And I'm going to take that and we're going to add to it a 100. So let's take this plus a 100 and the point that 70% of the width is going to hold our graph and the 100 is going to hold some more metrics that we'll go ahead and fetch in the next video, I believe. So let's go ahead and images line break this, so it's a little cleaner. Let's go ahead and tap into one of these elements and our watch list and make sure we've got some room up here and up here we'll see the graph and then the bottom 100 points here we should see our financial data metrics that we're going to need to set up a collection view for and an API call. Now the last thing we'll do before we wrap up this video is at a close button up here as well as the title here in case we don't have one already, which we don't. So in the viewDidLoad function, I am going to go ahead and say the title is going to be the company name. Pretty simple. And we're also going to say set up close button. And we'll go ahead and come down here to the private section. We'll say private set up close button. It's just nice to have a little way for the user to close the controller, even though you can swipe to dismiss. So this is going to be a UI bar button. Item style will be close, target will be self action will be did, tap, close, just like that. Let's go ahead and line break all this. So it's a little nicer. And here we're going to say at Objective C, private func did tap close and you guessed it. All we're gonna do in here is a dismissal for this particular controller. So let's see if everything looks good. In the next video, we'll start getting that financial metrics data and plotting it right below where our graph is going to go. And I promised we're almost everyone's usual favorite part which is creating the graph. So if I come in from Microsoft, we see Microsoft Corporation at the top, which is perfect. We have a canceled by an up here. It's not what I wanted. I wanted a close by elites. Try that one more time. I'll read, bear with me. So we're going to open up one of our watch list items. And maybe we'll go with Amazon. We see Amazon, we've got a pretty cool looking close button up here. Lots of Amazon related knees and see where Amazon has been up to. Apparently UK competition watchdog is probing Amazon, that's not good. So we can click on it, we can open it up. You can also hit this, this should dismiss and I should be able to search for companies as well. So if I search for Apple, we should see apple here, I can click on it. Similarly got the title, looks like in this case, it is in fact upper casing everything. So we might want to uppercase. It's a little subjective, but it's fine. So we'll go ahead and close this out. I'll add this to my watch list as well because that's Apple and why nots. And in the next video we'll talk about fetching that metrics that I've been talking about, the financial data to complete the information that we'll need to draw out everything here. So thanks again for watching. I'll see you guys in the next part. 27. Metrics API Call: What's going on, guys? Welcome back to the next parts in our section. In the previous part, we talked more about the detail screen in our app. So basically when I tap on into any of these stocks here, and in this part, we are going to further build this out specifically focusing on getting our metric data for the given company we're viewing. So let's jump on into our API color class under our managers folder and write out a function to get some financial metrics for a given company. So I'm gonna scroll on up under the public section here. And we're going to create a new function called financial metrics. And we wanna go ahead and get financial metrics for a given symbol. So we're going to say string. We're gonna wanna get a completion handler in here as well so we can get a response out of it and it's going to be a results. I'm just going to stick a string in here for the time being while we figure out what the model is going to be and this whole thing returns void. Now the next thing we want to do is jump on over to our API documentation. And here we've got the basic financials and points. I'm gonna do a couple of things here. If we take a look at the URL endpoint, it's stock slash metric. And that this endpoint takes into query items, the first one being symbol and X1 being metric. So let's go ahead and copy that right there. And let's see what else we need some zoo, this V here should be capital, so that error goes away. I'm going to stick in their new endpoints into our enum. So we're gonna say financials and just going to paste in the end point there. Let's go ahead and create our URL. So we're going to see, or URL is going to be a URL for financials. And it's going to take in a couple of query items. The first one that being a symbol of type, symbol, which is the parameter we're bringing in. And the second one being a metric of type. All I believe metric was singular and plural. Let's go ahead and have a quick peek. Ip it is in fact singular, it's right here. And this should basically be sufficient to construct our URL for this API call. The next thing that we wanna do is actually go ahead and make that call. So we're gonna say a request pass in are given the URL. We want a type of backward, just going to say string for a quick moment here while we go ahead and create our related model. And once again, let me just shorthand this and put this here and get rid of that, like so. And next up, let's take a look at the response we get back. So in the response here we actually get quite a bit of data. But the thing that we care about specifically is the very last key here, which has, which is metric and it has a couple of different pieces of information in here. So let's go ahead and create a model which is going to represent our response. So I'm going to open up our model's folder. And in here we're going to say new file. It's going to be a financial metrics response. So we'll go ahead and say financial metrics response to go ahead and create that. And in here we're going to say financial metrics response. And now the cool thing about quotable is we can disregard any of the keys we don't care about. So the only one that I'm going to stick in here is metric. Since that's the only key that we care about. And metric points of this object here we are going to create right down below. So metrics, Angular is going to be of type metric. Let's make sure it's singular. Yep, it is. In fact, singular symmetric is going to be of type metrics plural. And let's go ahead and create that structure right down here. So we're gonna say metrics is going to be quotable it, I'm going to stick this in here, like so. So let's go ahead and jump into actually creating these properties. Now there is going to be one issue here that we're going to need to deal with that we'll talk about momentarily. So first things first we have a volume here which looks to be a float. So I'm gonna say this is a float. And let's see what else we have. This here is a double, presumably we see a double here. Same thing for this next guy. Whoops, let's see, simply for this one, this one here is going to be a string. And let's see. This last one here is a float as well. And this one in the middle here is going to be a float as well. So the one thing you might have observed, which is a problem here, is the fact that these keys start with a number. And that's actually not allowed in the nomenclature or something That's quotable. So similar to how we used coding keys to. Clean up of the naming convention of our actual properties here we're gonna do the same thing in here. So I'm gonna go ahead and created called coding keys. It's going to have a raw value of string and it's going to also conform to coding key. We're gonna go ahead and grab these. I'm going to toss these in here. And we are going to start to tweak these. So first of all, we'd need all of these. Let's hear to be cases you can hold Option and get the multi, multi cursor support like so. And instead of having these have a type, we want it to be equal to a particular string. So I'm gonna go ahead and z, That's what do these for all of these here like so, like so, and see these ones here as well. So for the Beta and this one as well. So instead of using these, I'm gonna go ahead and make this 10 day this while we can go ahead and say for any of the 52, I'm going to say Annual. That way it'll actually figure out the fact that it's a key. And we'll do that here as well. And similarly here we're going to say this is an actually before I go and change all of these, let me just copy and paste each of these keys into the respective string. So this way we're telling Swift bad thing in the string is the actual thing that'll be in the JSON. And that's what we are using is the case here is our property is. So let's go ahead and just update these. So these are all going to be annual, so I can get these all in a one-shot to psych that. And we should hopefully be good to go, that error should go away. So now our things are named nice and appropriately and swift is happy and we can go back to our API color. And we could drop in right here that we expect to get this back as a response, expecting a market or financial metric response.body self, just like that, beautiful. And let's actually go ahead and hook up where we call this API from. So we're going to be calling this API from one of our controllers, of course, and it's going to be our stock details controller. And in here we have a function. Let's see if I can find there, this one here for a fetch financial data. So we want to go ahead and do this year. So we're gonna say we're gonna have a dispatch group first and foremost will say dispatch group is going to be created like that. And we'll just stick this in here as well. So we're gonna say if the candlesticks is empty, we wanna go ahead and fetch candlesticks all say group data enter. And let's see what else that we need to do here. Groups that enter here will need to fetch that. And then here I'm going to also go ahead and say Group dot enter. And we are going to say API color shared. And we wanna go ahead and actually fetch this data. So the way we're going to go about doing that is by using our new endpoint, we're going to pass in a symbol here. Completion is going to give us a result back. And hopefully I did this correctly and we will get a successful response, which is going to have our, I'm just gonna call it a response in this case. And then we'll have some metrics off of it. So we'll say metrics is response dots. Metrics. It should be response, not result here. So we'll say response.me just like that. And the failure case, let's go ahead and just print out the error that we're gonna get. So we'll say prints error just like that. And of course don't forget to leave from your dispatch group, otherwise you make it a weird crash. And once all of our data has been fetched, we are going to say group dot notify. And we want to get notified on the main queue. So we're gonna say mean and execute. In the execute block, we're going to go ahead and say render the chart. So let's go ahead and say weak self in and render charts. We're gonna go ahead and do that. And once we have this data here, we basically want to go and creates a bunch of view models that we're going to use to show our metrics. Now since we have not created that viewModel gets one thing that I am going to do in this render chart function is start to talk about a little bit, how are we going to create our view? So we want to create a view that is going to take in two things. It's to take in a chart view model. And it should also take in a collection of financial metric view models plural because we're going to have multiple of those and we should pass those into a view. Now we haven't actually created a view yet. I'm going to stub it out and then we'll dig into it in the next video. This we can call it, see what we have already. So we actually have a stock chart view already. I'm gonna go ahead and call this a stock detail header view. And that's going to wrap a chart view and some other stuff. So we're going to call this a stock. Detail, header view, just like that. Let's go ahead and create it. And basically inside of here, what we want to do is we want to have a chart view and we also want to have a collection view. The collection view is going to represent our particular financial data and the chart view is self-explanatory. It's going to represent our chart. So we're going to see our chart view as a stock chart view just like vats and our collection view, we're going to create one of these here as well, not a TableView. We want a collection view. And for those of you wondering why we want a collection view is so we can get a horizontal layout and you guys will see what I mean that momentarily. So let me just create a collection view here of type UICollectionView. This gets created with the frame as well as a layouts. Up here we're going to create the layout will say layout is a UI collection view flow layout to psych that's on this layer. I'm going to say that the direction is what I'm looking for, or C, we want a scroll direction is horizontal. We're also going to say layouts data minimum inter item spacing is 0. We're going to say layouts, dots, a minimum line spacing, if I can find it is also going to be 0. And we are going to return said Collection View here. Now we want to register cells for the collection view, which we're gonna get into in the next video. But let's go ahead and just get this stuff added as a subview. So I'm going to override the initializer just like any of our trusty subviews, we're gonna go ahead and say add subviews plural, we're going to say char to view as well as our collection view. Now we also want to set up the collection view. So I'm gonna say Collection View. And we want to assign the delegates to be self. We also wanted the datasource to be self just like that. And let's see what else we wanna do. So we want to conform to both of those. I'm just going to stick it on up here. So we'll say UI collection view delegates, UI collection view data source. And lastly UI collection view flow. Delegate flow layout is actually what I'm looking for here. And now that we've got all of these, we can start implementing our collection view. But before I do so, let me go ahead and bring in the required initializer as well as the layout subviews override just like that. And down here we're going to actually put all the collection view stuff, but I'm going to add a mark just to organize our code. Number of sections is going to be one number of items. We're just going to hard code this to maybe be three, maybe just be 0 for now since we don't have any cells, cell for item at index path, we want to go ahead and create and return a cell here. But for now, we're just going to do that. Now we don't want this stuff to be interactive, but we do want to go ahead and specify a size. So we're gonna go ahead and say size for item at index path. And we're going to return CG size with a width and a height. And the height is going to be the view's height divided by 3, and the width is going to be the width divided by two. So I know we've done quite a bit. Let's go ahead and set a background color on the Collection View and see if we can actually see where it's going to show up. So I'm gonna go ahead and make it red. And we actually created this view, but we're not using it just quite yet. So before it actually switched to the controller, we're going to want a function on here. And let me actually put it above the collection view stuff. And it's going to allow us to configure. And we want to pass in two things in here. We want to have a chart view model, which is going to be a stock chart view, ViewModel. And then we also are going to want a collection of metric of TableViewCell view models. So we haven't created that yet either. So maybe we'll just stick to this for the time being and then we'll extend this. Let's go ahead and toss this into our controller. So we'll open up our controllers here. And in stock details controller here we are going to say our header view is going to equal this view here. The frame is going to be the exact same size as our current header view. So the way we wanna do this is say CG rect 000 vue.js with and the heights you guys have seen previously, we're going to save this is the width, the view dot width times 0.7. And we're gonna go ahead and add a 100 to that. So this should be 0.7 and not anything else plus a 100, just like that. Let's just go ahead and line break all of this. So it is a line here. Let's do that. And that's, and we expect to see our red Collection View. Hopefully once we've created this here, we would call the Configure function here. And then finally we're going to say table, Table View, dots table header view equals our new header that we've created right here, this header view, just like that, and we should be good to go. So let's go ahead and print out our metrics that we are getting to make sure we're actually successfully getting them. Because if they're not, that's a bummer. So we're going to have to fix it. So let's print those out right there. And we're going to eventually need to reference weak self. So we'll go ahead and do that like so. Let's go ahead and give this a run and make sure our brand new API call that we just built out is in fact working. So go ahead and give it a run. I'm going to open up the console here for good measure. And we're going to, basically, we're going to want to see Steph as soon as we select one of these, I'm going to click on Apple and we expect to see some metrics. And we in fact do there is a 10 day average trading volume. We have an annual, weekly, higher annual week, I should say. And it will weak, low, et cetera, et cetera. So that's basically the metrics API. In the next video, we're going to finish up building the metrics UI at which should actually be showing up right here. Let's actually figure out why it's not, because it's not at the moment. So let's see what's going on in this or render function. Let's see where it is because we are setting it here. Let me set a background color to this. We'll say a background color is going to be link. But we'll basically builds out the metrics and the next section we're going to dive into building outs and configuring our graph slash chart view. So we'll go ahead and select one of these. We got that blue background looking awesome. Let's see what's up with our chart view because I'm not seeing it. Yeah, and I believe what I forgot to do in here is actually give the collection view a frame. So in here we're going to save the frame of this guy is going to be CG rect 0. This is going to be height minus a 100. This will be a width and this is going to be a 100. And will also give the chart view a frame while we are at it's, the x will be 0, y will be 0 with his width and heights minus a 100 is its heights. And let's just go ahead and tidy some more stuff in here, since we're in here already and we'll go ahead and say clips to balance is true to make sure nothing overflows. Go ahead and give it a run that we should see that red collection view towards the bottom of our blue header. So we'll go ahead and select one of these and boob our financial stuff. So it's show up here once we have the cells setup and our, our graph slash charts and show up here. So that is the end of this part. We've come a super long way, be super proud of yourself. We've got a little bit further to go to make this completes and especially get our chart in. So I'll catch you guys in the next video. 28. Metrics View: What's going on, guys, welcome to the next part in the stock of details view section. In the last part, we put together our financial metrics API call. And in this part we're going to actually convert that data to view models and actually build out our cells that'll go into this red collection view that you see here. So without further ado, Let's go ahead and jump on into building out that custom cell first. So under the views folder, I'm gonna go ahead and create a new file. It's going to be a Cocoa Touch class. It's going to be a UI collection view cell not it's hebrew view one. Well a habit there. So we'll go ahead and say UICollectionView cell. This is going to be a metric collection view cell. Maybe we can keep a singular, go ahead and create it. And in here we're gonna do something fairly simple. We're just going to want to labels one for the actual name and one for the value. First up, we want to have an identifier, which is what we're going to use to register the cell. Then we're going to want to override the initializer liquid do in any of our views, we'll go ahead and say super. And this should be a period, not a comma. We'll go ahead and do super, and it's, we'll bring in our required initializer like that. Then every cell you guys know the drill where you want to have layout subviews so we can lay out all the appropriate some views. And we also want prepare for reuse. So we can prepare the cell for reuse. What a creative name. Next up, what do we want in here? We want to bring in the subviews. But before I even zealots created a view model. And the view model will basically have two things. It's going to have a name and then it'll also have a value which is the other label will basically shares the name might be like the volume, the label or the value might be like, I don't know, 10 million. So let's go ahead and bring in our two labels. So we'll say here we have a name or label of type UI label. And we're gonna go ahead and create this like so. That's in here. We'll create this. Boom, boom. And inside of here we are going to, we're going to leave the label actually as is the one thing that I'll go ahead and X2 in the other one that we created here, the value label, I am going to go ahead and set the text color to be a secondary label just like that. And now that we've got both of our labels created here, we want to add them a subview. So I'm going to say add subviews for the name label and the value label as well. We're going to say constant view clips to balance is true and slight mistake here we actually want to add these labels to the content view. So just be mindful of that. In size layout subviews that we are going to say value label size to fit. And we're also going to say name label size to fit. The name label dot frame is going to equal. Let's see a y. We can go ahead and say it's 0. This will be named label dot frame and this is going to be content view dot heights. Now the ECS is a little tricky in terms of what you want it to look like. Maybe we'll just go ahead and say, I don't know, let's do let's do three and let's see what that looks like. Now the next thing we're going to want to do, let's see why this is yelling at me and name label frame looks like we screwed something up here. This should be a name label for the width should be with, and we can probably get away with just copy and pasting this for the value label. The only thing that really should change is the x here. So we're gonna say the x is going to be the name label dot-dot-dot rights may be plus three, so it has a little bit of buffer padding. The width is going to be the value label dot width and the height will also be content to view Heights. Next up and prepare for reuse. We're going to say the name label text is going to be nil. Value label tax is going to be nil. This function gets called when the cell tries to be reused, hence prepare for reuse. Finally, we are going to want a configure with Vue model function on here. And this is going to simply assign those labeled texts or say the name labels text is going to be view model should be the lowercase one and dot name. And the value label text is going to be a ViewModel dot value just like that. And we're basically good to go with our cell here. So let's go ahead and register it and use it in our view. So the view we're going to want to use it is in our stock detail header viewer. We started putting together this collection view. I'm going to go ahead and drop the background color here. We're going to say Collection View, register a subclass with this identifier. Whoops, this should be solved that self and this identifier like that. And we're also going to have some view models up here. So these are our sub views. So it's going to add a comment here. And up here I'm gonna go ahead and creates metric view models, which will basically be of type of this self.view model by default, that's going to be empty. And in our actual collection view methods here we're going to say for number of items. We're going to say it's going to be this collection dot count. Here. We want to actually get to the given ViewModel, which is going to be this collection again and the element at the particular row. We want to go ahead and try to use the dequeue function off the Collection View here to dequeue the appropriate cell. So we are going to say dq, a reusable cell with identifier. And this identifier is going to be our metric collection. And I keep saying TableView, our metric collection view cell dot identifier. Let me line break this so it's a little cleaner. And this is going to be for the particular index path that we care about. We'll go ahead and align that with the control I tried to cast to the proper cell. And here we can say cell that configure with the ViewModel and finally return that cell. So that's looking pretty good. We've got a size here is specified. And in this configure function, we can now also go ahead and say that this takes in metric view models and it's going to be of type metric collection view cell dot view model just like vats. And whenever we configure we can say self.name metric view models is going to be this guy. And then we want to go ahead and say Collection View. Go ahead and reload yourself. We'll also wants to update our chart here in the next section, but I'll just stick a comment there for now. So let's see, I think we should be good to go. So we're going to jump into our stock Detail View Controller. And here we actually already fetch our data and we can go ahead and create some view models from it. So here we have basically just printed out that metric. We, instead of printing it out, we are going to say self.metric. I would see if we have, it looks like we haven't actually created it yet. Let's go to the top here. We should have view models that we hold on this particular controller. It looks like we do not yet. So we're gonna say here private var, metric view models. And actually instead of doing a here, well we could probably do is hold the metric here. So we can say metrics is going to be of type metric. And what I can actually do if I come down here where we have gotten those metrics, I'm going to say self.me metrics just like that. And when we go to configure the particular view, we can pass them in. So here we are going to say header view. We went to configure this. Now in this case, we are going to just pass and you know, some dummy data for the chart. So we'll go ahead and say false and false here. And this is the one that's more interesting. So what we are going to do is create these view models and pass them in accordingly. So it'll say view models like so. But we need to actually create them first. So we're gonna say let view models is going to be an array of our metric collection view cell, a dot view model, just like a vats, it's going to be empty bad faults that we're going to start to append in some data. So we're going to say view models dot append. We're going to create one of these with a name and a value. And the place we're going to get the data is basically going to be from our metrics that we should probably unwrap it for somebody. Say if let metric equals metric just like that. So recall a metrics since it is in fact plural, right, looking good. Now in here we're gonna go ahead and create it. I'm going to stick this view models out here. And in here we can now say the value. The first one that we want is metrics, dots, and maybe we'll get the annual heifers. So I'll say 52 week high, 52 w. Hi, and I'm going to go ahead and simply copy and paste this a couple of times. So this guy right here is going to be a double. So what we wanna do is we are going to stick it inside of a string so it satisfies our types. And I think we have a total of five in here. So I'm going to go ahead and just depended that are rather copy and paste that a couple times. So we're going to have 52 week low here. We can go ahead and change this to low. The next thing we're gonna want here is our, let's see, we have an annual dates, load date, we have a price return that daily. And it will week 52 week return daily. So maybe you'll call this 52 week Delhi. They would call a 52 week return. So it's not super long. Let's see what else we've got in here. I think we had a Beta, so we'll simply call this one Beta. And then I think we also had a volume in here. So let's see if we have a volume, we have a 10 day average trading volume. So I'm going to go ahead and call this ten d volume soldiers say attendee evolve with a period. It just like that. And we should be good to go. So it looks like conditional for optional binding with C are saying if law metrics equals metrics, I believe metrics is optional. Let's see, let's see. So it looks like it is not in fact optional, but it should be. So we're going to create this up here as an optional just like that. And that should satisfy our optional binding here. Go ahead and hit Command B, and let's go ahead and give this a run or we should start seeing our financial data in that red space, which we dropped the color for at this point. So go ahead and give it a run. Everyone, cross your fingers. Let's go ahead and select a company. And we do in fact now see this here, it's horizontally scrollable, but that's not exactly the look I was going for. So we do see here that we have our cells. There are 1, 2, We actually the colon in between these 34 or five cells. But we want them to be stacked on top of one another because the way they're looking right now is not, it's not really doing it for me. So let's jump into our, we want to change two things into our metrics collection view cell. The first thing we're gonna wanna do is add onto the name a colon. And the next thing that we wanna do is adjust the Collection View layout heights of these cells. So the width is width divided by two, which is looking all right, and this is height divided by 3. So this should be sufficient space, be laying out each of these cells, but for whatever reason it is not. So let's figure out why that is the case. So we have a cell here that we are configuring. We have set up the minimum inter item spacing as well as the minimum line spacing both to be 0. The other thing that we might want to go ahead and specify here is the section in sets. So we can go ahead and supply some UI edge insets where each of the values is going to be 0. I still have a hunch that our layout will be off. So I am in fact going to set a background colors so I can take a closer look at how our cells are actually getting. Layout setting a background is generally a good idea so you don't have to guess and check. So let's go ahead and give it a run and see what our layouts look in like. Alright, so it looks like it's taking up the entirety of the cell. So that's a little strange. I see why? Because this height is actually the height of the entire view up here. This whole thing, when this should be a 100 divided by three is what I'm actually looking for. So go ahead and give it a run once more, because this is the height of the Collection View itself. Let's go ahead and give it a run. And now our cell height should be appropriate. So cool. So we've got our five cells here. Now, let me get rid of the background color as well as the section insets that we just zeroed out. I think we can keep them and it'll still look. All right. Let's go ahead and comment that out for the section insets and try one last time and what's all? Cross our fingers and hope that everything is looking. All right, so let's go ahead and pick one of these stocks from our watch list, like so. And everything is looking really nice. Now you may want to add a little bit of buffer onto the left side of the cells. The other thing you might notice is the fact that when you hit Command Shift a to put this into light mode, the text turns black, but the collection views color doesn't actually reflect the current background color. So what I would recommend that you guys do is actually specify a color for your collectionView. So we're gonna say that the background color here is going to be a secondary system background. Just like that. And go ahead and give it a run once more. I'm being very nitpicky on design right now, but it's pretty important. So let's go ahead and make sure it's looking. All right, Let's bear with my simulator. We'll pick this, I'll write it looking pretty good if I put it into light MOOC, that's looking pretty good too. I really liked that this has light moats and pour out of the box per our, you know, the way that we've built it. So let's go with Amazon. Now we've got this big blue area up here and let's see where we are setting this, I think is some link background color, but up here essentially is where our graph slash R-chart is going to go. I think we were setting a background color in here that we can go about dropping now. So let's delete this line right here which we were setting, and that's the end of this part. In the next section, it's going to be all about this chart. We'll talk about configuring various looks and feels of it. You know how to get different colors on it. The green, the red, the axes, you know, a legend, et cetera, et cetera. So thanks again for sticking around. You guys have come a super long way. I'll see you in the next part. 29. Create Chart View: All right guys, welcome to the next section in our class. This section is all about the charts that we need to bring in for our app to really be a full fledged stock app. So we can either build this out ourselves, which is going to require us to use Bezier paths with some geometric calculations. Or we can leverage a library called charts, which is really wonderful to use and does a lot of stuff for us. So we're gonna be using the tarts Library. And I'm going to talk you guys through every piece of what we use and how it's actually manually built under the hood. So that said, let's go ahead and actually start by closing or execute project here, as well as our simulator, we need to open up our terminal. And what we want to go ahead and do is cd into our project. We're going to open up our pod file. And in here we're going to add in one last dependency for our entire application. And it is respectively called charts. Once you have added it, close text editor and you can run a pod install like so. And just like that, it'll bring in the dependency. We can go ahead and open up our project folder, jump back into our workspace, and go ahead and give your project a Builds Enron and hopefully everything is still building and showing up in your simulator. Now charges a really popular library and iOS, it has come a long way over the past several years now it does the basics for you when in terms of what we're using it for, we're going to take values x and y, right? Doubles and floating points, and we're just going to draw a line graphs with that stuff plotted out. If you wanted to do it manually, you would essentially draw out what we call Bezier paths, which is the process of connecting multiple vertices with different edges. For a quick flash back to geometry class for all of you. So where we're successfully compiling here, let's jump into our stock chart view, which is under our views. And let's start creating a line chart view. So the stock chart view we're going to jump into here. And my goal in this video is just build out its heart view. And we're not gonna use any of this legend or axes or even a fill color. We're just gonna go ahead and make sure we can get our data to show up. So the first thing we wanna do is we want to import tart at the very top here, as you can probably imagine. And the next thing that we want to do is add some comments because our code is not going to be messy and we're gonna make sure it's nice and organized. So these are initializers. Here we are going to reset our actual tart and here we're going to lay it out as here, we're going to configure it. So how do we actually create a chart view? Well, it's super simple. We're gonna say privates. Let's, our chart to view is going to be a line that chart view. And we're going to configure quite a few things here in the anonymous closure, so bear with me. So we'll go ahead and create it like that. I'm gonna go ahead and return the chart view. And on this chart view, we want to go ahead and do a couple of things. So we're going to say pinch, zoom enabled, it's going to be false. Chart view, set Scale enabled is going to be true. We're gonna say Chart View. And for the legend, let's actually not do the legend yet. Let's do the x-axis, we're going to say enabled is going to be false. We are also going to say chart view. This should be enabled not entries dot, draw, a grid lines is what I'm looking for. A grid background enabled should it be false? We also wants chart view to draw our line. Let's see if I can find it. There should be a drug written here. So there's grid background. We can maybe go ahead and say y axis or let's see whether axes are on here. If I can't remember at the moments left axis enables is going to be false. We're going to save the right axis is enabled, once again is going to be false. So we're basically turning off the majority of the things that you would expect to see because we want a very vanilla chart. So we're going to stick with this as a baseline and we're going to add stuff as needed. So the next thing we wanna do is actually add this as a subview, like so we're going to give it a frame which is going to match the entirety of our balance. So we can just say bounds. Reset is simple. We're gonna say the chart views data is going to be nil. The data, as you can imagine, is how we actually supply of what to show on the chart. And this configure function is gonna do a ton of heavy lifting for us. So what we want to actually do is specify some data for our actual chart view here. So we're gonna say a dataset is going to be a line chart data set, or line chart data, I should say. And data gets created with a dataset. So let's rename some of this stuff. This is going to be data. This will be theta as well. And up here we're going to actually creates a dataset. So we're gonna say datasets is going to be line chart, dataset. And datasets can be created with entries, a label, a variety of things. We're going to use this. And here I'm gonna go ahead and say entries. And the label is simply going to be some level. We're going to come back to this momentarily. Now what is entry is going to be entries is going to be a line that chart data and tree I believe is what I'm looking for, a line chart entry. So let's see, I don't see a line chart entry, so let's look for a data entry and there should be a generic version, so there is a chart data entry. Let's see if we can get away with using this. It looks like we can. And the most important piece, the moment of truth, we're going to say for index and value in ViewModel dot data dot enumerated. And basically we want to append to the entries. We're going to say go ahead and append one of these, and we want to append it with an x and a y. So the x is going to be the index here, and the y is already a double. We're just pop in the value and we should be good to go. And that is how we set up our chart. Now keep in mind there are still more things to do. But before we even move any further, let me just go ahead and give it a run and let's see if we see the chart anywhere already being rendered. I don't recall the state that we left some of the things in, so we might need to jump around to clean things up just a little bit. So cool. So looking at that, we see our chart. We see no chart data available presumably because we're not actually passing in data into here. So let's go and let's go and solve that. So we are creating that in the watch list TableView cell. So let's see where we are calling the Configure function. We've got a view model on here. So let's see if we have a view model and we should have hopefully some chart ViewModel information on here. So we're gonna go ahead and say mini chart view. Go ahead and configure with this. And I'm going to also jump into the watch list view controller. And we're gonna see where we are returning the cell because apparently here we need to also deal with creating the appropriate ViewModel. So let's see, we should have a create view model function somewhere here. And we want to make sure we're actually creating it appropriately. So it looks like we're reversing the candle sticks and remapping into the closing price. And for Show Legend and show axes, we have false here. So we're not going to deal with the color just quite yet. Go ahead and create it and just give it a run. And let's make sure we're actually seeing something because something is better than nothing. So let's go ahead and wait for our simulator. And I'll write it looks like we are indeed seeing something. This looks up noxious, but let's, let's give ourselves a pat on the back so we see something. Something is better than nothing. So let's jump back into our stock chart view and let's start cleaning this up. So on the dataset, I believe you can specify things like a fill color. So I'm going to say system blue for now. And there are a variety of other things on here you can specify, such as draw circles enabled, draw icon enabled. We're going to say draw fulfills enabled is true. We're going to say draw icons enabled is going to be false. We're gonna save raw values enables will be false as well. And let's go ahead and say draw. Let's see what else we need. We have filleds. Now we don't want circles here either. There's going to be circles by default of the top of your lines. We're going to turn all these off and give our app a run once more. And let's see what this ends up looking like. Maybe this will look better now Fingers crossed. All right, so we're starting to look a whole lot better. There's some label is not looking too great. I'm gonna go ahead by default set to the legend here to not be enabled. And that'll actually go ahead and get rid of it. So here for the legend and we'll say enabled is false, go ahead and give this a run, and we should just see our chart now instead of that weird label underneath it. So bear with me and it should start to look a whole lot better. So cool. We start to see our charts here looking a whole lot better. The colors should reflect the fact that the stock is up or down right now, it's just blue. And if I tap on this, we shouldn't be able to interact with it. So that's something we should probably fix right off the bat. So the watch list controller, wherever we created this mini chart, this guy right here, we are going to say is user interaction enabled on it is going to be false just like that. And when I tap into this, we should see a chart here as well. So we see the char, but we see no chart data available. So let's see why that is. So I'm going to jump into my controller and stock details of view controller. And we're basically configuring this with no data for our header ViewModel. So what we're going to want to actually go ahead and do here is we're going to want to configure things properly. So what do we actually need to pass in here now we should have some candlestick data. We're going to want to reverse it. And then we're going to want to map the closing price from all of these. So we're gonna say candlestick data, dot reversed, dot map, not to AMP dollars zero dot close. And that's basically the data we're going to pass in to render out this chart here. And in this case, we do want to show the legend and the axes. So we'll go ahead and put Shrew there, even though we have now hooked up those properties. And let's go ahead and give it a run. So now we expect to actually see a graph. It won't look like our final product because we need to configure stuff, but we should see something. All right, still not seeing it. Let's see what the heck is going on because that's not good. We should definitely be seeing something here. I presume I have a feeling is because we're not calling configure upstream. So if I click into this, in this configure function, Let's see if I can find it. We need to configure the chart. So here message heart to view, chart, view. And we're gonna go ahead and configure this with the appropriate chart view model. So we'll say configure chart view model just like that. Go ahead and get rid of these line breaks like that. Go ahead and give it a run and hopefully we'll start to see our chart now. Hopefully I didn't miss anything else. Go ahead and give it a run, bear with it. And we'll select one of these and boom, we now see our chart. We've got financial data, we've got news. It's looking like the real deal, so this is looking pretty good. This is Microsoft's chart. Now one thing you'll notice here is we don't have any lake axes. We don't have anything that's telling us is this 30 days a month, a year, seven days. So I'll need to configure that with the ViewModel, but we have something to start off with. And the last thing that I'd like to do here is one final clean up in this video at least. And that is when we go ahead and let's search for maybe Twitter's stop here. And I'll see if it shows up. If I go ahead and tap on it, what the heck, we're missing our graph. So what's, what's the deal here? I don't see any graph. And the reason we're missing a graph here, it is because we're not actually even calling that render function. And it's because we need to fetch the candlesticks for the stock because we came from Search. So I'm gonna go into stock details view controller, and you'll see that we have a group dot enter. I'll see if I can find it if candlesticks is empty, but we're never seen grouped dot leave. So in other words, we need to make an API call here we're going to say go ahead and get market data for the current symbol. And this is going to give us results back. And we're going to switch on results right after we say Group dot leave. We're gonna switch on results here. And we're going to say in the success case you have a response. And we're going to say self dot candle stick data is going to be response dot candlestick data, response dot candlestick data. And otherwise in the failure case, we'll go ahead and say We're just going to print that error out. We want to make sure we say self optionals, we don't leak any memory. Go ahead and say weak self and give it a run one's moral, its search up Twitter and let's make sure we're seeing in our graph. All right, Bear with me, bear with me. Simulator loves to be slow when we're almost there, Let's search for a stock. So Twitter it is. We're going to click on Twitter right here and boom, we see our financials and we see the graph looking awesome. I'm going to add Twitter as a favorite Because awesome, Twitter's great and boom, we should have Twitter in our list as well, which in fact we now do. So let's see where is Twitter yet right there. And we can click on it and see Twitter. So we now have graphs and charts working. Now, you can get pretty wild with charts and customize it. And the next video we're gonna take a look at customizing a with colors and the axes and a legend. I won't go too deep into it, but I mean, there's a ton of things you can get away with in terms of customizing, we're going to set a solid baseline. So this is more functional and aesthetically pleasing, but that's all I've got for this particular video. Thanks for watching. I'll see you in the next one. 30. Chart ViewModel: What is going on, guys? Welcome to the next parts of the chart section. In the last part, we finally got our data plumped into the chart components and rendering. In this part, we're going to actually hook this up to the chart view model more so right now all we're doing is reading the data from the chart view model to plot our graph. But we're not doing anything like showing the axes are the legend or even a fill color. So we're gonna do that in this video without further ado. Let's jump right in. So we have these two things here for show legend and show data or show axes, I should say. But we're not really using them, so let's use them and then let's further customize a couple of things. So first and foremost, how do we actually use them? It's pretty simple. I'm actually going to do them up here instead. Now on the chart view, I'm going to say, let's see chart view. We're going to say that the right axis enabled. And I'm going to say, let's see if I can get it to. Pop-up enabled is going to be the ViewModel dot. And let's see a show axis just like that. And then similarly for the legit, I'm gonna do the same thing here. This is going to be show legend, just like that. Go ahead and give it a run and we need to talk a little bit about a couple of configuration options, as well as how to plumb in the color of our particular or particular stock. So here we don't see any legend or access which makes sense. But if we click into here now we start to suddenly see we have our legend here and we also have the prices here. So clearly Amazon's doing, doing pretty hot. So let's see our actual legend title here. So we see it just says some label, which is what we supplied here. Now if you recall back in our API color, we have defaulted the market data that we get. Let's see if I can find that. Call. The market data. I believe that we are actually getting is for seven days. So you can actually go ahead and say one week down there or seven days or whatever you want. You can also up this to be 30 days and say, you know, one month data. But I'm just gonna go ahead and say seven days here, just like that. If you wanted to support different frequencies, five days, seven days a month, you can have those buttons up here and just adjust as needed and fetch the data as needed. It's pretty simple at this point since all the pieces are in fact in place. The next thing that we want to actually do here is we want the color to reflect basically whether the stock is up or down. So how do we do that? So simply relating the color to the percent change is actually how we derive this red color here or the green color. Are we going to do the exact same thing here? So I'm gonna go ahead and save this takes in a fill color to our view model. And instead of making our fill color down here, this system blue, I'm gonna say this is Vw model.fit. We'll color. And if we do a Command B, you'll see we're gonna get a couple of errors and the places where we haven't actually supplied that fill color. So we're gonna deal with this 1 first, which is the watch list. This one's pretty simple. We're just going to say this is a view model and there is a color in here, I believe you models. This will be indexPath.row. Let's see, let's see how we want to do this. So we should have the proper, the proper our viewModel already. So here we're appending these view models. We have creates a view models for each of these. This takes in a color based on the change here. So I'm going to actually pass on the exact same color here. We don't need to calculate anything else. But in the other case, we do need to calculate something. So let's see, we have this comma here. Let me do Command B. That error should go away. And in this other case, we actually do need to calculate this same thing again. So we went to say get changed percentage for this particular data. So I'm going to go ahead and actually steal this function. And we're going to jump into here. And essentially what I'm going to go ahead and do is instead of just hard-coding this or something, because that's definitely not what we wanna do. We're going to drop this function right down here for get to the change percentage, which is going to return to us a double. So let's see, we're gonna save you change up here. Let's create it like so. So we'll say change is going to be get changed percentage for the given symbol. Are we going to pass in? Let's see if I can get the proper term are candlestick data right into there. And similarly here, we're going to say, if this change is less than one or less than 0, I should say it's going to be a system bread. Otherwise it's going to be a system green. And once again, as a quick recap, this function basically takes the data and it calculates the difference, the percentile difference in today's or the most recent closing dates and the prior date. So if you go ahead and give that a run, we should now have the graph appropriately colored based on whether the stock is up or whether the stock is down. So go ahead and do that. Everybody, hold your breath, cross your fingers and boom, we have green here, we've got red here, and everything's looking pretty darn good. So let's go ahead and select Facebook stock here you can see that it is down even though this graph says otherwise for the week. But this is basically doing a comparison for the prior day. So if you wanted to compare the actual duration, you would just grab a date for a week back. We can see this is a seven days graph. We can also see the trading price here. And we can even link select this if you wanted to disable interaction, you can do that as well if you don't want it to be selectable. But this is basically our completed application. Now we need to still do some Polish work with things like haptics and things like unit testing and this and that. But this is the majority of the application in its finished state. So we've got our details here. This is Snap. We've got a whole lot of news. We can scroll through these and figure out more about what's going on with this particular stock. We've got a beautiful chart up here. We've got our watch list that we could of course, edit and update as we see fit. We definitely don't want to delete Facebook here because we want to keep track of that stock. We've got top stories so we can collapsing case. We're getting tired of seeing those stories. And of course we have our search functionality. So that is the end of this part. We have come a super-duper long way. In the next part in section, we're going to dive a little bit into talking about iOS as a career. Now that we've built out this app and you should have a fairly solid portfolio piece. I want to get a little bit into some career advice and learning a little bit about the struggles and the benefits of being an iOS dev and the do's and don'ts. So basically the things that I've learned over the last ten plus years of being a professional iOS dev. So thanks for sticking around and I'll see you guys the next part. 31. How Much iOS Pays: What's going on, guys? Welcome to the next part in our section. In this part we're gonna be talking about how you can get paid, rather how much you can get paid as an iOS developer. So here we are all levels out FYI, a very popular website amongst the tech community. We're gonna take a look at how much iOS engineers can earn and how you can earn upwards of a million dollars a year. So it's no secret that tech pays very well. Ios is no exception. You can get anywhere between 70 thousand as an entry-level engineer, it does depend a little bit based on cost of living of your area, work from home and all that good stuff. But you can make anywhere between 70 k to 1 million plus annually. Now, on this website, we're going to specifically be taking a look at different companies and what they're paying their iOS engineer. So on the landing page here we can see that we have three companies. It shows us the levels for those companies. And more specifically, if we click on any of these levels down here, it'll pop up a box to show us what that person at that level is getting paid on average. Now that's not the most helpful thing for us because that's averaging all the different type of software engineers, both entry-level, senior, different disciplines, distributed systems, Android, iOS, security, et cetera. And we specifically care about iOS. So let me see. Let's come down here to a particular box and we'll go ahead and see which are what they're getting paid, I should say. Now, these three companies here are just a defaulted ones in this list. This website basically has any company you could think of that you would want to hear more about. You just search for the company and it'll go ahead and bring it on in here. Now there are particular big tech companies that pay higher than others. Admittedly, Google, Facebook, Microsoft, Apple, of course, we'll pay the biggest amounts. And the way these compensations are put together is basically a salary components and annual stock component, which is, you know, you can sell it right away or hold onto it and it can appreciates. And lastly, we have your annual performance bonus, which is a cash bonus. So this is essentially how you can go about making these pretty, pretty decent figures, I would say pretty crazy figures. And you can compare the different levels between companies. But what we want to do is not actually click on the company at the top right, you're going to see all the salaries and there is this view all link. And if we go ahead and select it, It's going to show us basically all the salaries submitted to levels I'd have phi and we can organize these are sort these I should say. And descending order by pay for someone to change it to show us a 100 rows so we don't have to keep going between pages. And then we're going to filter it out to basically have the highest paid individuals at the top. And you can actually see the very top one is a Iowa's technical director and is director is at, let's see, is at Apple. And they are making over a million dollars a year, 1.4 million. And you can see the breakdown rate below. It's a little dull. It's hard to see around 300 plus K for salary, 975 for their annual stock, and then a pretty hefty bonus as well. Now of course, a lot of us and most of us are not going to start off as technical directors at Apple. We might not even be an apple. So you might be wondering, well, this is absurd. I'm not a technical director. This is not how much I'm gonna get paid. So as we continue down this list, you'll see that there are quite a few people at different companies, companies like Facebook, Uber, we even have VMware I saw earlier in this list that are making around a million dollars a year. Keep in mind that this is gross income. Now, this is like pre-tax, basically not after-tax. But the thing that I want to share here is and iOS engineer out of college can be making $200 thousand. And you don't necessarily need a college degree for that matter as well. So the way that comes together is you would earn anywhere between a 100120 as your base salary. You would add in some stock component, let's say like 30, 40 thousand for the year. And then you would have some performance bonus at the end of the year. So we're just going to go through this list and see what we can find here. There are tons of other disciplines here as well, not just IOS, you'll find some iOS and Android you'll find Distributed Systems, Security, back-end, front-end, you'll find all different types as website is not limited to iOS, but iOS engineers are some of the highest paid software engineers. It is a subset of mobile engineering that is going to be thriving, I would say for at least another decade, every company and organization needs a high-quality mobile app. Some companies need more so than others. If you think about a company like Facebook, a lot of their business is built off of their apps. So things like Instagram soon simply for Uber, we saw Uber in this list here as well. And Uber is literally accompany based off of an app. Same thing for DoorDash. And do these companies have peripheral businesses where you can access things on our website? Of course they do because it'll be not very intelligent, not to. But the point that I am trying to drive home here is iOS engineers are some of the best paid, some of the most well treated, and some of the, you know, the most highest job security roles, right? The retention of iOS engineers is usually a top priority in engineering or eggs, because if you don't have people to build your flagship application, guess what? You're out of a company and you're out of a product. So we're going to continue on here and see what other roles we have to look at. And let's see. So here in this particular case, we're looking at DoorDash. We've got iOS and E7. This person's making an absurd amount of money, a $100 thousand for the year 900, I should say. Now, of course it's going to take you some time to get there. The third column here, you can actually see the years of experience somebody has. The number on the left-hand side is years at that company. Number on the right-hand side is total years. So some of these people at a or seven years or nine years, right? Not everybody has like 20 years. Now these positions are fairly up there. We've got staff engineers and L sevens. But if we do scroll all the way down or we continue to go across different pages, you'll see that there are different, different levels that are all making very healthy sums of money. Now we also find companies in here like VMware, which you would, a lot of you might not even know a VMware is, but if you do know what it is, you would be a little surprised to find out that they have iOS engineers working there, right? Like what app Can anyone name for VMware personally, I can't name any. I'm sure if I search the abstract will find something similarly for Cisco, I'm sure they have something they make. And these are companies that are paying very well slack we saw there in the list and Slack is paying their staff engineers, you know, a million plus. So hopefully I've beat the dead horse enough that you can get paid very well as an IOS engineer, put in the work, climb the ladder, no matter where you start, it starts one day at a time and keep learning your technical skills, develop those soft skills and expanded scope. And U2 can climb the ladder and get there. So that is all I've got for this video. And let's see if I can scroll and find some more interesting information in this list anymore examples, and I'll catch you guys in the next part. 32. Documentation: What's going on, guys, welcome back to the next part. In this part we're going to start to talk about documenting all of our code with documentation strings, otherwise known as doc strings. So let's go ahead and jump into our xy workspace here. And what we are basically going to accomplish is documenting all of the functions, classes, structs, and other pieces of code that we have written. So let me go ahead and open this on up and bear with me here. And as soon as it decides to load, we are going to jump into our project tree. So let's go ahead and do that. And, and we'll talk about how we want to document everything. So let's go ahead and jump into here. Whoops, to nothing to close Xcode there. Let's open that up one more time. Xy workspace. And we'll jump into here and then we'll start up in our very first folder. So that is other. So we'll start on the AppDelegate here now in the AppDelegate, now we can document this, but generally speaking, I don't like documenting things that apple already has documented and we'll probably skip over TableViews by a quick shortcut. You can hit Command out till the shortcut here is Command Option backslash, and it will give you the outline to document something. So in this case, it gives us the place holder for this class. We can also do that for functions and wants to leave as debug function. First of all, since we don't really need this anymore, we're basically done. The other thing we are going to do is get rid of this commented out code since it's just verbose at these points. And just like that, we can add a documentation string for this function. So generally the first thing you put in the function at the top here is a description of what the function does. So it gets called when the Apple launches or HIV launch, I should probably say, but it's fine. Then you specify what the parameters are and what this function actually returned. So you can specify the type which is a Boolean or you can specify something for in terms of what the bull represents. This case, the ball is going to be success or failure. Now I'm not going to document the rest of the things in here since Apple related code. And we can just go ahead and now here if we actually go ahead and call that function, you should see the documentation string. But the reason we're not going to actually see it here is because we're going to see Apple string tells a delegate when the app has finished launching, but in our own code. But you'll realize is that the documentation string is what you see in this autocomplete drop-down when we do go into our typing out a function or a class. So that said, let's go ahead and jump to our next file. In this case we'd seen delegate. All I'm going to do is delete all this commented code so we don't have such verbose code, we're not using any of these functions are, are relevant to us for our app and our project. So I'm just going to delete it. You can optionally lead the lever here. But personally, I just like getting rid of it because it just makes a little cleaner so we'll get rid of that there. And here we're going to say that this window property is our main applications window, just to specify that there now I'm not going to do anymore in there. So let's jump into our extensions here. So inner extensions we can write our expenses for each of these. So this first thing is a notification which notifies us when something I've added a symbol got added to the watch list. So we're gonna say that as such. And basically I'm going to go through the entire project and write out some documentation strings. We'll go ahead and fast-forward this younger ones to sit here and watch me type all of this out. But before I do that, some things I'd like to call out. First of all, why are we doing this? The reason we're doing this is because as you start to build out a project, especially professionally and it gets larger and larger. It's a really good habits and build out to document your code in our only helps you remember what a function is supposed to do, but it helps others of you work in a team environment. It also allows you to generate documentation websites for those of you that really like Apple's developer dot apple.com slash documentation. If you ever notice all those pages are consistently, they look insisted that consistently designed. Those pages are actually generated from Apple's own documentation. And a lot of companies professionally have standards that require that sort of documentation. So it's a little subjective. Some people find it a little tedious to go and do, but I promise you that it does come in handy and it makes your quality of raw just improve. And we're doing this exercise after we've written out all of our code, generally what you should probably be doing is documenting as you go and that way, you don't have to think back in terms of what a function or a class does. And it's under chore afterwards. So let's go ahead and we'll basically go through the super quickly. I'll just fast forward it here. And once you get your code documents in our heads, all guys in the next video. Hi. Okay. All right. Hi. Okay. Hi. Hi. Hi. Hello. Hi. Hi. A good strategy. Okay. Okay. Hi. Let's see. Okay. Okay. Now. Hi. Okay. Hi. Hi. Hi. Hi. Right. Hi. Hello. Hello. Okay. This recording. Okay. 33. Haptics: What's going on, guys? Welcome back to a, another part. In this part we're going to start to deal with haptics, otherwise known as Little vibrations you can feel in your device when various interactions occur. So in our app in particular, we might want to have some interactions occur where a haptic to occur when we tap on maybe a cell or some event occurs that is successful or a failure. So we'll talk about that. So we're going to start by jumping into our haptics manager object here. And we already have this function declared for vibrate, for selection. We're going to want one more function. But essentially, what we want to happen here is every time we select something, we're going to play a very subtle vibration. So a lot of apps do this, apple does it themselves, and a lot of places. They really bring a new sense of depth into your application. It's really, really solid in terms of a user experience. So I highly recommend you guys take a little bit of time to go and add haptics. So here we're going to start by creating what we call a feedback generators. So we're going to say let generator is going to equal a UI. I think it's called the selection of feedback generator. Let's see if I can find it. Ui feedback, it was a couple of them, yep, selection feedback generator. Then we're going to say generator dot prepare. And then we're gonna say generators selection changed. So that selection changed function is a little misleading. But what it basically means is whenever the selection chains gets called on this generator, it's gonna play a very subtle haptic. So essentially when we tap on the news cell or a watch list cell or basically any type of selection. I like using this and a lot of places. And let's add our second function as well. Our second function is going to be vibrate for a particular type. There are a variety of different types that a UI, I believe is called a notification feedback generator offered to us. So we're gonna say vibrate for type, there's a feedback tap off of it. And I'm just going to copy and paste this because all that changes is the name of the generator and we are also going to say generator dot prepare. Then generator notification occurred and we just pass in the type. Now let's click into that feedback type so we can actually see what are the various feedback types that are available. I think there are three. Let's see if it loads. All right. So I believe there are three success warning and error, and they basically have a consistent haptic that gets played. This is also used by a lot of other apps that we generally want to play a success when something happens like adding to watch list perhaps and error when we want to show like an error. So let's go ahead and be good citizens and document this because we've just talked about documentation. So play half-day for a given type. And we're gonna go throughout our project and added these haptic manager calls in various locations. So the one that's going to be fairly common is going to be in our cells. Selection did select row at index path functions. So selecting a watch list cell, selecting one of these new cells. So we can jump through our controllers and find all those places. So let's go ahead and do that. We'll close up that folder, open this up. And inside of here we're going to serve. So C command F does the trick. So here is where the search results gets selected. So we definitely want to play a hop sequent. This occurs too. So I'm going to start by dropping a haptics manager colon here. So we're going to say haptics manager shared and I believe I called it vibrate for selection or via hybrid first selection. I'm going to copy that and here's did select row. We're going to paste this in here as well. This is when the user selects a item in there watch lists. So basically any of these cells that you see here, we're going to move on over to the next controller, which is going to be our news controller. And in our news controller, we're going to essentially wants to do the same thing. It did select the rows. So basically whenever a news item is selected place subtle haptic. I think that's the only one that we want in here. So moving along to the search results, now there is a did select, but our delegate upstream is already handling this. So we don't want to redundantly add another haptic there and I don't think we need a haptic anywhere else in here. And it will jump to our last controller. And our last controller we have a did selected here for the news cell. So let's go ahead and do that. Or we're also going to want to play a haptic whenever somebody presses the Add button. So let's go ahead and in the, in the ADA it, so in this case we want to have to care for the selection. And then right down below it, if you take a look where my cursor is on 265, we have the function which handles adding something to the watch list. And that is a success case, right? So in this case we're going to say vibrates for a particular types are going to say vibrate for type. Let's see that one right there for a success. And then we're going to copy this. And we also have a case where we're unable to open up a new story. There's an alert that we show. I believe it's in the watch list controller. Let's see if I can find it. When we showed that error alert, we also want to play a error in our vibration error haptics. So it's right here, actually present failure, present fill to open alert. And we're going to change this to an error. And this is basically the ins and outs of how you can have haptics in your application. Really brings your app to life, make sure everything's compiling and building. Now of course, you won't actually be able to see the haptics in your simulator because your computer is not going to vibrate because that would just be crazy. So you definitely want to run this on your physical device to see what the haptic feels like her feel what the haptic feels like, I guess I should say. But yeah, definitely don't cut a corner on haptics and really bring your app to life. That's all I've got for this part. I will see you guys in the next video. 34. Introduction to Unit Testing: What's going on, guys? Welcome to the next part in our section. In this part we are going to be doing a introduction to unit testing. Unit testing is all, all but basically required for professional work, right? So it's kind of an unsaid thing where you really need to know how to do it. It's the process of testing various units in your application, specifically looking at functions and classes and things like that. And we actually have a primate thing in our application. Now we can test here so that being this market data model, we're going to test that our candlestick conversion from the market data is corrects all of this logic that I've got highlighted here. So things like ordering, sorting by dates, making sure the number of elements are correct, et cetera, et cetera. So how do we actually do unit testing? Where do we put our unit tests? What the heck is a unit test? So on the left-hand side here you'll see all our folders and at the top you have stocks, right? Our main project products, pods and frameworks. We essentially want to create a new folder which is going to be a new target to hold our unit tests. So we're gonna go to File New and we're going to find targets. And in the box that appears, we're going to search for unit. Now we want to select the second one, not the audio extension. And we're going to want to create a testing targets. So stock tests, it actually shows us what our app icon, what we're testing, the current project. And of course, your language should be swift. Now we can leave the default name, go ahead and create it. And once you've created it, you're going to see it. Let's go ahead and verify that name is correct. We'll create it and we'll see here that it gives us a new folder called stock tests. And it actually gives us a template file in there to start writing our tests already. So basically, we have all of these things in here. We're going to delete all of them and we're just gonna do is simple, just example that's not related to stock. So you guys can see what tests are. So for example, let's say we wanted to test that in integer maybe a one is equal to a string converted to a it. So maybe here we'll say let number is going to be one. And then we'll say let string is going to be the number inside of a string, so I'd like that. So now we can assert that these two things are equal to one another. So I can say FCT, assert equal the number and then the integer variant of that string. And how do we run our tests? We can hit this little diamond next in the class here it should show up next to the funk as well. If it doesn't, you can just hit the class and like that it'll start building to test our application. Now of course, we expect this to succeed. We should see green check marks on the left-hand side here. If it does succeed, indicating that, you know, everything past, of course it passed because these this condition is correct. Now, I want to show you guys what happens if it's incorrect. So what happens if I change this number to be 12, right? This should fail. But let's take a look at what it actually looks like when it fails, we expect to see basically a Red Cross. And we'll see me a error or rather we will see an error on the line that actually filled, boom, it fill there. Now we have a generic error for the failure there. But if we wanted to specify our own custom error or a string to show, we can specify that as the third arguments here in the FCT assert. And we'll see it basically on the right-hand side. So I'll go ahead and say Here, numbers do not match. And that's what we'll actually show up on the right-hand side. Now, we looked at her and there's actually a whole lot of other things you can assert. You can assert the things are not nil. You can assert things are nil, true, false, greater than something else. There's a whole lot of conditions that you can try to verify. And this is basically the principle of unit testing. Basically, you know what the input and outputs are for code. And you're going to assert that your code is doing what you wanted to do by asserting various conditions. So we're just going to leave this function up here and we're going to write another function down here to actually test our, our model. The first thing we wanna do is do a testable import of stocks, which is the target we're testing. Now some of you might run into errors when you're importing this and it's related to CocoaPods. So I am going to show you what you can do if you run into these errors. It looks like I'm numbering into the errors. I suspect you guys shouldn't as well. But in case you do, generally the error is the fact that we need to also install our dependencies to the test target. So what does that actually mean? So if you guys recall, we had created a pod file, and in that pod file we had added a bunch of different targets. So we need to open up our project, go to that pod file and we have this single target here. Well, we would wanna do is copy and paste it and just change stocks to stock tests. And what this is going to do is install these three dependencies, floating panel as T web image and charts into your test target as well. And that way it'll resolve any errors that you might be having if Xcode can't find something. So let's go ahead and add our function to test our actual candlestick conversion here. And basically, now that we've got a testable import of stocks, well, we want to start by doing here is creating an instance of the market data model. And then when we call candle sticks off of it, we're going to actually go ahead and start doing some assertions. So here we are going to line break all this stuff and we are going to pass in some data. Maybe we can just pass in some dummy data. So status is going to be a success. And the rest of these we need to pass in an array of doubles. Human actually, I'm thinking about it now instead of doing it this way, this way might get a little verbose. Maybe what we wanna do is use a repeating array. So that way it'll minimize your code and it will also make maker code consistent across the properties. So let me think what the best approach to do this is. You can write your unit tests in a variety of ways. So let's actually delete this here. And what I'm gonna do is create an array where we're going to repeat a double. So here we're going to say doubles and we're going to create an array and we want it to be repeating and see if auto-complete it's gonna do its job. So we're going to say repeating and we're going to pass in a double here. So it looks like we have an issue was as rented out. So we'll see what the actual problem is. So let's see why this is the anatomy already. There needs to be an equal and we still have an error here. And let's see why that is. It's because I have a typo in here actually. So what we probably want to go ahead and do is just delete this whole thing. Autocomplete, do its job. So boom, repeating, we're going to pass in some double here. The way you're going to specify a double is by just doing a decimal place. So we'll say it's all point to, and we're going to have ten of these. All right, Now we're going to explicitly make this a array of doubles. And now what we can actually do is we can create our market data and pass in doubles for all of our, all of our stuff. So we'll say market data, all the properties I should say parameters. And for each of these, Let's first line break it so open and close, high and low. And we're just going to pass in doubles for each of these arguments that taking a array of doubles just like that status, we can go ahead and make this status or probably success is probably a better thing, so it's updated to success. And then we have our timestamp here. Now, what do we wanna do here? We basically want to show a array or pass an array of timestamps. Let me just create one timestamp up here. And we're going to have a way to create multiple in an array. So here we are going to save this as a time interval, and by default it is going to be in array repeating. We're gonna do the same thing again, and we're going to repeat the current date time intervals since 1970 and counts should match, so it's going to be 12 in this case. Up there we have repeating ten. So let's see, let's see. So little toss that in there and we should be good to go. So now that we've got this created, we actually probably want our dates to be different because the function for candlesticks actually sorts everything in descending order. So the most recent dates to the oldest states. So instead of just doing this repeating business down here, we'll make an array in a second. But first, let's go ahead and pull out our candlesticks from the market data. And next we can basically try to do our assertions. So our assertions or basically encompass figuring out that the number of elements in open, close, high, low, and timestamps is equal to the number of candlesticks that we get. Before we do that, let's go ahead and make an array here where we dynamically create different timestamps. Because if we just use the same date over and over, we can't really test, you know, if, if it's different. So we're gonna say for underscore in 0 up until 12, which is the number of elements that we have now in our, in our, in our dates are that we had on our dates. We're going to append dates, adding time interval 3600, which is an hour multiplied by time interval of x, which is our underscore that we just updated it too is an integer. And then we're gonna go into time interval and basically upended this whole thing up here. So we'll say this is an interval and toss interval down there. All right, so now that we've got this, the next thing that we want to do is start working on our assertions. So in our actual assertions here, the simplest thing is to start asserting equals our candlesticks dot count, right? Let's see what's going on there. And candlesticks dot count. And we want to assign this to be equal to, let's give, let's get rid of that typo to 12 here and let's make sure actually, instead of even doing 12, we can just say because that's not an, it's an arbitrary number. And I purposely mixed and matched 12 antenna up above. We're going to say this is market data open, close, that counts open dot count, Haida accounts and load account because the counts of all the input data should match the number of candlesticks that we get back. So now that we've got this situated, we probably can go ahead and give this a run before we move any further and make sure it passes. All right, so bear with me here and we want to make sure that it passes. It looks like let's see if we give it a run. Let's go ahead and give it a run. So that's the timestamps shuffle. Let's actually shuffle up our dates first. So well, the reason we want to shuffle or dates is so we know that the candlestick parameter, the candlestick property getter, is actually doing its job because we're going to verify that the dates are in fact in the proper sorted order. Now how are we actually getting? Go about sorting our collection and testing it. We'll see that in a moment. But so far it looks like our test has passed. So let's come down here and let's write out that sorting function. We're going to say verify sort. Now how do we want to do this? So you can create a, another sorted array of dates. Or a simpler way is, you can say get the, get all the dates. First of all, in the array, we can just do a for-loop and we can verify that the current date is less than the next date in the array. We want to go ahead and do a for-loop up until the second to last element in the array. And by doing it that way, we're going to verify that we're not out of balance. So if we come up here, let's take a look at our timestamp. So we're gonna say four. Let's go ahead and create our for-loop here. And we're gonna say for x and 0 up until a Dietz dot count minus 1. Again, we do minus1 to make sure we're not exceeding our balance when we try to get the next elements are current will be dates at the current position. And the next will be deeds x plus 1. So x plus 1 and the minus one up there is critical because if you don't do minus1, you're going to see your test actually crash. And the next thing, the last thing that is left to do is basically do an assertion. So our assertions here is going to basically be xy assert true that the current date is greater than the next state. Now the naming is a little confusing because we used next, but next is next in the array, not the actual date after. So if we go ahead and give this a run, we should see the function is passing. All right, build succeeded. Let's make sure our function actually passes here. And once it does, it should hopefully, we can go ahead and verify the regular has passed or also verify that our function properly fail. So if I go ahead and make that a less than sign and run it one more time. You'll go ahead and see that we get an error on that line. And because the current date should not be less than the next state. So let's go ahead and give that a run. And boom, we have filled, we see our error. We also see the error on that line. And we can go ahead and give a string here to be printed out saying the current states shouldn't, shouldn't be greater than the next date. And that way we get this printed out instead of whatever the default is and we'll go ahead and fix our greater than sign. All right, so we're almost just about done here. We want to verify one more thing. And last thing is the number of elements inside our time intervals, so our timestamps, so we can go ahead and copy and paste this and simply say that the counts of candlesticks should match the timestamps dot count. And we can go ahead and give it a run, one final run, and we should be good to go. We've written our first test for our stocks application. Now there are a bunch of other things you can unit test in our app. Anything that's doing business logic, we have some math calculations in our controller for the percentages. So generally that is a good candidate you can do it for. So let's see if I can find it. Let's see, Let's see already up. It's this function right here. So getting this percentage, this is a good candidate for doing a unit test simply because it does some basic math calculations and you can verify that your math is indeed correct. So if you want to take a look at other unit test examples, there's plenty you can find various stack overflow pages, but definitely don't cut a corner with unit testing. It is really important and it's almost a requirements for professional work since you want to build out things that are high-quality, where the code does what you wanted to do and there are no mishaps. So that's unit testing. In a nutshell. Hopefully you guys got a good glimpse of it. Thanks for watching. I'll see you guys in the next part. 35. Optimizations: What's going on, guys, welcome to the next parts in our section. This is arguably my most favorite parts and early most people's favorite part, and that is optimization. So we're going to polish things up and optimize. So the last part, we took a look at a unit testing here. So we are on our unit test. So we're going to jump into our project code and actually optimize some things. So let's talk about what to optimize. Let me go ahead and run our app here. So there are a couple of things I want to optimize. First of all, I want to get rid of duplicated code. The other thing that I'd like to do is sort our our actual watch list. You might have noticed if we go and close and reopen the app multiple times, we get the watch list data in a different order every time. And the reason for that is because we use a dispatch, a group to go and in parallel fetch the different market data. So it's kind of a race between which data comes back into our model that we end up showing in our actual table. So what is a solution to this? There are a couple of ways you can do this. But before we even do that, we want to get rid of duplicated code because duplicated code is not good at all. So let me do a Command Shift F for a project wide search. And we can see we use this get change percentage in two different places. We pass a symbol and data in. The first thing that we are going to tidy up here is the fact that we're not even using this symbol parameter. We're actually just passing it in because originally we were printing it out for the purposes of just debugging. So let's go ahead and get rid of the symbol here. Let me just verify that it's not used anywhere in this function, it is not. So we can highlight and delete it. So sick of that. And now we're going to want to go and find where this function is called, n, delete it from here as well. Let's go ahead and do this exercise on the other controller as well so we can get rid of the redundant, redundant symbol parameter. So let's go ahead and do a Command Shift F will get rid of symbol there. Boom, and let's see where the color is for this. So let me scroll up and see if they can do a Command F. Let me get rid of the comment first, Seidel, forget to do that. And let's see where this is being called from now before I even go into the other one, let me actually copy all of this code and we are going to cut it and move it into an extension. So come all the way down here and let me do a mark for an extension on our I guess we can call this I candle stick sorting or call it whatever you want to. Basically, we're going to write an extension on an array where every element equals a candlestick. So this is a fancy way you can write array extensions that you can specialize for the type of array. And we're going to create a function in here. And this function is going to basically give us our percentage back so you can go ahead and call it whatever you want. So let's see, let's go ahead and call it get percentage. And it's going to return to us a double which only to stick in there. And I'm just going to paste in Oliver logic. So let's go ahead and add a double and do a build and we still see some errors. So it's complaining that it can't find data. And the reason it can't find data is because there is no data, right? Self is what we need to replace it with because we are in an array. So self represents the data of candlestick data. So we'll go ahead and do that. And just like that, we are good to go. That's all we need to do. The last thing that is left is we need to actually call this function from our various places. So instead of even calling that function there, Let's see if we can get away with cutting this and making it cleaner. So let's see. So we want to get rid of this get changed function. We're gonna delete this whole thing. So let's see, let's get rid of that. And we'll also get rid of this function here since we just moved it. And this is where we're invoking it. So instead of doing this, we can actually just take candlesticks and replace this with that and say dots gets percentage, boom, look how much cleaner that is. And in addition to it being cleaner, it isn't duplicated anymore. So let's see if we can do this on our other one here as well. So here is the gets changed percentage. We're going to go ahead and simply delete this. So we'll go ahead and copy this whole thing backspace. There is our function. And let's go ahead and say candlestick stop percentage. Maybe we can even move it down into our parameter there for the other object actually has little backup there because we use it to calculate the color as well. So never mind with that. Make sure you write clean code but don't over-engineer. Otherwise you just end up being a little messy there. So that is our duplicate code reduction. Let's make sure we build and run and everything is still functioning as expected. Nothing should have broken. Let's see what I botched here. Something is broken. So we have let's see, it looks like this is our, this is actually just a unit test error. So we can do a command shift K to clean our project. And we should hopefully see that error go away. It should not be a Builds error. Execute does this weird thing where sometimes it'll just show these lingering unit test failures even though it's off filling anymore. But let's go ahead and clean and then do a build again, which will rebuild everything. So command shift K to clean. So once you build after that, it takes a couple more seconds, but should be done hopefully soon does not take that long. We just want to verify that our duplicate code deletion didn't break anything. It was good to verify it iteratively. Or product has launched. Looks like a compiled, which is good. We still see that error on the left as we can just disregard at this point. All right, so we still see our data. Everything's like an a. Okay, we are good to go. So the next thing we wanna do is start to sort our actual watch list. And then the watch list, like I mentioned, that there is a race condition because we're fetching our elements in parallel. And in other words, the view models are going to be created in order that matches our watch this map. So here if we take, keep our eye on Twitter, we can see that the Twitter simple actually moved to a different position in the watch list. And here we're going to come into the watch list controller, and this is where we are creating the viewModel. So how do we actually want to handle this? So instead of doing something fancy in the model, well, we can actually go about doing is we can simply say for this view model, we want to sort it by this symbol alphabetically. So how do we actually do that? So we come to this function for CreateView model, and regardless of which order we have gotten our actual models back, we're going to do a sort in here before we assign it and refresh our TableView. So let's see what we're doing here. So we're iterating over our watch list map, which makes sense. And for each of these we just append and our watch this map will be a different order every time and they'll be assigned to our view models global property. So here I'm just gonna say sorted by and let's see if we can get this correct. And we'll say $1 dot, I think it's symbol. Let's say $1 dot symbol is greater than $1.1 dot symbol. We should be good to go, go ahead and give it a run and looks like it's yellow and that meal and see what the problem is here. Dollar zeros symbol greater than dollar war. And that looks correct to me. Let's see, Let's see. Ha looks like it's yelling about something. Let's read the error. It's because we have a replace the dollar zero-tolerance 0. Let's see what's going on there. 1 is 0. What is a yelling EMEA, we have an extra $1. Okay. So get rid of your little typo. If you made a typo and go ahead and give it a run, and we should now see our symbols alphabetically sorted. Now we'll figure out if I did the proper greater than sign looks like it is reversed sort is because Twitter, snap, Microsoft. So we're going to choose greater than to a less than sign. And just like that. So we will hopefully have everything sorted. Array bear with me, bear with me. And let's take a look. Let's take a look and it should all be alphabetize. Awesome it is we've got Apple, Amazon, Facebook, Microsoft, snap, and then Twitter. So the last thing that I'd like to do in the optimization is if you ever notice when you open the app, sometimes you just see an empty watch list because the data's being fetched just like that and then it pops in. It doesn't look too great. So we can either add a spinner, which I'm not a fan of, or we can add some dummy view models and we can show some data for the stocks that are coming in before we actually get the actual market data to render the price and the chains and all that stuff. So how do we actually do that? So here we are creating the view models and this function gets called and the dispatch group notify. And up here in the fetch, our watch list, we have symbols. I'm gonna go ahead and call a function here that will create, which is going to be creates placeholder view models. And essentially it, Let's go ahead and copy this into this function. We're just going to create view models for the symbols we know that we're fetching and we're just going to supply dummy data into our view models. That way, our table will have something to immediately render. Let's copy these symbols down there. All right, and for each of these symbols, we can basically go ahead and add in a ViewModel. So I'm going to say view models are append. And actually instead of appending, this way where we probably want to do is loop over our symbols. So let's see, let's do symbols dot for each. And we want to go ahead here and say item in which is going to represent our symbol. I will say view models dot append. And we're going to initialize a ViewModel. We're gonna say symbol. That symbol means line break all of this. So this is going to be a UserDefaults standard string for key where the key is the symbol. Just like that. We'll go ahead and just make these prices and changes is 000, because we don't want to mislead the user with an incorrect value. You can of course, specified dash there as well. If you don't want to even supply 0. System green or sigma autocomplete is playing some tricks on me. Let's see DES and wrong typo somewhere. Sometimes going on on the line break all of us. All right, so let's see, something is off here. So what I'm going to go ahead and do is let me delete this and actually try it one more time. Sometimes he's execute errors are the most useless thing as you guys probably have noticed already. So let's see, I think it looks correct to me. Maybe we need UIColor. There's a system green. Looks like it's still not picking it up. So we definitely have a typo somewhere here. Bear with me. I'm sure you guys can see what I'm missing. So it looks like is yelling at me here. So let's see. That is item Okay. Not symbols. That's correct. That was a typo. We wanted to put the item. They are not symbols. Looks like it's still yelling at me, so we still have something wrong here that I'm probably missing. So let's go ahead and delete it and try this one more time. All right, so we are going to go and we're going to try to iterate over symbols. We're getting item in. We're going to say our view models, we're going to append array. We want to append the new element and we are going to create one of these elements. I'm just going to line break will say inits. Simple is item, Okay, Makes sense. The next thing is going to be UserDefaults standard. And we're going to say string for key. And this returns are, Here's otherwise it returns an optional. So we want to coalesce a company string has a default value, then the rest of the steps should all works. A price we'll say 0 dot 000 change. We're going to say system green. I'll re, now everything is working or the autocomplete, happy, I'll re, and the chart ViewModel we want to pass in one of these guys as well. Data will be empty and there was a false and a false. All right, We should be good to go. Let's just line break all of this and let's see for the color here, we'll go ahead and say clear, since we don't want to show a chart by default, Just line break all this and make sure it's all looking good. And at the end of this, we probably want to refresh our TableView. So we're going to say TableView dot reload data. All right, let's go ahead and give it a run and let's make sure we're seeing our dummy placeholder. So basically we should see something immediately instead of it coming in after a second because it's easy to see the delay. So it definitely is working. The data comes in afterwards. One thing that looks a little strange is it does look a little choppy in terms of how it's jumping once we do get the data. So you can go ahead and update the cell one at a time. You can figure out how to update with a ViewModel, but I think it definitely looks better than before. Optimizations are a pretty broad area. You can go as far as you would like to, but let's go ahead and look at that one more time and we can probably wrap it up there. Our wrapper with me, bear with me. All right. So definitely better than what it was looking like before. I don't know if I'm particularly satisfied yet with there, but I'll I'll leave it here so we don't end up spending an hour on this. So that is all I've got for this particular video. We're in the homestretch of our entire class. So that as you're sticking around, I'll see you guys in the next video. 36. Thank You!: What's going on, guys, welcome to the final video of our class. If you've made it this far, start by giving yourselves a huge round of applause. We've made it, we've built out our stocks app. We've talked about career advice, We've polished it. We looked at unit test day. We've done a whole lot of work and I keep saying we you've done all this work. So I just wanted to take a moment to recap everything that we've learned here. Say a huge thank you for you joining me participating in the course and also inviting you to connect further. So what did we build? Of course, he built a stock app that we looked at networking, we looked at building our custom views. We looked at protocols, delegate, pattern, architecture memory. We looked at bringing in dependency and a whole lot more.