So in this lesson, all I'm gonna do is just a bit of tidy up around our codebase to make it a little 1
bit shorter, a little bit more succinct, and a little bit easier to read. 2
So the first thing I'm gonna do is I'm gonna get rid of our debug options, so for any app that you're 3
putting on to the App Store, you probably don't want those dots confusing the user. And the next thing 4
is I'm gonna get rid of all these comments and this bit of space. And then inside our touchesBegan where 5
we create a new diceScene, 6
I'm actually going to separate that out into its own function. 7
I'm gonna call it addDice and it's going to take a single parameter which is going to be called 8
atLocation, and this is going to be of the type ARHitTestResults. 9
Now, I'm going to take all of this code and put it into addDice. And then, over here, instead, I'm going 10
to just going to call addDice atLocation which is the location that we got from our hitResult. 11
And this is probably a good point to show you a different way of naming your methods in Swift. 12
So, in Swift, there's something called the external parameter and the internal parameter. So we can say 13
addDice atLocation which seems quite expressive when we call it. 14
But when we want to use it inside our method, I don't really want to say atLocation.worldTransform. 15
Just semantically or in English, 16
that doesn't really sound good to me. 17
So instead, I want to be able to write something like location.worldTransform. 18
So I can keep the external parameter as atLocation, but I can change the internal parameter to simply location. 19
So, now I can use location inside the method and still use atLocation outside the method to indicate 20
what kind of input I'm looking for. 21
And this is just a way of making your code more expressive so that somebody else who has never seen 22
your code can have a look at it and be able to get to grips with it relatively quickly. 23
All right. 24
So we've separated that functionality out and I'm going to put this function above the rollAll. 25
Now, this is really, really up to you, 26
and this is completely personal, I would say. But I think it makes more sense hierarchically. 27
I'm going to keep these three as they are, and then I'm going to move on to refactoring this didAdd 28
delegate method. 29
So one of the first things you can do is you can add a pragma mark to separate it out and we'll call this 30
pragma //MARK: - ARSCNViewDelegateMethods. 31
And now, if you have a look in this dropdown, you can see we've got our categories, 32
ARSCNViewDelegateMethods which has only one at the moment. But as your ARKit app gets more complicated, 33
you're going to be putting more delegate methods in here and it'll be nice to be able to split them 34
up. And equally, you could probably also split up the lifecycle methods up here, 35
viewDidLoad, viewWillAppear, et cetera, and maybe your Dice Rendering Methods. 36
Now, you can split this up however you like, but it's just nice when you can actually browse all your 37
methods and properties and have some sort of structure that divides them up. 38
So if you remember, by having that dash in there, you actually get a little line. If you don't have that 39
dash, you only have this bit of text. And I quite liked that line separation, so I tend to have it in there. 40
All right. 41
So let's look at this renderer didAdd method, and one of the first things that you notice that is 42
pretty long-winded are these lines here. 43
If anchor is of the type ARPlaneAnchor, then let planeAnchor = anchor as! ARPlaneAnchor. 44
So this, obviously, is there because I wanted this code to be as expressive as possible so that even a 45
beginner could actually understand what the hell is going on. 46
But now that we're refactoring, let's make this a little bit simpler. 47
So first thing I'm gonna do is I'm actually going to take out all of that code, put it at the bottom 48
and I'm going to comment it out. 49
So right now we're not concerned with that. 50
We just want to shorten all of this junk here. 51
So instead of checking if anchor is off type ARPaneAnchor, and having an "else" statement that returns, 52
we can actually get rid of all of these lines by simply using a "guard" statement. So I can say guard let 53
planeAnchor = anchor as? ARPlaneAnchor. 54
And if the "guard" statement fails, then I'm simply going to return. 55
So that single line of code has replaced all of this code and we can now get rid of it. 56
But before I do that, I just want to show you how it works. 57
So, firstly, let's look at this part. 58
We're saying, "let," this new constant planeAnchor be set equal to anchor, 59
and we're going to try and downcast it from ARAnchor type to ARPlaneAnchor type. 60
Now, if this is not doable, i.e., the anchor that we actually detected was not of the type ARPlaneAnchor 61
or cannot be converted into the type ARPlaneAnchor, then this planeAnchor is going to be an optional 62
that's going to be equal to nil. 63
And in that case, this fails. And then this guard statement will jump to the "else" portion in which case 64
we return and we escape out of this entire function. 65
So this is kind of like having a moat outside of your castle where you're tripping up all the things, 66
you know, all the--all the cavalry, all the foot soldiers, and you're trying to prevent them from 67
entering your main code, and you're just saying escape if this statement happens to trigger. 68
So, now we can get rid of all of this and we can bring back all of our code down here. 69
So the other thing I want to do is I actually want a separate method to create that plane. 70
So I'm going to create another pragma mark down here and let's call it Plane Render Methods or Plane 71
Rendering, I guess that makes more sense. And then I'm going to take all of this and I'm going to put 72
it into a method here called createPlane with, 73
and it takes a ARPlaneAnchor as a parameter and I'm going to paste it in here. 74
So, again, I want to have with or withPlaneAnchor as the external name for this method. And the internal 75
name, 76
I'll just call it planeAnchor, so that we don't have to update our code too much. 77
Okay. So, now we're going to call that method over here. 78
We're going to say createPlane withPlaneAnchor and the anchor is, of course, this one. 79
So let's pass that in there. And then I'm going to make sure that this method actually returns a 80
SCNNode which is the one that I'm gonna be adding as the childNode. 81
So I'm going to store this inside a constant called a planeNode. 82
So planeNode equals the output of this function 83
and, of course, we need to be able to return planeNode here for that to work. 84
And then, finally, I'm gonna say node.addChildNode, and it's going to be playing node that we got 85
back from that method. And all the errors disappear and all is well in the world. 86
So you can probably even refactor this further. 87
Another suggestion I would make is that this plane can actually be its own object. 88
You can see that we're doing a lot of things on this plane, plane.position, planeNode, plane material, 89
plane geometry. 90
But for now, I'm happy with this. And I hope you enjoyed this bonus refactoring lesson and I like the way 91
that our cleaner code looks. If you have any suggestions on future tutorials that you want us to make, 92
then do go ahead and shoot me a message, and we're going to try and figure out what other things that 93
most people want to learn about, and to use it to guide our future course development. 94
So this is all from Angela at the London App Brewery and I hope you'll look forward to more tutorials that 95
we're going to be adding to this course in the coming weeks and months. 96
So thanks for watching this far, and see you soon.