Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save maximveksler/8620893 to your computer and use it in GitHub Desktop.
Save maximveksler/8620893 to your computer and use it in GitHub Desktop.
Captions for Stanford CS193p Developing Applications for iOS Fall 2013-14, Lecture 6. Polymorphism with Controllers, UINavigation, UITabBar. For more info visit http://maximveksler.github.io/CS193p/
00:06 >> [ Background Music ] Stanford University.
00:08 >> Okay. Well, welcome to CS193P. This is lecture six -- six, yes, of fall 2013-14. So, today we are going to have a little demo at the beginning. I want to talk to you a little bit about polymorphism with controllers. In other words, using inheritance for -- in the world of controllers, and those of you who -- for whom object-oriented programming is not that facile quite yet, you might be, kind of like, oh yeah, I guess I could subclass my controller, and in fact, you do want to subclass your controller, and it's quite common to subclass controllers. As I said, iOS is, kind of, all designed around object-oriented programming, so you get to object-oriented principles everywhere in the system, so I'm going to show you that today, and that's to help you a little bit get you started on your homework, because what I' m going to ask for your homework is for you to add a second card matching game to your Machismo. Now this second game is almost identical, plays by the same rules and everything, it really just uses a different deck of cards. Okay, that's the primary difference, so you'll, obviously, have to update your modal to have this extra different deck of cards, but your game playing logic and the basic part of your controller is the same, but we don't want to have playing card wiring into our controller, so we're going to use inheritance to create a playing card specific one, and then keep a generic one that we can share for the other game, so we'll show that at the beginning. Then we're going to dive into how to get multiple MVC's in your application. In other words, how to make your application have more features than you can just fit on one little screen. Okay. And the critical, obviously, to building any kind of complicated or sophisticated app is to be able to expand your feature set, even though you're talking about being on a device -- it's a small device, it's a very small screen, that limits how much UI you can put on there at a time. And then I'm going to do a demo towards the end where I'm just going to, basically, show you -- I tell you I always talk about what I'm going to do, then I demonstrate what we're going to do, and then you do it for your homework, and that's exactly going to be true today. So I'll do the demo with Attributor that we worked on Monday. We'll enhance it to have multiple MVC's. Okay, so let's talk -- do that demo first. So, we're going to take the Machismo as of last -- at the end of lecture three, so this is prior to all your homework, and if you remember then, the storyboard looks like this, we just have 12 cards and the score, really, really simple. And we have this card game view controller. Right. This is the card game view controller, also quite simple. You remember that from last week. The problem with it, and I mentioned this at the time, is that it imports playing card deck. In other words, this card game playing controller is pretty generic card game player, and if you put other kinds of cards in there it could probably match them, except for this one line of code down here that causes us to drag in playing card deck and make this card game view controller be playing card specific. So, what we're going to do, it's very simple, we' re going to create a subclass of this card game view controller that's specific to playing cards, then we'll move all the playing card specific stuff into that subclass, and we'll keep this one nice and generic. This card game view controller class is going to be a generic card game matching view controller. Does that make sense what I'm going to do here?
03:32 >> [Inaudible audience response].
03:33 >> Okay. So the way we're going to do that is we're going to get rid of this offending line of code. Okay. This is the line of code that makes this class depend on playing cards, and I'm just going to delete it and return nil here and create a deck. Okay, well, that's done it. We have a generic card, now I can get rid of that and it's all generic, but obviously, this is going to be a problem because now there's no deck. Right. This is going to return nil, this is going to return nil right here. This is actually going to return nil as well, because it's not going to be able to draw any cards, so this is a problem. So by doing this -- by putting this nil right here, we've essentially made this class -- card game view controller, abstract. Okay. So, hopefully all of you know enough object-oriented programming to know the word abstract. Abstract means that this class cannot be instantiated and used, it's only useful as a superclass for other classes that are concrete -- what we call concrete.
04:28 Okay. So we need to make a concrete subclass of this if we want to do anything with it, and I personally when I -- okay, an objective-c, there's no abstract keyword that you can use to specify that this is an abstract class, you just have to document it in your header file that this class is abstract, you can't instantiate. And I also like to document, even on my implementation, any methods that, basically, are abstract. Any method that is required that you override this method, and also any abstract method, you' ve got to make them public. Okay. Because otherwise the concrete subclasses won't be able to know that they're supposed to implement them. Okay. They could still override them is someone sneakily told them about it, but we don't want any sneaking around here, we want create deck to be public, so I'm going to copy create deck and put it in our public interface -- I'm going to leave that thing there that says it's abstract. Okay. I'm also going to put a class comment here that says abstract class, you know, must implement methods as described below, or something like that so that when people come to this class they know ooh, this class is abstract. And then we go down here, and then a lot of times I'll put right here, maybe the word protected or sub -- for subclasses, something like that to, kind of, make it clear the difference between methods that are just for sub classers, that they're going to override, or something like that, versus public methods -- which would probably go up here, which someone using this card game controller would call. Okay. So of course, we have an error here, because deck -- so we have to import deck, but that's a lot better than importing playing card deck, because we are not now tied to any kind of deck -- any deck of cards will do. Okay.
06:29 That make sense? So now that we have this abstract class that has this method that has to be implemented, let's make that concrete subclass of this that implements create desk.
06:39 Okay. And we just do that in the same way we create any new class. Right. File, menu, new file and then we're going to say we want an objective-c class. We can specify the superclass here's going to be card game view controller, and I'm going to call this class playing card game view controller, okay, because that's what it's going to do. It's going to be a card game view controller, but it's going to have the concrete thing that it is going to play with playing cards. So, I hit next. I'm going to put it in the same place as all -- my other view controller. Here it is.
07:13 You can see a couple of view controller lifecycle stubs in here. I don't need those. This is actually the designated initializer. I'm not sure why it throws that in there, because nowadays we pull these things out of storyboard. We would use a wait for nib, or even better, view did load.
07:28 Okay. So we don't want that either. So we have this nice concrete subclass, and all this thing needs to do is implement create deck. Okay. So I'm going to do that. I'm going to return. Okay. Here I do need to import playing card deck, but that's okay here, because that -- this class is for playing cards. That's what it's for, so I have no problem doing that. So let's go down here -- playing card deck, alloc, init. Okay. Bingo, I've created a concrete subclass. It's ready to go. If I were to go back to my storyboard here and run -- let's go ahead and run this. We' ll do this on the device, why not. See what happens. Can anyone predict what's going to happen if I run this? Is it going to work? No guesses? It's not going to work -- I see heads shaking no, it's not going to work. And in fact, it isn't going to work, and we'll see what it does. Okay, so I' m trying to flip cards and all these cards there's no cards here. Okay. I just made that concrete subclass, what's going on? How come it's not working?
08:37 >> The storyboard's still tied to the abstract controller.
08:39 >> That's right. So the answer is, my storyboard right here, if I look at this, this controller is still the abstract one. So, it's actually properly not working. Okay. Because it is abstract, it has no cards that are associated with it because it has not deck, so it doesn't work. So the question is how do we tell our storyboard that we want this controller to use the concrete subclass instead of using that abstract superclass? The answer -- very simple, we just select it. We can select a controller either by selecting here -- be a little careful when you click here, it didn't - - this actually selected the top level view. You can see -- we need the blue border around the edge. There's actually a little trick that you can do when you're selecting things -- let's see if I can remember which one it is. Go to command, click -- oh, dang it what is that? There is it. Shift click?
09:33 No. Okay. Control, shift, click. When you go to control, shift, click on something, it will actually show you all the things that are under your mouse. So actually if I control, shift, click here -- is that what it is? Yeah. Then it's showing me the button, which is under right under my mouth, then the -- mouse, then the view, and then the controller behind it, and so now I can pick which one of these I actually meant to select, like that. Okay. So I think it's control, shift, or something command shift. I can never remember it. Loss of memory. And my keyboard's slightly different in this one. So anyway, so now I've got it selected, it's got this blue thing around it, so now I'm going to inspect it. Okay. I'm going to bring up the inspector, but I don't want the attributes inspector. Okay.
10:15 I'm going to inspect the identity of this thing, so I go to the identity inspector. That's this one right here. Okay.
10:21 And if you look at the identity inspector, if you have a controller selected, the very top thing is what class is this controller in. You can see that right now it's card game view controller, the abstract superclass. So if I click here, I can either just type playing card view controller, or it could be in the list right here. So if I scroll around you can see some other classes that are in iOS, and here's a playing card one right there. If I select that one, now when we run it'll be using that concrete subclass, which will be dealing out playing cards in our game, so we're back to having this work. Okay. Everybody understand what we did there? Now you'll have to do this -- setting the class of controllers, and this is especially common to have to do when you have multiple view controllers, because you'll drag out another view controller, you'll need to say what class it is. Okay. Otherwise, you won't be able to hook up your outlets and actions to your subclass UI view controller. All right. So, that'll get you started on that, and again, you' re going to have another game. Both of them are going -- your app is going to be able to play either game. All right.
11:24 That's it. That's all I wanted to show there. So let's go back and start talking about multiple MVC's now. Why do we want multiple MVC's? Obviously, so we can have more -- oh, sorry, question.
11:35 >> Just really quickly.
11:36 >> Yeah.
11:36 >> So if you -- if you, say, bind a method to something in the storyboard and you bind it in the abstract class and then you override it, does it automatically inherit the same listener steps?
11:49 >> Yeah. So that's a good question. The question is, what if I have an outlet or an action that I've connected up to some outlet or action that's in your abstract superclass, and then I set the class to be a concrete subclass, will all my outlets and actions still work? Yes, in fact they will still work. They'll work great, and in fact, if you're -- if you have the code for the abstract superclass like we do here, you can actually have your storyboard up, and in the assistant editor, open up the abstract superclass and you can wire up outlets and actions, okay, even private ones.
12:19 So, something doesn't have to be private in the abstract superclass -- the outlets and actions, to wire it up. Okay.
12:25 Now, if you have the right side of your assistant editor set on automatic, you'll have to switch it to manual to go and pick the abstract superclass, because automatic's going to want to show you the concrete one, but like in our example here, we can't wire those cards up to playing card view controller, because it doesn't have that outlet for card buttons. That's in its abstract superclass. All right. So we just open up the abstract superclass, and we can wire it up.
12:51 In other words, that code is smart about knowing the inheritance of our key, to let you wire up to abstract superclasses, or even concrete superclasses, and even if they're private. So outlet and action connecting is, kind of, considered a private thing. All right. It's, kind of, a private thing. You don't have to make all those public to be able to connect those. But calling methods is something that's public. Okay. If you want to call a method in the superclass, that needs to be made public, because there's no protected. Okay. Good question. All right so, multiple MVC' s. Why we want multiple MVC's. Obviously, we can put more stuff in our app. How do we do it? Very simple actually, you just go to the object palette -- the same place you drag a button or a slider out of, and you drag out a view controller, and when you drag it out it'll be a generic view controller. In other words, it's class will be UI view controller and it'll be blank, obviously. Then you go create your subclass of UI view controller. Okay. In this case -- in the demo I just did I created a subclass of a class I already had, but you can create a direct subclass of UI view controller, and then you go and inspect it with the attributes inspector and you set its class. That's it. That' s how you drag a new MVC in and create one for your app. So it's easy to add MVC's. Now, once you have an MVC added, you can put its view -- put things in its view, buttons and labels and stuff, and you can hook up outlets and actions and all that stuff to create a second MVC, or a third, a fourth, a fifth, or a large app might have 100 MVC's in it, okay, or more. So, you got all these MVC's, how do you present them to the user. Okay. Well, there's a number of ways to do it, but the fundamental answer is you use a controller whose view is other MVC's. Let that sink in a little. Okay. So I can have a MVC that has a controller -- like all MVC's, the view of that controller is other MVC's.
14:44 This is the, kind of, conceptual way we're going to put multiple MVC's. And I'm going to talk about two classes provided by iOS today -- two controllers, whose view is other MVC's. One is UI tab bar controller -- you're used to that. It's got tabs along the bottom. Every time you click on a tab, you can see a different MVC's view, okay, couldn't be simpler. That's the simplest, you know, way to get multiple MVC's on screen. And then I'm going to spend more time talking about UI navigation controller, which is the thing where you have something on screen and you click on a button, or something that's on screen, and a new view slides in. Okay. And then you maybe click again and another one slides in, and then there's a back button and you can back up, so go down and back up. So when you want to drill down information or back up. Okay. So that one's a little more complicated, and that's what I'm going to spend most of the time on today. Now there's other ways to put multiple MVC's on screen -- popovers on iPad and modal presentations.
15:40 Though I'm not going to talk about those today, we will cover them all in the next few weeks. Okay. I'm just trying to meter this out to you in bite-size chunks. Okay. So, let' s talk about UI navigation controller. So, a great app to look at that uses UI navigation controller is the calendar app. So, here's the calendar app at its top level. You can see it's, basically, a year -- an entire year. Today's date is selected -- the little red in there. That big gray dot is supposed to be the finger. You're going to see it touching various spaces as we go through these slides. And we use the UI navigation controller when we have a bunch of stuff on screen and we want to show the user more -- more detailed, more information. Okay. Generally, what this navigation -- now, it's very common to want to do that when you're, kind of, showing high level information and you want to show more detail, more detail. So, the calendar app -- if you go over to the day with your finger and you touch, then a month view slides in. Okay. So all of that happened in a single MVC, which was a UI navigation controller MVC. Okay. So the purple -- or the light blue, whatever color that looks like to you on the screen -- that is the view of a UI navigation controller-based MVC. Now, inside there there's another MVC' s view -- the month view. So the little yellow area is another MVC's view. Okay. And what used to be in there was a year MVC view, which was yet another MVC. Okay. So you can see how it's imbedded. And not only is it embedded, but it - - the navigation controller is, kind of, controlling its own UI, based on what happens to be embedded at the time. And so, I could click on the day and a day view comes in, so this is a day MVC. So this is four MVC's we've seen here.
17:31 The surrounding navigation controller one, and now three separate year, month, and day MVC's that are being shown in here. Okay. So, let's take a look -- of course, we can click again and now get the details for an event, so there's five MVC's that we've seen. So let's look at the components of this UI navigation controller. So at the top, there's this light gray bar that stayed on the screen, you notice, for all of the MVC's as they come swiping in. Okay. But it changed slightly as they all swiped in, so let's look at all the parts. There's three major parts there of that navigation bar. First is the title, okay, event details.
18:12 You'll notice that the month and the day -- actually, I don' t think they even had titles, which is perfectly legal. This says event detail because the navigation controller is basically asking the embedded controller -- the calendar event MVC what's -- what's your title, and then it gets that and it puts that at the top. You can also set that title in your storyboard, if you want to. Okay. But it's associated - - that title's associated with what's inside -- what's embedded in the navigation controller and it changes as things slide in. Okay. Also, we have the buttons on the right here. So, there's only one button here -- edit, but if you remember back to the month and day, there were actually two buttons -- like a little plus sign to add an event maybe, and a little magnifying glass to search, things like that. So you can actually have multiple buttons here, that's why it's an NS array. Now, these buttons are not UI buttons, they're UI bar button items. Okay. Kind of lightweight buttons and the navigation controller figures out which one to put there by asking the embedded view for an object called a navigation item -- so all UI view controllers have this property navigation item, and it returns this object that has some stuff in there like right bar button items, which is an array. Okay. Everybody understand the property notation I'm using there? Navigation item dot right bar buttons. I'm getting that from the embedded view, you know, the day view, or the month view, or whatever. That's what's determining the buttons that are up there. This back button, over here on the left -- if I click that back button, it's going to go back to the last thing that was there, which in this case, was the day view. All right. And that's automatically done by UI navigation controller, and the word it's going to use there is -- if it'll fit, the title of the previous MVC.
20:00 So this case it -- day works, it fits. It can also be set, because I don't know that the day MVC actually had a title that said day -- might have, but I don't think so, so it can be set. Also if it doesn't fit, it'll just say the word back. Okay. So you'll see that sometimes. But the user knows that upper left hand corner is how they go back, so they drill down, they can go back. And if I click on that back button, obviously, I'm going to go back to the day. If I click again, I'm going back to the month. All right. So that's the back button. Now down at the bottom, you see there's a little light gray bar there. That's not always there. That wasn't there on the calendar event view -- MVC, by the way. This is just a bunch of UI bar button items that again, the navigation controller only displays if the embedded MVC's view says that it wants them. Okay. And there's another property for that called toolbar items, so you call -- the navigation controller calls toolbar items on the embedded view controller, and it returns an NS array of bar button items and it puts them in the bottom. And if the embedded view controller doesn't want any bar buttons at the bottom, then it just animates that gray thing away and then animates it back, if you navigate it back to one that does.
21:15 So everyone understand the components for UI navigation controller? Okay. So now let's talk about how this thing works. We know the parts of it. I'm going to do this, kind of, in a MVC like view of this. So, here I have an MVC.
21:32 Right. You recognize this from the very first lecture.
21:35 Right. And let's say I have more features than I can fit onscreen. So got extra views and buttons and stuff I want to put on screen, but they just won't fit. Okay. So what do I do? Well, like I said, we create a second MVC. Now, what's really important to understand here is that MVC's need to be independent. Okay. So this second MVC has to encapsulate some amount of functionality and it has to be able to be set up, prepared to be onscreen, and then it has to be able to run by itself. Okay. Why is that? That's because this MVC is going to serve as the view of another MVC. And remember from the MVC discussion, that the views can't really talk back to their controllers. The controller can talk to the view. The only way the view can talk back is by this blind structured communicate like target action, and things like that. And there is blind structure communication -- delegation.
22:31 Basically, we talked about for an MVC -- part of a view to talk back, but it's much more complicated, and usually, we try to avoid it. We really want to set this MVC up and have it live on its own. Okay. It's really important to try and design -- it's really just part of object-oriented programming to encapsulate things. So this MVC wants to be encapsulated. It wants to have its own life. Okay. So, let's talk about then about how UI navigation controller comes into this. If the second MVC, what is wants to show, is more detail of the first MVC, then a UI navigation controller is appropriate. All right. A UI navigation controller looks like this. It's an MVC, it's controller is the UI navigation controller, it's view is this, kind of, white rectangular thing with the gray bar at the top, and possibly a gray bar at the bottom, and it includes a root view controller, which is a special outlet that comes out that points to the controller of the MVC that's going to appear in the navigation controller when it starts up -- it's root view controller. Okay. So when you set that to be this MVC, the navigation controller is going to look like this. It's going to put the view of that root view controller's MVC into -- embedded inside of its view. Right. Everyone understand that? Okay. Now, if you then have some button, or something, inside this view, or maybe in the bar at the top that wants to give that more detail and have this other -- that this other MVC provides, you click on that button and it slides in the view for this other MVC, okay, and puts a back button there, as you see. Now again, when the MVC -- when the navigation controller's in this state, okay, the MVC that's on the left, kind of, wants to be quite. It doesn't want to be doing anything. Okay. It's not really involved right now.
24:28 Then MVC on the right is completely in control. Okay. And so it should be doing everything it's doing on its own -- independently. Now of course, that little back button which automatically appears when you do this -- we're going to talk about, by the way, how to make this happen, to go to another MVC. This little back button, when you press it, it' s obviously, just going to move back to the original one, then this MVC is now live again. What happened to the MVC won the right when we clicked the back button? The answer is, it got de-allocated from the heap. Okay. This is an important thing to understand as well. Okay. That MCV on the right got un-freeze-dried from the storyboard when we put it onscreen, and when it went back off screen, it got de- allocated. Okay. Every time we push a new thing onto a new UI navigation controller, we're creating a new one from the storyboard. Okay. We're instantiating a new one in the heap, and every time we go back and it goes away, it's de- allocated. So these MVC's need to know how to come to life, be prepared to come onscreen, do what they do, finish what they've done, save whatever work it is, and then just go away. Okay. That is the modal. Some people -- some people will be confused by that. You'll think oh, wow, what happened to all my data, it's gone. Well because it got de- allocated -- all right, because that's what happens when you do back. Okay. So if there's any data in there that needs to stay, you need to save it somewhere. Okay. And you could do it by communicating it back to the MVC that pushed you onscreen, but you have to do it with the blind structured communication. And we'll do that later in the quarter. Okay.
26:07 You won't have to do that for this assignment whatsoever.
26:10 Okay. So, that's basically how it works. Now, let's talk a little bit about that pushing. How do we make a second MVC appear on screen? How do we make it do that sliding in thing? Well, the answer is we use what's called a segue.
26:24 Okay. Segues are very important to understand in this class.
26:26 A segue is just when you're going to move -- or segue, from one MVC to another. Okay. That's what a segue's about and the segue that's involved in a UI navigation controller is called a push segue. We, kind of, think of the navigation controller as we push a new MVC into the front, and maybe push another one, and then we pop back, and pop back when we hit the back button. Okay. That's the terminology that we use. But it's called a push segue. So, let me talk about how to set up a push segue first, and then we'll show you how to put the whole thing into a navigation controller. Okay. So that's the two-step process here. All right. So we've only had the single MVC. Let's show, briefly again, how you create a new one. I'm just going to drag a UI view controller out of the object pallet. It appears like that.
27:15 Then I'm going to go up to the identity inspector -- not the attributes inspector, the identity inspector, and I'm going to set the class to whatever class I've created with file, new file, or I might have that class lying around, because it's very possible in a storyboard to have multiple of these scenes that use the same controller, if you're displaying the same thing in different environments, or whatever. It's perfectly fine. It's a very common mistake to forget to do this. All right. You end up coming to office hours and saying ah, I put this -- I dragged out my view controller, I created my new view controller class, but I can't hook up any of the outlets or actions. Well, because you forgot to set the class. Okay. Simple thing to do, but simple to forget, as well. I'm sure at least one time in a demo in this class -- in lecture, I'll forget to do that too so, I'm relying on you to say oh, don't forget to set the class.
28:01 Okay. So once you've set the class, now you have these two MVC's with different controllers. Okay. There's no view in either of these right now. We call this -- one of these little rectangular things, a scene, okay, in the storyboard.
28:16 If you hear me use the word scene, I just mean a combination of a controller and a particular view that we've built.
28:22 Okay. So that's called a scene. Okay. So, what we're going to do now is I'm going to drag a button into the left scene, and when we click that button, it's going to slide it in in a UI navigation controller. Okay. It's going to push it. So we're going to put that button in the left, and we're going to create a push segue to the right. So let's put the button there. All right. We're just going to drop it right in the middle there. I'm not going to change the title or anything.
28:51 To make it segue all I do -- control drag. Right. That's what we do in an Xcode, we control drag. So you just control drag from the thing you want to start the segue over to the view controller you want it to segue to. Okay. When you let go of the mouse, it's going to put this little black thing up and tell -- ask what kind of segue do you want here, and in this context, there's only three that make sense -- push, which would be navigation controller one. Modal -- which we' ll talk about later, which is take over the screen segue. I teach you that late because that can be abused. Okay. We don't want to do that too much. And then custom create your own segues. We're not even going to talk about that in this class, that's so rare. All right. So I click push and it puts this little thing in between my MVC's. You see that little round thing? That's a segue. Okay. And this is a clickable thing. In fact, you're going to need to click on it, because when you click on it and you go to the attributes inspector, you'll see that it has two things actually, one is the type of segue, which is push, but above that, it has this identifier. Okay. And I call this segue the do something segue.
29:54 Now why do I need to put this identifier here -- and actually, it's pretty mush mandatory to put something here.
30:00 And the reason is that I need to identify this segue in my code. Okay. This is the link -- tenuous as one might argue it is, between Xcode and your code, when it comes to a segue. Okay. We essentially, name these segues -- we give them identifier strings and in our code we can refer to them. And you'll see in a few slides here, where in our code we refer to this, but it's very important to do that. Okay.
30:25 Another common thing -- this is a common thing to forget.
30:27 You create a segue, you go to your code, and you're like oh, oops, and then you end up having to go back to Xcode and naming it. This one you're less likely to get very far without remembering to go back, but it's still something that's commonly forgotten. All right. So, we're going to call this segue the do something segue. Usually you want to pick an identifier that describes, in some -- you know, just like a variable name would describe, what's going on here.
30:51 So this is a generic example, so when we click that button, we're going to do something, so I called it do something, but you probably want to pick a better name than do something. That's a little generic. Okay. Okay. So, there's a problem here though. If I were to run my application in this state, it would not work. Okay. Clicking that button would not segue. Why is that? Because this whole thing has to be in a navigation controller. Right. These two MVC's -- I need a third MVC, which is the navigation controller they' re in. So, let's talk about how to do that. It's very simple. You pick which one of these you want to be the root view controller. All right. Of the navigation controller, and you go to the editor menu and you say embed in navigation controller. So I picked the one on the left -- you see it's got the dark blue line around it. I say embed in navigation controller, and when I do that, boom, it's going to create a navigation controller, so now I have three MVC's in this storyboard. Three. I've got the navigation controller on the left, and then I've got my two other ones on the right. Okay. And the little arrow on the very left -- do you see that arrow that, kind of, points in from the left? That is where -- that's the MVC that's going to be onscreen when your application launches. And that little arrow can actually be picked up and moved around. Just pick it up and drop it on any MVC you want. That's going to be the MVC when you start. Now it used to be pointing at the MVC that has the word button there in it in the middle, but as soon as I embedded it in a navigation controller it automatically moved it out to the navigation controller. It would never make sense to have a little arrow pointing to an MVC that's inside a navigation controller. Okay. Because that doesn't mean bring up the navigation controller and have this be the root view controller. That would just mean something strange. I'm not even sure -- I'm not even sure why it's going to allow that, but it would work. When it came up there would be no navigation controller, because you'd be bypassing the navigation controller. So -- but you can drag that little arrow to a tab bar controller, or -- sometimes in testing, it's nice to move them to a view controller and just say oh, just start with this view controller, because remember these view controllers are supposed to stand on their own, so you can sometimes drag it to startup for testing and then drag it back. In fact, I'll try to do that, if we have time, in the demo today. Okay.
33:03 The second little thing there, that looks like a segue but it's not actually. That's actually just showing you the root view controller connection from the navigation controller.
33:14 Okay. When you see the little, kind of, it looks like a dot with two lines in there that means it's a, kind of, an outlet type of connection not a segue. Looks very similar but you can't inspect it, you can't set an identifier. None of that's necessary here. It's just showing you that connection. But this one, that is the segue, the thing that we control dragged a few slides ago. If I were to click on that, it would say identifier do something, etcetera, and notice that all -- every single one of the scenes that is now inside this navigation controller -- not just the root view controller, but everything it can navigate to with push segues, gets a bar on the top in Xcode. And that's so you can lay out your UI nicely, knowing that that bar is always going to be on top of that scene, because this thing is inside a navigation controller. Okay. And if you're adding toolbar items things, then you'll have a bar on the bottom as well. If this was all inside a tab bar controller -- which is legal and which you're going to be doing for your homework, then it would also have a bar for the tab bar, and so the UI would be squinching down as you have to make your UI fit. And again, next week or the week after, I guess, we' re going to talk about auto layout, which is a way as these things are appearing or disappearing -- these bars on the top and bottom, to automatically have that stuff rearrange, but for now you're going to have to manually do it. Okay.
34:29 You can double click on the title in these bars and set the title if you want, or it'll ask the view controller that's at that scene for its title, just using the title property, and you can also -- if you wanted to add a button to the top, remember the calendar has like the search button, and the add button, and the edit button at the top. The way you do that is you just drag a button in, but don't use UI button here. Okay. Or you'll be frustrated if you try to drag UI button. It's like ah, how come the UI button won't go there? And that's because we use UI bar button item, which is kind of a lighter weight one. You scroll down almost to the bottom of the pallet you'll see this thing -- bar button item. You drag that out, you'll see that it will drop there and when you let it go, now you have a button there called item. That button will only appear when this MVC -- the one that has button in the middle of it, is the currently visible thing in the navigation controller. That's the only time the item will appear. Okay. And it is perfectly legal to, instead of having our segue go from button to the next one, we could control drag from that item to the next one. In fact, I'll do that in the demo just to show you. Okay. So that item button at the top is allowed to be a source of segueing. In fact, it very commonly is. All right. Okay. So, we talked about pushing this stuff on.
35:47 Okay. That's how you get something to appear -- the segue -- push segue. How about coming off? Well normally, things are coming off by a user hitting the back button, and that's when you want it to happen. You want the user to feel in control of their diving down for detail and coming back, so you'll want that back button to work. But there are a few times when it makes sense to programmatically do it and one example is, let's say, you dive down and you're showing some employee record, and a button in there is delete, meaning delete this employee. Well if you hit that delete button, it doesn't make any sense to be here anymore, because that employee is gone, so you want to go back. Okay. You want to go back to the previous level, and so you can call this method in UI navigation controller -- called pop view controller animated. We almost always specify yes, by the way, in animation. You don't want your UI jumping around.
36:36 You want things sliding in and fading in and stuff like that, and we're going to talk a lot about animation in the next couple weeks of your own stuff. But you might ask, how do I get ahold of my UI navigation controller to send it this message and an awesome thing about this way this is all set up is, if you are a view controller and you are inside a navigation controller -- anywhere on its stack, you call the property -- you can get the property on yourself called navigation controller and it will return you to the navigation controller you're in. Does that make sense? If you're not in a navigation controller, it'll just return nil, and it's perfectly reasonable to have MVC's that can live in a navigation controller, or live in a tab bar controller, or live in a navigation controller that's inside a tab bar controller, or live on their own, or live in a modal situation, whatever. You want to have MVC's that are flexible about where they live, so sometimes this'll return nil, and you might say, if I'm in a navigation controller then pop. If I'm not then, you know, do something else. All right. So, self dot navigation controller is a good thing to know inside a controller. It tells you the view controller you're in. There's also self dot tab bar controller. You can find out the tab bar controller you're in, although you almost never need that, but navigation controller you do, if you're going to pop or do some other things. What other segues are there besides push? I mentioned the modal and popover, there's also a replace, which is an iPad only thing, and there's custom ones. We'll talk about iPad stuff in a few lectures, and we'll cover all that then, and again, we'll talk about modal later, because it's, kind of, easily abused. Okay. So, now let's talk about what happens in code when a segue happens. We already know what happens on screen, which is this new MVC slides in. Right. Like the month slides into the day, or the day slides into an event, you know, whatever, so they slide in as you click them. But what's happening in your code? Well, there's an important thing that needs to happen before a new MVC can slide in, which is that it needs to be prepared. So let's go back to the example of the calendar. When I click on that -- let's say I've got a month's view showing the calendar and I pick on a day, and now it's going to slide it in to show me day.
38:40 I need to tell that day MVC what day. Okay. Because that day MVC, I guess it could just always show today, but if you're a calendar app you want it to be able to show other days, so you need to prepare that day MVC to come onscreen by telling it what day. Okay. Once you tell it what day, it's on its own. It just goes off, shows the day, you scroll around, you know, if you click on a thing, it's the one that pushes again to push in the even detail one, but you've got to prepare it. Okay. So MVC's need to be prepared. Well, who does the preparation? Obviously, it's the MVC that you clicked in to cause this other MVC to slide in. So in the example we just did, the MVC that has the button in it, it should have a method in it prepare for segue that prepares the next one over -- the one on the right to come onscreen.
39:28 The month one has to have a prepare for segue that prepares a day view controller for coming onscreen. So what does this prepare for segue code look like? Okay. First of all, it's called prepare for segue colon sender colon, don't worry about that sender argument for now. We'll talk about when that's useful -- it's a pretty rare case. Normally, you just need the information that's in that first argument -- the UI storyboard segue. You see that US storyboard segue. If you go look at that class, there's a couple of very interesting properties on it. One of it is -- one interesting property is identifier.
39:58 That's that string we typed in in Xcode -- do something.
40:01 Remember that? So when you get this prepared for segue, the first thing you're going to do is look at the identifier of the segue to see which segue we're talking about. Now why do we even need to do that? The answer is we can have multiple things segue, so again, let's go back to the month view. I can click on a day and it can segue to a day view, but maybe I click on the edit, or something like that, and it could segue to some view that edits something about the month.
40:33 Okay. Like, do they start on Sundays or do they start on Mondays, that kind of view. See what I mean? So it could segue to a different one, so you'd have two different controls inside the month view that are segueing to different MVC's so we need to know -- we know which one it is by its identifier. Okay. So, once we've checked to see which one we're talking about here -- and we always do that, even if there's only one segue, we always check the identifier just to make sure we're in sync with what we put in our storyboard, because some day we may add another segue with a different identifier. Then, the next thing we do is we're going to say what MVC are we segueing to? Okay.
41:11 Usually we are going to know what class of thing it is -- or think we know, because we know the identifier of the segue.
41:19 So it only makes sense if you're in the month view and you click on that day, that thing it's segueing to better be a day view controller, because you don't know what else to do if it's not. Okay. But you still, even so, will usually do a segue destination view controller --it's kind of class, the view controller we expect. Then we'll make a little local variable with it, and then we're going to do dovc -- which is our local variable, dot needed info equals, well that's, kind of, pseudo code for preparing that day view controller.
41:46 So, if this were the day view example, probably it would say dovc dot date equals some NSdate. Right? And so now we've prepared the day thing. And that's all we do here.
41:59 Everything else happens by magic. Once we've prepared that new MVC, it goes onscreen, does what it does. We don't have to do anything to make things slide or animate, that's all handled by the system. All the system is asking right here is please prepare this MVC to come onscreen. Now, very important thing to understand here, when this is called, your outlets are not set in the destination MVC. Okay. So this is between await for nib and view did load. This is very annoying. Okay. I wish this was different. I'm sure there must be a good reason why this is the way it is, but it's very annoying, because it means that any information that you're passing -- like the day, to the day view, it has to, kind of, hold onto it until all its outlets are set and then in view did load, it can go update all its UI. Does that make sense what I just said? Right. So you're going to have to have properties that are going to have to hold on to the day, and then when view did load happens, then it can update the UI. And I'm going to show you in the demo, kind of, a way that we might do it that's somewhat boiler plate, or somewhat, kind of, -- I don't know if I want to go so far as to say best practice -- simple practice for doing that -- for dealing with the fact that this gets called before view did load, okay, before your outlets are set. Okay. So it is possible to prevent a segue -- I have a few other slides, by the way, that I'm not going over in lecture, but they're on what you downloaded, so you can, kind of, read through them and look at the documentation to figure it out. But I'm going to talk about a couple of segue things here. One is you can prevent a segue from happening by doing this should perform segue with identifier colon sender colon, and that's exactly what it says. You return yes or now whether you want that segue to happen. Why would you never want -- why would you not want this to happen? Let's say you have a button and you click on it and it normally segues, but for some reason you can't segue. Okay. Maybe you don't have permission, or to can't find the date, or whatever, so instead you want to put up an alert that says could not, you know, provide the information, or whatever. You can't just have a target action from that button that puts up the alert. Okay. You need to prevent the segue from happening and put up the alert. So you prevent the segue with this and then you have target action from your button that puts up the alter. Okay.
44:11 That obviously, you wouldn't want to put up the alert and segue, so it -- they want to be mutually exclusive, but this is how you can prevent a segue. Okay. Any questions before I dive into a demo to show you all this in action? All right.
44:24 Here we go. So what we're going to do here is we are going to go back to Attributor. Instead of Machismo, we're going to do this in Attributor. All right. Let's hide others here.
44:43 So this is what Attributor looks like, if you'll remember, hopefully, from just two days ago. And what we're going to do is we're going to add a second MVC, and what this MVC is going to do is to analyze -- it's going to analyze some text and say how many colored characters in there, how many outlined characters in there, etcetera. Right. So it's, kind of, a stat. It's giving you statistics about some texts.
45:06 Now, I'm going to put this aside and do this new MVC completely independently. In other words, it's -- I'm not even going to think about this right now. I'm going to build the second MVC which does this thing -- which is analyze text and give you result, then we'll use it. And I just want to do that to emphasize how we want MVC's to be independent.
45:27 Okay. So let's design that MVC. We start by dragging out a view controller -- just like this. Okay. We're going to create a new class for it. Okay. And I'm going to call this thing -- it's going to be a UI view controller, and I'm going to call it -- let's call it text stats view controller -- I think that's the name I used. Make sure I did it. Yeah.
45:53 Text stats view controller. We could call it analyze text view controller, something like that, but I think text stats view controller -- although it's a mouthful, is pretty descriptive. And so we're going to put it at the same top level there, and can of course, group our view controllers too. Here's the code for our text stats view controller. You can see again, we've got this nice designated initializer which we don't want, and we've got some view controller lifecycle, we don't want any of that. Okay. So, this text stats view controller -- it is, essentially, a reusable thing. It needs a public API. Okay. And just like we did when we designed the card matching game and we, kind of, tried to come up with a public API first so we could think of how our thing's going to be used, we're going to do exact same thing here. So, I'm going to go to the public interface of this -- this is the public interface for text stats view controller, and I'm going to add a property -- nonatomic strong, which is a NS attributed string, which is the text to analyze. Okay. So the way this MVC is going to work is, you set it a text to analyze -- which is an attributed string, and it's going to analyze it. Okay. That's it. That' s what it does. Okay. That's its entire reason for being.
47:07 Okay. But it's an entire MVC, so it's going to have the UI to do that -- all that stuff to do that. So, how are we going to implement something like this? Well, I'm going to start by thinking about how I want to react, if I'm this MVC, when people set my text to analyze. And obviously, if someone sets my text to analyze, using set text to analyze - - right, the public method. Obviously, I want to set my little variable here, but I'm also going to update my UI.
47:39 Okay. So anytime someone sets the text to analyze, I'm going to update my UI. So, I don't want to allow my UI to ever get out of sync with what is, essentially, my model. Okay. This is, essentially, the model for this MVC, is the text to analyze. So, of course, we're going to want nice update UI - - very similar to that we had in the other one, and we'll do that in a minute. Okay. But, there's another time here when I might want to update my UI, and that is in view will appear. And that's back to what we were talking about before, which is that is this text to analyze gets set when I'm not onscreen, maybe before my outlets are set, okay, I want to come along when view will appear and make sure my UI is in sync. Okay. Because this update UI is, obviously, going to be taking to my view and if my outlets aren't set it won't do anything. Okay. So, this is, obviously, going to get called to prepare for segue in a moment, so that's why I'm doing this, but this is also, kind of, a generically good thing to update your I there -- UI there, and update it here. Now you might argue oh, what a waste. What if this is called and your outlets are set? You updated UI and then you appeared and you updated UI again. So, one might argue that it's a good thing to do this. Okay. Self dot view dot window is the window that your view is in, view is the top level view of your MVC, and if that's nil, then you're not onscreen right now. So that this says is, if someone sets the text I'm supposed to analyze and I'm onscreen, then I'd better update my UI. Otherwise, I'll let view will appear do it for me, because I'm not onscreen and I'm eventually going to come onscreen. In fact, I'll never analyze my text unless I get put onscreen, so it's, kind of, good performance too, although analyzing text is going to be trivial. Okay. So this is, kind of, a common pattern to have outlets that you set that, if you're onscreen will update, otherwise, you wait and let view will appear do it. Okay. All right. So, let's talk about update UI and how that's going to work.
49:51 Well, let's build our view so you know what our UI is that we want to build here. So, I'm going to make this really, really simple, so I'm just going to have a couple of labels here.
50:01 I'm going to say zero colorful characters. Okay. And then we're going to do the same thing we did with the score in Machismo to change that with the printed F thing, and then we'll also keep track of outlined characters, but you could imagine that this text analyzer would have a whole bunch of other lines, where it'd analyze other things that were in random attributed text. Okay. Font, bold, [inaudible] italic, etcetera, but again, we're going to make this simple. So I need to update these two things with -- by analyzing whatever my model -- this model right here, contains in terms of attributed strings. So how am I going to do that? Well, I'm going to do that in a way that shows off a little bit how we analyze attributed strings. Okay.
50:48 Now, I'm going to type this code in pretty quick because we' re time constrained, obviously, but you should make sure you understand this code. It's very simple and straightforward, but it really requires that you understand attributed strings, so it's a little bit of a double check of you attributed string understanding. So what I'm going to do is, I'm going to have a method called characters, matching -- or we'll just this one, characters with attribute, NS string attribute name. Okay. So what this is going to do is, is it' s going to look in my text to analyze for any characters that have this attribute, like NS for -- NS foreground color attribute, or in stroke with, or something like that, and it's going to return a string that has all those characters cloned onto it. And then in my UI, I'll just specify how many of them there are by checking the length, okay, of that string. And you might ask why am I going to all the troubles to collect them up, and you'll see that later. Okay. So, how would I collect this up? I'm doing it mostly because I want to show you how that would work. So I'm going to create a mutable attributed string to collect all this into. I'll call it characters, and -- let's make more space here on both sides. Okay. So I'm just going to say NS mutable attributed string alloc init, so here's an empty mutable string that I'm going to put the characters in and return.
52:09 Okay. So, in here I need to collect all this stuff. So what am I going to do? I'm actually just going to do a wild loop that goes through and looks at every character. Okay.
52:20 Couldn't be simpler. So I'll say int index equals zero while this index is less than the self text to analyze length -- oops, length. Then I'm going to collect the characters.
52:40 Okay. Too many square brackets there. Okay. So everyone understands this part so far, right? Couldn't -- this part couldn't be simpler. So, now let's go ahead and get the value of this attribute at this character. So that's value, and the value's an ID here, because it could be a color, it could be a font. Right? It could be a -- it could be an NS number, so I'm -- this is where ID comes in handy dandy. So let's say self dot text to analyze attribute colon attribute name at index -- index effective range. Okay. So this effective range, remember I told you, is going to turn -- return the range that this attribute is the same for. Right.
53:33 So if this attribute is there for 12 characters in a row, it's going to return this range for 12 in a row, so I'm going to capture that range, and you'll see why I want that.
53:42 Okay. So, I better create a local variable -- NS ranger -- no, NS range. Oh, hello -- range -- range. So this is just a local variable range for this struct and I'm just going to pass a pointer to it, so that it fills that struct out with the effective range. Got any questions there? All right. So, if the value is set, okay, that's what I'm looking for. I'm looking for characters where this attribute is set. Okay.
54:08 So, if I'm looking at foreground color, this would be colored character. If I'm looking at stroke width, it would be outlined characters. So if the value is set, then I'm going to take the characters and append onto it the text to analyze attributed string for range -- that range I just got back. Everyone make sense there? So I just collected those characters that matched that attribute, and I can -- I also want to say -- I could say index plus plus and just go to the next index, but actually know that this range of character ends of range dot location plus range dot length.
54:49 Right. So there's no need to check -- I already grabbed this range, so I need now to jump to the end of this range. If the attribute is not set on this character, then I do need to move to the next thing. Okay. To the next character, because I'm in this wild loop right here, I need to go round and round. Okay. So that's it. Hopefully, you all understand this code. If you don't, you definitely want to, offline, make sure you understand how this works so that you understand mutable strings -- or attributed strings. Okay.
55:20 So now, notice that I'm returning a non-mutable attributed string here and this is clearly a mutable attributed string, and that's perfectly fine. What that says is whoever's calling this, shouldn't rely on this being mutable. They should assume it's not mutable. And so, update UI is going to call this and it should be sure not to try and change these characters, and it won't be allowed to either without doing some sort of casting because the compiler is not going to let you assign this to a mutable string. I'm going to move this up here like this, and so let's go ahead and use this. This might seem like a really long line of code, but it's pretty straightforward, so we need to have some outlets that point to these things. Right. These little guys right here, so let's do that -- C -- oops. Okay. So, here's an example of exactly what I was talking about. I want to create an outlet here and what's going on? How come I can't create this outlet? Okay. This is on automatic. What's going on here? Well the answer is, this is still UI view controller, so I need to go over here, go to here, and instead of having UI view controller here, I need text stat view controller. Okay. Now look what happened. It automatically updated this. Okay. The automatic did it's automatic job. Okay. So now I can control drag from here to here -- we'll call this colorful characters label, and I'll also drag from here to here and we'll call this outlined characters label. Okay. Everyone see that? All right. So all we have left to do here is implement our update UI to make these two labels here properly display the length of the characters that we calculated with this characters attribute down here. So let's make a lot more space. Let's go over here, just showing our view controller. And in self update UI all we really need to do is get the characters with the given attribute, whether it be color or the outline and count how many characters in there. So let's do self dot -- sorry, let's do self dot characters with attribute first.
57:39 And let's do the color ones first, which the attribute there would be the foreground color attribute name. So now we've got these characters. And let's see. Now that we have them, we can count them. So let's do that by sending length of the string. So now we know how many characters there are here.
58:01 So now we can update that field, which is our self dot colorful characters label text. And we'll do that by saying NS string, string with format, percent D, colorful characters. And the argument is this thing we just calculated right here. Okay? So we got that. And let's do the exact same thing here with the outlined characters. And these are outlined characters. And this is the NS stroke width attribute name. Okay? So we've went and found the characters that have that attribute, found out how many there are, and then we created a string with format that displayed that into the label.
58:54 Okay. This is not 100% correct, because what if the color set on something is black? It's not a very colorful character. Or what if the stroke width is set, but it's set to zero, so this is not a great implementation, but it's simple. It gives you the idea. Now one thing I like to do when I build a new MVC sometimes is test it. Okay. So I'm going to test this by adding a little view did load. Okay.
59:24 So here's view did load, and what I'm going to do is self dot text analyze equals NS attributed string alloc init with string test attributes, and I'm going to put some test attributes in here like foreground color -- green, and also let's put NS stroke width -- call it minus three, or something like that. Right. So I have this. So now, when this MVC appears, it's view to load is going to set its own model, which is, kind of, of a good testing thing, so let's go back and do that. And how would we do that test? So we got our storyboard here, what if we just pick this guy up and put it over here? Now when I run this app, it's going to go straight to this MVC and just bypass -- this is not even going to be used right now, because I'm just going to test this guy. So let's try that. See if I forgot anything.
01:00:23 >> Oops, simulator. I'll do this on the -- [inaudible] on the device. Okay. Okay. So the word test have four characters, so hopefully this is going to come up and say four colorful characters and four outline characters, so it's working. And I could go delete one of those attributes, make sure it says zero. I could change the word to be longer than test to make sure it says more than four. You see what I mean? See how I can, kind of, test this MVC to make sure it's working? So, we're going to take our word for it though that that's enough testing and that it's working, so I'm going to get rid of view did load. This is something -- you might put this in some, sort of, ifdef testing or something like that. You know how to do all that, so you could do that as well, but I'm just going to delete view did load, but I have a really nice working MVC right here that tells how many characters are colored and outlined in a given piece of text. Well now, obviously, I could use if from this guy -- let's move this guy back. And I'm going to put these inside of a navigation controller, and I'm going to actually add a button to the navigation controller's bar, when this one's visible, that will segue over to this guy. Okay. So let's do that. Let's put it in navigation controller first. More space here -- so I'm just going to embed in navigation controller. Right. Boom, puts it in. Okay. It got a bar.
01:01:54 Notice that this one did not get a bar. Why? Because there's nothing that segues to this yet, that's inside this navigation controller. Another bad thing happened though. I lost my CS193P rocks. Okay. And we know that CS193P does rock, so we do not want it blocked like that, so one thing you can do is if something gets blocked like this, you know, like, oh no, I've got to go fix that, you can just delete the navigation controller and you'll be back where you were, or you can hit undo. So I'm actually going to get rid of this and put it in that gray bar instead. It's a perfectly reasonable place for it to go. Maybe I'll move this down a little bit too and make sure it fits on there. So now let's go back and select this again and embed it. Okay. So now we' re back in here. All right. And now I can put my CS193P rocks here. Okay. Perfectly reasonable place to put it. And I've got this. Maybe I would line that up there or there, depends on where the blue lines say. Okay. So I got that.
01:02:54 Now I want to put a little button right here, so if everyone remembers how to do that. We go all the way down to the bottom here and we find bar button item, which is right here, and we drag it up. We put it right there. This is going to show the stats, so I'm going to call this stats.
01:03:09 All right. And now, every time I click on stats, I want this MVC to slide in here and replace this one, so I'm going to control drag to here. Okay. Inside of navigation controller it's always push. Okay. There's a segue right here. If we click on this segue and go to the attributes inspector and see that it's a push segue, and we're going to call this show stats -- or even maybe better, analyze text. Okay. So, we want to have something in there that makes it clear what this segue does. It analyzes text in this case. Okay. Now the last thing we need to do is prepare this MVC to come onscreen, basically, by setting its model to be the text that's in this text view. Right. So we do that in here. The preparation for this to come onscreen is done by this guy, because this guy's the guy causing the segue. So let's go here. As soon as we do this we're on automatic, so we're going to see this guy's code -- here it is. Okay. Hopefully, you remember this code from last time, and let's go ahead and put the prepare for segue. We'll put it at the top because it works nicer for me. Prepare for segue. All right.
01:04:18 And all we have to do inside this prepare for segue is prepare for this particular segue. It's the only segue we have, so I'm going to make more space here -- actually let's scroll over so you can see the segue in your mind, while we' re working on this. Just click this back again. There we go.
01:04:37 Okay. So prepare in segue what do we do? Well, like I said, the first thing we're going to do is we're going to make sure we're talking about this particular segue, which is the analyze text one. Now, of course, if you mistype this here, you're not going to get any warning or anything like that, or if you mistype it over there, and it's just not going to work, because it's not going to prepare that MVC properly, so it's a little bit of a weakness, I think, of the way this system works, but just a debugging thing to make sure your text here matches the text there. All right. So I know that when I'm segueing here, I need to use this text stat view controller. Okay. So it's okay for me to import that MVC's class in here, because it's part of my view -- almost, so you can, kind of, think of it -- the stats as being part of the view of this other one, because it's sub -- you know, a sub thing, so it's okay to do that, but I better make sure that the destination view controller that we're going to be segueing to is, kind of, text stat view controller. Okay.
01:05:51 But if it is, then I'll create a little local variable here -- text stat view controller equals text stat view controller. This is, actually, not necessary -- this one I'm doing right here, but I personally like to do it, just because I like to have, you know, a local variable that I can do things like tsvc dot text to analyze equals. Okay. So here I'm preparing it. Okay. What does it need? It needs my body text. Okay. Remember from last time? This text view right here is self dot body, and the text storage is the NS mutable attributed string. This is an NS attributed string, but it's okay to assign that, because a mutable string is a regular attributed string, so this is perfectly legal, and so that's it. That's all that's necessary for us to do. And now if we run, you will see that first of all, we come up inside of a navigation controller. Okay. We still have our thing here. We can still select text. If we bring up the stats, there's zero colorful characters. I didn't color anything. When I hit back, it just dealloc that text analyze. Let's go ahead and make a new one here. Orange and maybe some outline, and maybe some purple, and now stats -- 14 colorful, seven outlined, okay, working like a charm.
01:07:14 Maybe we'll make a whole bunch of outlined here. Okay. Stats -- 250. Okay. So that's it. Everyone got that? So you will be doing this on your homework. In fact, you'll be taking this and putting it inside of a tab bar controller, so you' ll be doing double duty. So let's talk about tab bar controller in the last five minutes that we have here. Any questions about that before I go on to tab bar controller?
01:07:40 It all makes sense once you see it. Right? There's a number of components to it, but they, kind of, fit together. All right. Tab bar controller. Here is my favorite tab bar controller application example, which is the clock app on iOS seven. You can see it has a tab bar across the bottom there and four tabs. Each of these four tabs is completely independent of the other and that's the way MVC's inside a tab bar controller should be, completely independent of each other. If they're dependent, you probably want a navigation controller. Okay. Or if they're in an iPad, you might want to a popover, or something like that, but on an iPhone you probably want a navigation controller if you have a dependency. All right. So how does tab bar controller work?
01:08:23 Very, very simply controller, it has a property called view controllers, which is an array of MVC's -- UI view controllers, basically, the controllers are the MVC's. And how ever many you have, that's how many little tabs you'll have on the bottom. Okay. And this -- to create these connections in your storyboard -- surprise, control drag.
01:08:45 Okay. So you just drag the UI tab bar controller and then just control drag to all the controllers that you want to be the various tabs. Now, how does the word timer and the little icon there appear. Well, the timer is going to be the UI view controller title, the same thing that will appear in the top of a split view controller, and the icon, there's actually a UI view controller property called tab bar item, and inside there is the icon and a few other things like the badge, which is a little round circle with a number or a letter in it, which you can put on there. So that's how these things get set, but I'm not even showing you that here, because usually you set them in the storyboard. Okay.
01:09:26 You set this icon and this text in the storyboard. That's the best place to set these things. Now, what if you have more than four controllers -- or more than five, actually?
01:09:34 Then what happens? Then a little more tab is going to appear -- see it down there in the corner, and when you click that there's going to be this UI that's presented that allows you to -- the user to pick which four they want down there. Swap them back and forth, okay, which is, kind of, cool. And that happens automatically. You put that more button on there, it just does it -- it does it for you. So that's really cool.
01:09:58 Okay. So I, actually, don't recommend UI's that have more than five tabs. I think this is a little cumbersome for users, but there are some places it would make sense. In this app, it's not bad. It, kind of, makes sense. This is the iPod app, or whatever -- your music app. So it, kind of, makes some sense here. But anyway, if you do need to do that, that's how it works.
01:10:19 So let's, in the last couple of minutes here, look at Xcode and see what it looks like to make a tab bar controller. So this is the same thing I was just showing a few slides earlier. Right. You see the navigation controller with the MVC that has the button and then it just -- you know, it segues to the next one, so I'm actually going to put this in a tab bar controller, so it's going to be one of the tabs, and then I'm just going to have like a blank view be the other one. Okay. So, see the tab bar controller there? I'm dragging it out. When you drag it out, it's going to come along with two blank ones, okay, two empty blank ones, which very much of the time you don't want. In this case, I'm going to keep one of them, get rid of the other one, just to show you how that's done. So when you drop it, it might overlap other ones. Obviously, in the storyboard, you can drag these MVC's anyway you want to make them look nice. If they happen to be connected by a segue or something, it'll automatically redraw that line for you as you move it. It's really quite nice in that way. You can imagine that these storyboards get very large. With 100 storyboards in there how does it even work. Well, you can see -- if you look down in the lower right corner there, you'll see there's a magnifying glass -- you can zoom in and out. Okay. Zoom way out. If you have 100, you can see all 100 at the same time.
01:11:31 Zoom in all the way to zooming in all the way on one view controller and then you can edit that view controller. You can't edit a view controller itself, unless you're zoomed in all the way. Okay. So here I've got to blank ones. I don't want them both, so I'm just going to select one of them, make it blue, as we talked about before, and hit delete, and it's gone. So I've still got the other one. Okay. And now I' m going to hook that navigation controller in there by control dragging. So I'm control dragging from the tool bar controller to the navigation controller, and when you do this control drag, it's going to put up this little segue thing, but when it's a tab bar controller, it only makes sense for this to be view controller. And I'm really surprised the Xcode just doesn't automatically do this. I'm not sure exactly why, because you -- it would make no sense to pick push here, so why even offer that. I don't know.
01:12:16 Anyway, you always want to one on the bottom when it's a tab bar controller, which means wire this up to the list of view controllers. Okay. You do that and now it's going to have this line drawn over there. Again, these little round circles are not segues, they're showing the outlet view controllers -- plural, in the view controller case. It's root view controller in the split view -- or the navigation view controller space over there. So I got these things wired up. Note that on all of the scenes that might appear in this tab bar, even if they're -- that's happening through a navigation controller, they're all getting room for this little bar on the bottom. You see that? Little bar space on the bottom, so that's going to be there. So it's smart about knowing oh, this could eventually be in this tab bar, so I'm going to make that space down there. And again, you have to adjust your UI to fit in the smaller space, whatever. Notice we have a navigation controller inside a tab bar controller, that's legal, other way around, not so much. Okay. Don't be putting a tab bar controller inside a navigation controller.
01:13:18 Yeah?
01:13:19 >> [Inaudible] how do you know which one shows up on the left?
01:13:22 >> Well, the tab bar controller -- the things that the tab bar controller points to, those are going to show up in each tab. Okay. If you wired from the navigation controller to any scene that had a tab bar controller in it, that would be bad. So basically, the tab bar controller should not be anywhere downstream of a navigation controller.
01:13:37 >> Oh but, what I meant is...
01:13:38 >> Oh, so the question is what's the order of the tabs?
01:13:42 >> Yes.
01:13:43 >> That can actually be changed in Xcode. If you see where the tabs are in the bottom of the tab controller, you can pick those up and move them. Okay. So anyway, so we have these two tabs. I'm going to make the launch point. I'm moving it from being the navigation controller over to be the tab bar controller. Right. Obviously, I want the tab bar controller to be showing onscreen when it first launches, and I can double click down on a view controller and change the text, right there. See where I am there? Double click.
01:14:13 And I can also set the image over here on the right. You can set it to an image that's in your assets library. These images need to be 30 by 30 pixels, all alpha. Okay. In other words, your 10th color is going to show through the alpha in that 30 by 30 icon. Okay. It's as simple as that. It's going to show through the alpha. So if that icon has anything but alpha in it, you know, opaque and alpha, it doesn't make -- it's not going to show. Okay. So that's that. That's it.
01:14:43 Hopefully that's enough for you to do both kinds of controllers. Friday, no section. Next Friday we'll get you up and running on your devices. Monday, no lecture. Your homework's due on Wednesday, which is convenient, and then starting next week -- next Wednesday and for the two weeks after that, we'll be doing drawing and gestures and how to layout animation. Lots and lots of fun stuff. Okay. Thank you very much.
01:15:08 >> For more, please visit us at Stanford.edu.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment