11/13/2018 Updated for Xcode 10/Swift 4.2
Many iOS applications obtain data via web APIs that return JSON documents. For example, the following table view controller uses the Kilo WebServiceProxy
class to invoke a simple web service that returns a simulated list of users as JSON. The controller requests the user list when the view first appears, and reloads the table view once the data has been retrieved:
class ViewController: UITableViewController {
var users: [User]?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Load user data
if (users == nil) {
let serviceProxy = WebServiceProxy(session: URLSession.shared, serverURL: URL(string: "https://jsonplaceholder.typicode.com")!)
serviceProxy.invoke(.get, path: "/users") { (result: [User]?, error: Error?) in
if (error == nil) {
self.users = result ?? []
self.tableView.reloadData()
}
}
}
}
...
}
User records are represented by instances of the following structure:
struct User: Codable {
struct Address: Codable {
let street: String
let suite: String
let city: String
let zipcode: String
struct Geo: Codable {
let lat: String
let lng: String
}
let geo: Geo
}
struct Company: Codable {
let name: String
let catchPhrase: String
let bs: String
}
let id: Int
let name: String
let username: String
let email: String
let address: Address
let phone: String
let website: String
let company: Company
}
The results are shown below:
This works fine when both the device and the service are online, but it fails if either one is not. In some cases this may be acceptable, but other times it might be preferable to show the user the most recent response when more current data is not available.
To facilitate offline support, the response data must be cached. However, since writing to the file system is a potentially time-consuming operation, it should be done in the background to avoid blocking the main (UI) thread. Here, the data is written using an operation queue to ensure that access to it is serialized:
class ViewController: UITableViewController {
var userCacheURL: URL?
let userCacheQueue = OperationQueue()
var users: [User]?
override func viewDidLoad() {
super.viewDidLoad()
title = "Response Data Cache"
tableView.estimatedRowHeight = 2
tableView.register(UserCell.self, forCellReuseIdentifier: UserCell.description())
if let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first {
userCacheURL = cacheURL.appendingPathComponent("users.json")
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Load user data
if (users == nil) {
let serviceProxy = WebServiceProxy(session: URLSession.shared, serverURL: URL(string: "https://jsonplaceholder.typicode.com")!)
serviceProxy.invoke(.get, path: "/users") { (result: [User]?, error: Error?) in
if (error == nil) {
self.users = result ?? []
self.tableView.reloadData()
// Write the response to the cache
if let userCacheURL = self.userCacheURL {
self.userCacheQueue.addOperation() {
let jsonEncoder = JSONEncoder()
if let data = try? jsonEncoder.encode(self.users) {
try? data.write(to: userCacheURL)
}
}
}
} else {
...
}
}
}
}
...
}
Finally, the data can be retrieved from the cache if the web service call fails. The data is read from the cache in the background, and the UI is updated by reloading the table view on the main thread:
class ViewController: UITableViewController {
...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Load user data
if (users == nil) {
let serviceProxy = WebServiceProxy(session: URLSession.shared, serverURL: URL(string: "https://jsonplaceholder.typicode.com")!)
serviceProxy.invoke(.get, path: "/users") { (result: [User]?, error: Error?) in
if (error == nil) {
...
} else {
// Read the data from the cache
if let userCacheURL = self.userCacheURL {
self.userCacheQueue.addOperation() {
let jsonDecoder = JSONDecoder()
if let data = try? Data(contentsOf: userCacheURL) {
self.users = (try? jsonDecoder.decode([User].self, from: data)) ?? []
// Update the UI
OperationQueue.main.addOperation() {
self.tableView.reloadData()
}
}
}
}
}
}
}
}
...
}
Now, as long as the application has been able to connect to the server at least once, it can function either online or offline, using the cached response data.
Complete source code for this example can be found here.
Hi sir.My Json structure is
{
“profilePic”: [
{
“a0”: “http://wedicons.com/admin/images/uploads/d4c5543b-Desert.jpg”,
“a1”: “http://wedicons.com/admin/images/uploads/fbbadae6-Hydrangeas.jpg”,
“a2”: “http://wedicons.com/admin/images/uploads/31914e88-Jellyfish.jpg”
}
],
“status”: 1
}
I want to retrieve all images in gridview.One more thing is that I don’t know how many images are there in server.So please explain me logic sir.Thanks in advance
LikeLike
Could you elaborate on what you mean by “grid view”? If you are referring to a table or collection view, you could probably do something similar to this:
https://developer.apple.com/library/content/samplecode/LazyTableImages/Introduction/Intro.html
LikeLike