Leave a rating/review
Notes: 11. Work With Cookies
When setting up the cookieProperties dictionary, the following line is also required in order for the initializer to return a non-nil value:
cookieProperties[.path] = cookie.path
A cookie is a small text file generated by a server to identify a user on subsequent requests.
Cookies are often used for shopping carts, user preferences and registration details. Websites may also collect demographic data or browsing patterns for marketing purposes.
A session cookie lets the client access server resources without having to re-authenticate. It’s not stored on the client’s disk, and expires after several minutes.
A stored cookie is used in future sessions to retrieve user preferences. It can track the user’s path to indicate usability issues, and can be stored for years.
You can control cookies in your app with 3 configuration properties:
httpShouldSetCookies, which controls whether tasks should automatically provide cookies from the shared cookie store when making requests. The default value is true.
If you want to provide cookies yourself, set this value to false and provide a Cookie header either through the session’s httpAdditionalHeaders property, or in the request object.
httpCookieAcceptPolicy determines the cookie accept policy for all tasks. The default value is onlyFromMainDocumentDomain. You can change it to all or never.
If you want more direct control over what cookies are accepted, set this value to never and then use allHeaderFields and cookies-withResponseHeaderFields-for to extract cookies from the URL response object yourself.
httpCookieStorage determines the cookie storage object used by all tasks. To disable cookie storage, set this property to nil. For default and background sessions, the default value is the shared cookie storage object.
For ephemeral sessions, the default value is a private cookie storage object that stores data in memory only, and is destroyed when you invalidate the session.
Cookies are repsented by the HTTPCookie class.
You can get cookies from a response’s header fields, but you can also create your own cookies.
You do this by create a dictionary of HTTPCookiePropertyKey and Any object. You can then pass this into the HTTPCookie initializer.
At this point you can save your cookie to the HTTPCookieStorage class. This class is shared with other apps and extensions. Mind you, in iOS each app has a unique data container which have separate cookie stores.
You can access the shared storage by way of a method called sharedCookieStorageForGroupContainerIndentifier. You can also subclass HTPPCookieStorage, but that’s beyond the scope of this episode.
Time to show you how to work with cookies. Open this episode’s Starter project. The project now has a Cookies where you’ll work with cookies in this episode. Open CookieView.swift and add the following method:
private func getCookiesTapped() async {
func setCookies(name: String? = nil, value: String? = nil) {
Task { @MainActor in
cookieName = name ?? "N/A"
cookieValue = value ?? "N/A"
}
}
}
You create an asynchronous private method, and then declare a function within it called setCookies. This internal method takes two parameters, both of type String, for the key and the value.
Ensuring you run code on the main actor, you set two of the view’s properties to your cookie’s name and value. After the setCookies method, still within getCookiesTapped, add this code:
guard let url = URL(string: "https://apple.com") else {
setCookies()
return
}
You create a URL to Apple’s website and, in case of an error, you call the set cookies method (which will set the cookie name and value to nil) and return. Add this code next:
do {
} catch {
setCookies()
}
You’ll fill in the do block in a second, but in the catch block you also call setCookies with no parameters.
In the do block, add the following code:
let (_, response) = try await URLSession.shared.data(from: url)
This makes a request to Apple’s URL. You discard the data it returns, but you keep the response. Add the following guard statement next:
guard let httpResponse = response as? HTTPURLResponse,
let fields = httpResponse.allHeaderFields as? [String: String],
let cookie = HTTPCookie.cookies(withResponseHeaderFields: fields, for: url).first
else {
setCookies()
return
}
As is the case with other requests, you check the response, but this time you also check the response’s headers and the first cookie available within. After the else statement, add this code to set the cookie:
setCookies(name: cookie.name, value: cookie.value)
Finally, and to wrap it all up, add this code to set your new cookie, and delete the response’s cookie, from the cookie storage:
var cookieProperties: [HTTPCookiePropertyKey: Any] = [:]
cookieProperties[.name] = cookie.name
cookieProperties[.value] = cookie.value
cookieProperties[.domain] = cookie.domain
if let myCookie = HTTPCookie(properties: cookieProperties) {
HTTPCookieStorage.shared.setCookie(myCookie)
HTTPCookieStorage.shared.deleteCookie(cookie)
}
Creates a new properties dictionary for the response’s first cookie, and then creates a new cookie from it.
You save this cookie in your cookie storage and delete the response’s cookie. Build and run the project, and navigate to the Cookies tab. Tap the Get Cookies button and check out the results on-screen. Awesome work!
At this point, we’ve covered all topics in this course. There is, however, one last challenge for you related to cookies, so I’ll see you in the next episode! :)