Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Start a free Basic trial
to watch this video
To complete the swiping functionality let's provide implementations for the data source methods to load the photos before and after the current one.
-
0:00
For either data source method, whether it's the viewControllerBefore
-
0:04
the current one or the viewControllerAfter, our goal is to create
-
0:07
a new instance of the PhotoViewVontroller, give it a new photo and show it on screen.
-
0:13
So let's refactor this code out of viewDidLoad
-
0:17
where we create a new instance of the PhotoViewController for a given photo.
-
0:22
And this is pretty easy in Xcode 9.
-
0:25
So what we are going to do is we are going to select all of this right here.
-
0:32
And then we'll command or we'll right click Refactor and,
-
0:35
wait that doesn't seem to work.
-
0:39
Hold on, select Bugs, gotta love them.
-
0:50
Okay, let's just select this and see if we can get it to work.
-
0:55
Now, wonderful.
-
0:56
Okay, we'll do this manually.
-
0:59
So right after viewDidLoad, let's add a new method func photoViewerController,
-
1:08
With photo of type Photo.
-
1:12
And this is going to return an optional instance of PhotoViewerController.
-
1:18
So in here we'll move this guard let storyboard.
-
1:21
All of that cut and paste it in here.
-
1:26
And instead of just returning out of the method,
-
1:29
we'll return nil to indicate something went wrong here.
-
1:32
Oops, this is supposed to be an optional instance, there we go.
-
1:36
And then once we have that, we can grab this line of code, put it in here.
-
1:43
We're no longer going to reference the photos array,
-
1:47
we're just going to say photo, right?
-
1:49
This is the argument we're passing in to the method.
-
1:53
And then we'll return the PhotoViewerController.
-
1:56
So now we can use this method inside of viewDidLoad instead of our original code.
-
2:01
So we'll say if let photoViewerController =
-
2:06
photoViewerController, that method we just wrote, with.
-
2:12
And here we'll say photos, indexOfCurrentPhoto.
-
2:17
So if this works, then we'll delete this.
-
2:22
And we'll move this line of code up.
-
2:28
Okay, so that works.
-
2:30
Back to the data source methods.
-
2:31
Now that we have this helper method,
-
2:33
we can easily write a fewer lines of code to do the same thing.
-
2:38
Let's start with viewControllerBefore.
-
2:40
Let's walk through the steps here.
-
2:42
First, we need to figure out what photo is currently on screen.
-
2:46
To do this, we'll get the current photo and see which index it's at.
-
2:50
Now you might be thinking, wait a minute,
-
2:51
I thought the current photo was at index of current photo.
-
2:55
Now that holds true for the very first photo.
-
2:57
Once we start swiping though, unless we update index of current photo,
-
3:01
the index stored in the variable and
-
3:03
the index corresponding to the photo on screen are different.
-
3:06
Once we have an index, since this method asks for the ViewController before that
-
3:10
one, we'll get the photo at the index position immediately to the left and
-
3:15
use it to create an instance of the PhotoViewerController.
-
3:18
There's only one caveat here.
-
3:19
If that index is 0, there's nothing to the left, so we're going to return nil.
-
3:23
Okay, let's try this out.
-
3:24
So step one, get the photo and check the index.
-
3:28
If you look at the method signature of the protocol method,
-
3:31
it includes a reference to the current viewController right here.
-
3:35
This ViewController is an instance of the photoViewController, but
-
3:39
the type is just UIViewController.
-
3:41
So let's start by casting it first to the right type.
-
3:43
We'll say guard let photoViewController or
-
3:48
PhotoViewerController = viewController as PhotoViewerController.
-
3:56
Else if this doesn't work, return nil.
-
4:00
Next we need to get the index of the photo
-
4:03
stored in the viewController's photo property.
-
4:06
Let's add this logic as a check to the guard statement as well,
-
4:09
since the index of method returns an optional integer.
-
4:13
So here we'll add a comma and then we'll say let index = photos,
-
4:19
that's our data source, essentially .index.
-
4:23
And we're gonna look for index of, oops, index, right here, index of Photo.
-
4:28
And we'll say photoViewerController
-
4:36
.photo.
-
4:39
So what we're doing is, this is the current viewController.
-
4:42
We're casting that to a PhotoViewerController,
-
4:44
grabbing the photo out of that, and
-
4:46
then checking the index and comparing it to our array that we have at the top.
-
4:53
Next, we'll check to see if this index is the first index in the array.
-
4:59
So we'll say if index == photos.index or
-
5:03
photos.startIndex which represents the first index.
-
5:09
And notice that I'm not using any hard coded numbers here.
-
5:12
I'm relying on built in logic to traverse the array induce index math.
-
5:16
So if this is the start index that means there's no photo before this one.
-
5:21
Remember this data source method is asking, hey,
-
5:23
what's the viewControllerBefore this current one?
-
5:26
So if we're at the startIndex, there is nothing, we can return nill.
-
5:30
If it isn't nill, however, we will get the index right before it.
-
5:34
So, else, we will say let indexBefore = photos.indexBefore.
-
5:41
There is a method for that.
-
5:42
And we will use the current index.
-
5:45
Now we have this index, we can get a photo.
-
5:47
So let photo = photos[indexBefore].
-
5:52
And then we'll return photoViewerController with that photo.
-
5:58
Let's try this out.
-
5:59
Why is this an error?
-
6:01
Let me build.
-
6:02
Cannot call value of non-function type.
-
6:05
That's because these two things have the same name, so let's change that.
-
6:09
I'm going to command click here,
-
6:12
and select Rename from these new fancy methods.
-
6:17
You'll notice that it selects this which is obviously wrong.
-
6:19
We're gonna get rid of that and we'll say photoVC, right?
-
6:25
That should work.
-
6:25
Rename and that recognizes this as method.
-
6:30
Okay, let's give this a try.
-
6:32
I'm gonna run this app.
-
6:35
Now, before you actually tap on a photo,
-
6:36
remember that we're going to select a photo and try to go before it.
-
6:40
So backwards.
-
6:41
And in order to test this, you'll need more than one photo.
-
6:43
At least two.
-
6:44
So go ahead and add a few in.
-
6:45
So I have three in here.
-
6:46
I'm gonna select this one.
-
6:48
And you'll notice that I can swipe.
-
6:51
And it works.
-
6:52
While this page curl effect that you just saw is fun, that's out of place here, and
-
6:57
is mostly used when you're flipping through pages in a book.
-
7:01
So let's go to main.storyboard, and select the PhotoPageController.
-
7:06
And in the Attributes Inspector,
-
7:08
you'll notice under the Attribute section that there is a Transition Style.
-
7:12
So if you're building something like a book, you can leave the Page Curling,
-
7:15
otherwise we are gonna set it to Scroll.
-
7:17
Cool, now that we understand the logic behind how this works,
-
7:21
let's provide an implementation for the second delegate method.
-
7:24
And that's back in the PhotoPageController class.
-
7:28
For the second method, we need to go in the opposite direction.
-
7:31
So really the only change here is how we do the index checks.
-
7:36
So let's copy the implementation from the previous method.
-
7:38
We're going to get all of it, Paste it in.
-
7:43
And then here we'll say guard let photoViewController.
-
7:47
We'll make that check.
-
7:48
We'll get the index of the current photo, all this is the same.
-
7:52
Now the if statement here checks to see if the index of the current photo
-
7:56
is the startIndex.
-
7:57
We'll need to modify this to check if it's at the opposite end of the array.
-
8:01
Arrays have a property called endIndex that points to the index
-
8:04
right after the last index in the array.
-
8:07
So what we need to do is check whether the index of the current photo is
-
8:10
the same value as the index right before the index.
-
8:15
Make sure you don't compare it, so don't do this.
-
8:17
Don't do if current index is photos.endIndex.
-
8:20
This we'll be wrong, because endIndex represents the index after the last one.
-
8:24
So what we'll do here is we'll say if index ==
-
8:28
photos.index(before: photos.endIndex.
-
8:33
And then we'll return nill.
-
8:34
Now this does seem like a complicated way of achieving this since we can just index
-
8:39
less than the current property.
-
8:41
But by doing it this way, we let the array type worry about the index math and
-
8:45
we don't do any hard coded values or compare it.
-
8:49
So if the current photo is the last one in the list, then we return nill.
-
8:53
And the pageViewController takes this to mean that we can't swipe forward,
-
8:56
we're at the end.
-
8:57
In the else case,
-
8:58
we now need to switch the logic to get the index after the current one.
-
9:02
So let's rename this.
-
9:03
So we'll command click.
-
9:06
We'll rename this to indexAfter.
-
9:09
Hit Rename.
-
9:11
And then all we have to change here now is this method to say after.
-
9:16
Okay, that should be it.
-
9:18
Let's run the app.
-
9:20
And now if we select the first photo,
-
9:23
we should be able to swipe all the way to the end.
-
9:28
There we go.
-
9:28
And then back as well.
-
9:31
So the key bits here are the data source methods.
-
9:34
By returning nil when we hit the edges of our data source, we inform
-
9:38
the pageViewController when it should stop loading another viewController.
-
9:42
But when we tap on the photo here, nothing interesting happens.
-
9:47
So over the next few videos, let's allow the user to zoom, pinch, and pan a photo.
You need to sign up for Treehouse in order to download course files.
Sign up