Hey everybody what's going on this is Caleb with Deb's Lopes dot com.
And if you remember in the last video we wrote a function that basically prevents are in at purchased
subscriptions from ever being pirated.
It basically uploads the data that saved to your phone compares it against iTunes servers.
If it's good to go we get a response back.
If not we get an error and our app basically returns false saying no.
No that's not a real purchase.
Very very cool stuff in this video we're going to write two functions one that's basically going to
extract the expiration date from the sun data and return it back to us.
We're also going to write a function that will be able to determine whether or not our subscription
is still active or if it expired and to do that we're going to need to make an extension of date so
that we can check to see hey is this less than a certain date.
Is this more than a certain date so that we can basically see hey is our subscription still good to
go.
So pull open your project and let's begin actually by extracting the expiration date from the Jason
data downloaded from our application.
So let's go ahead and beneath our upload receipt function we're going to write a new function called
expiration date from response.
So go ahead and type that phunk expiration date from response.
OK.
Now this function is going to return a date and an optional date because there is a chance that it might
not return anything.
So go ahead and give it some curly brackets and we're going to pass in our Jason response.
Now that should be a capital are a capital R and we need to think most of the time when we're dealing
with Jaison it's cast as a dictionary of string and any.
But we did not do that up here when we have our Jason downloaded.
So we should actually do that first because we're going to pass that into our function.
So let's cast that as a dictionary of string.
And any.
And of course we need to fix that so it says string and that's stirring because that's not a real type
anyway.
So now that this is a dictionary we can pass in this same type into our function so we can type.
Dictionary of string and any escape.
Really really cool.
Now if you remember this is our dictionary that gets passed in k we have lots of information for all
of these different purchases.
And then we also have an expiration date.
You see that right there it says expires date 2017 9 18 2044 20 GMT.
So this is the subscription date when it expires which is pretty cool.
And so we can use that key later to get this value as the date.
So let's go ahead and let's write this function.
Now we're basically going to create an array of receipt info.
And that's going to come from an array within this called receipt info so check it out.
If we look in here we got to look a little bit deeper you'll see that inside this there is an array
called latest receipt info and it comes from the Jason response it's an array which we can tell here
and it's actually an array of dictionaries.
OK.
So what we're going to do is we're going to go ahead and type if let receipt info of type MSRA like
so it's going to be equal to the sun response and we're going to pull out the item that is called latest
receipt info.
Like so.
All right.
And in order to actually cast this as an array we're going to go ahead and cast that optionally as an
NSA right like so.
So assuming that we do get this receipt info re filled we can go ahead and pull out the last receipt
information which if you look here is latest receipt info.
Here's the opening brackets of the array.
And here's the first dictionary second dictionary third fourth fifth sixth and check it out.
OK this is the last dictionary before it goes into the next array pending renewal info.
So we want the last item because that is the latest most up to date information.
So we're going to go ahead and call Let last receipt equals receipt info remember.
That's an X-ray and we can just get the last object by calling dot last object.
OK and that's going to give us the very last object which we know is a dictionary of string and any
object so we can go ahead and just cast that as a dictionary of string and any and I set any object.
But I meant any.
Now what we can do is we can basically pull out the date value here which actually is in the perfect
format for the date type.
But before we do that we're going to actually set up a date formatter so that we can tell it that we
want the date to actually be this exact format with the year month date with the time the time zone
everything.
So let's set up the format first and then we'll set up the instance of date.
So go ahead and type let formatter equals date formatter and instantiate it.
Now we need to set up formatter date format.
There's three tiers there huh.
Formatter.
Date format and you'll see it's of type string.
So in order to set the proper format we need to type it like this.
Why why why why for the years dash capital M M for month Didache lowercase d d for the day then ours
is capitalized.
Minutes is minimized and seconds is also small.
And then at the end Vee-Vee indicates that we want the time zone K so there is our formatted date and
now what we can do is we can create a constant called Let expiration date expiration date of type date
of type date like so equals formatter and then we can call a function upon that.
That's date from string k.
Now we want this string value here which is our expiration date.
Now how are we going to get that.
We can take the last row seat array or the last recy dictionary.
Like so last receipt and we can pull out the value for expires.
Date.
Check it out.
I can type.
Expires date and we can cast this as a string like so.
Whoops.
As String K so we're now creating a date from the expiration date which is conveniently in the same
format.
Thank you Apple and we can cast this as a date like so so that we can basically say hey this needs to
be of type date.
Now we're getting an error saying we're not using this or I guess a warning.
So let's do that.
If the receipt info is good to go we're going to go ahead and return the expiration date.
K that we just generated.
Otherwise we're going to just return nil because this is optional we might not get a return date back
and that's fine.
So if I go ahead and build this you'll notice it'll build it'll run and it will do exactly as we want
it to.
Which is beautiful but we are not yet finished so we're going to go ahead and head back into our upload
receipt function and we're going to call this so that we can set our expiration date.
OK now let's go ahead let's get rid of this print function here and let's just go ahead and say let
new expiration date equals expiration date from response and let's pass in the Jason response Jason.
So as as you might expect this will return a date to us and then we can do something with this expiration
date property.
So let's just print it for now using DEBUG print and we're going to print out new expiration date and
you know what let's actually say new expiration date with space and a comma then we can print out both
in the same debug print.
OK.
Super super cool.
I think we should be good to go if we build this.
Oh you know what.
It's going to say that we need to call cell phone because we're in a closure.
So call self-taught expiration date and let's go build and run this and subscribe and then let's see
if we actually can print out our new expiration date.
So build and run and we should be able to check this out.
All right.
Here we go.
Beautiful.
All right so we see IAP products loaded let's tap on our subscribe button enter our password one two
three exclamation mark press enter.
So remember what we're looking for here is it should print out our new subscription date when we push
subscribe and confirm it.
Let's see what happens UK it says subscription valid purchase was successful.
Interesting so I wonder why we did not get an expiration date to print for us.
Interesting.
So we go through we call oh guys you know what.
I just remembered we we were not calling upload receipt from anywhere.
That is unfortunate.
Let's let's go put it back.
Really quick upload receipt valid.
And you know what we don't actually need to do anything in there because we're just focusing on what's
happening inside the upload receipt function.
And when this loads we should see the expiration date printout which should be about five minutes after
223.
So let's go ahead and push the subscribe button.
New expiration date optional to 2017.
21:27 that's about five minutes after when I subscribe.
So that's amazing.
It's working.
We're getting an expiration date back.
That's five minutes in the future which in the real world would be a whole month.
So that's cool.
That works.
Let's get rid of this.
That's awesome.
And now we can successfully extract our expiration date.
But let's go ahead and let's actually force on rap that so it doesn't come in as optional.
It also silences that warning for us.
But now now that we can actually check to see if our receipt is valid and get our expiration date.
Now is the time for us to basically say hey is is the current date before the expiration date or after.
And that will help us to know hey is our purchase active or not.
So let's go ahead and let's write that function let's stop this from running to free up some memory
and up above upload receipt.
We're going to write a new function.
OK.
So go ahead and type phunk is subscription active OK.
And just like this function we're going to go ahead and basically pass in a boolean and that boolean
is going to say yep it's active or no it's not.
So I'm just going to copy the same completion handler here and paste it in.
So what we're going to do is we are basically going to create a property that will hold the date for
now and then we're going to compare it to the expiration date that gets returned to us from our Jason
call.
So let's go ahead and let's do that by typing.
Let Now date equals date.
And by simply instantiating that we get an instance of date for the exact second that it's instantiated
which is perfect.
So we have the date now but we need a way to basically access the expiration date.
And when we call upload receipt that's great but we should be doing something to save this expiration
date somewhere important like user defaults.
It should be stored there.
So to do that we're going to actually make a quick little function that is going to set the expiration
date into a nice little user defaults Boullion.
So go ahead and call this function phunk set expiration.
OK.
And we're going to set the expiration for a particular date OK with an internal parameter of date of
type date.
OK.
And this function we're going to call user defaults dot standard dot set.
OK.
And we're going to set value of any K for a particular key of type string.
Now the value is the date coming in right and we're setting it with the key expiration date with only
one t.
Now this key will help us to access this from user defaults later on.
But for now this function will let us save it and keep it there.
So instead of just printing the expiration date.
Now let's go ahead and call self set expiration for date new expiration date.
OK.
Really cool.
And you know what let's go ahead and force on wrap it there so that we save the value not the optional
value.
And now we will be able to actually save our date which is beautiful.
Now that's great to save it in user defaults.
But I wish we had a property in this in this Singleton that we can basically access at any time which
we can do if we go ahead and go up to the top.
We created 1 in the starter project for the Boullion non consumable purchase was made.
So right above that we can type var expiration date expiration date equals user defaults dot standard
dot value for key and the path or the key.
I mean is expiration date.
All right.
And you know what.
Since that's just a value I'm going to actually cast it.
Let's forecast that as a date because we know it's going to come in as date if it'll let us forecast
that.
Okay perfect.
That's really cool.
That will work.
And now what we can do is we can basically say you know if the now date is before or less than the expiration
date we're good otherwise we're not okay that's how we're going to basically determine if our subscription
is active or not.
Now the problem with what we're doing here is that the date subclassed and all of the fancy date stuff
does not really have a function that can that can compare dates in this way so easily.
So what we're actually going to do is to create an extension of date write our own custom function and
call it comparing the two dates.
So go ahead and right click on food Zyla create a new group and call it extension's.
Right click on the extensions folder and create a new file.
OK click.
Swift file.
And then we're going to go ahead and just call this date XTi.
OK so now we're going to do is we're going to go ahead and create an extension of date by typing extension
date.
And now any functions that we write in here it can be called upon any instance of date.
And so let's do that by typing phunk is less than.
And we're going to be able to pass in a date and then use that to compare against the current date.
OK.
Now go ahead and just create a property here let's just say past date of type date and we're going to
basically say if self meaning whatever instance of date let's say that I made an instance of the date
for today like you know the now date constantly created if self time interval since and look at what
it does it returns the interval between the receiver and another given date.
So now and then if we can get the difference we get the value of how long it will take basically to
get to that point.
So if the time interval since the past date well past date sounds like in the past let's just say date.
How about that.
That makes a little more sense.
So if the of if the if the instance of date that this is called on we're going to say how far is it
until the actual subscription expiration date.
Ok if that is less than the date we pass in time interval since now meaning the difference between the
date value and right now then what we're going to do is we're going to go ahead and return true.
Okay.
And you know what we need to actually return a boolean here if we're going to do that.
Okay.
Otherwise
we're going to return false.
Now what this function is basically going to do is it's going to let us say hey if the current date
is less then the subscription date then it's valid.
If it's not then it's going to return false.
So let's go back into our IAP service and what we can do is we can take that property we just saved
the expiration date.
We're pulling it from user defaults.
What we can do is we can basically say hey if there's an expiration date if if one is saved because
the odds are one might not be saved.
OK.
You know a new subscriber if one is subscribed if a date is saved we can say hey if Now if the now date
is less then the expiration date we can return true to our completion handler meaning subscription still
active man.
If not we can return false.
So let's go ahead and let's use guard let so that we can safely create a constant for the expiration
date in case there's not one.
So go ahead and type guard.
Let expiration date equals expiration date.
The one we have saved up above and we can say else return cake because if we do not have one we'll just
return.
Get out of the function and save us from crashing.
What we can do is we can say hey if the now date is less then remember that's our extension.
If it's less then the expiration date.
Check it out.
We can go ahead and say hey completion is going to be true.
Otherwise if it's not less then that means we've already gone past our expiration date else completion
handler is false.
OK.
So that's pretty cool.
Now we're getting an error here at saying needs to be optional cannot be of type date.
But the reason for that is because we're force unwrapping it as date.
Let's go ahead and optionally unwrap it there as a date and you'll see that air will go away.
Our function will work.
And this is super super cool guys.
I think we should try this.
I think that we should go ahead and see if this works to call our is subscription active function but
we need to think of a way we can do it.
And you know what let's actually figure that out in the next video.
I have just the thing.
So let's head over there and I'll see in the next video.