JSON Parsing in Swift explained with code examples – onlinecode
In this post we will give you information about JSON Parsing in Swift explained with code examples – onlinecode. Hear we will give you detail about JSON Parsing in Swift explained with code examples – onlinecodeAnd how to use it also give you demo for it if it is necessary.
JSON parsing in Swift is a common thing to do. Almost every app decodes JSON to show data in a visualized way. Parsing JSON is definitely one of the basics you should learn as an iOS developer.
Decoding JSON in Swift is quite easy and does not require any external dependencies. The basics APIs that come with Swift will be enough to do the job, so let’s dive in!
The basics of JSON decoding
It’s good to start with the basics to let you understand how JSON parsing in Swift works. Let’s take the following example of a onlinecode blog post:
{
"title": "Optionals in Swift explained: 5 things you should know",
"url": "https://www.onlinecode.org/swift/optionals-in-swift-explained-5-things-you-should-know/",
"category": "swift",
"views": 47093
}
We can easily decode this by making use of the Decodable
protocol:
struct BlogPost: Decodable {
enum Category: String, Decodable {
case swift, combine, debugging, xcode
}
let title: String
let url: URL
let category: Category
let views: Int
}
We defined a Category
enum that also conforms to the Decodable
protocol. All the properties match the names from our defined JSON example. Every type that conforms to the Decodable
protocol automatically converts. This means that you can also use your own custom defined Decodable
types as a property.
By making use of a JSONDecoder
we can make JSON parsing really simple:
let JSON = """
{
"title": "Optionals in Swift explained: 5 things you should know",
"url": "https://www.onlinecode.org/swift/optionals-in-swift-explained-5-things-you-should-know/",
"category": "swift",
"views": 47093
}
"""
let jsonData = JSON.data(using: .utf8)!
let blogPost: BlogPost = try! JSONDecoder().decode(BlogPost.self, from: jsonData)
print(blogPost.title) // Prints: "Optionals in Swift explained: 5 things you should know"
Although this might give the impression that JSON parsing is really easy, it all comes down to the edge cases. Luckily enough, Swift is capable enough to handle those as well.
It’s not required to define each property
It’s good to know that you’re not required to define each property that comes with your JSON. This means that the following struct would’ve worked as well:
struct BlogPost: Decodable {
let title: String
}
This is great, as it could be that you’re adding new keys after you’ve already released a version of your app. If it wouldn’t work like this, you could easily break old versions.
Optionals and JSON decoding
It could be that you’re not sure whether a JSON key is returned or whether a value will be set. In this case, you can define a Swift property as optional and the JSONDecoder
will take care of the rest.
struct BlogPost: Decodable {
let title: String
/// Define a key as optional if it can be returned as 'nil' or if it does not always exist in the JSON.
let subtitle: String?
}
Decoding JSON arrays in Swift
Decoding a JSON array in Swift is almost just as easy as decoding a single JSON object. Take the following JSON example:
[{
"title": "Optionals in Swift explained: 5 things you should know",
"url": "https://www.onlinecode.org/swift/optionals-in-swift-explained-5-things-you-should-know/"
},
{
"title": "EXC_BAD_ACCESS crash error: Understanding and solving it",
"url": "https://www.onlinecode.org/swift/exc-bad-access-crash/"
},
{
"title": "Thread Sanitizer explained: Data Races in Swift",
"url": "https://www.onlinecode.org/swift/thread-sanitizer-data-races/"
}]
We can parse this list of blog posts by defining the decodable type as [BlogPost].self
:
struct BlogPost: Decodable {
let title: String
let url: URL
}
let blogPosts: [BlogPost] = try! JSONDecoder().decode([BlogPost].self, from: jsonData)
print(blogPosts.count) // Prints: 3
Mapping JSON keys to custom property names
JSON parsing isn’t always as easy as copying over the same keys into a struct. It’s quite common that you like to define different property names when mapping the JSON.
Taking the previous JSON example, it could be that we would like to name url
as htmlLink
in our JSON model. We can create this mapping by defining a custom CodingKeys
enum:
struct BlogPost: Decodable {
enum Category: String, Decodable {
case swift, combine, debugging, xcode
}
enum CodingKeys: String, CodingKey {
case title, category, views
// Map the JSON key "url" to the Swift property name "htmlLink"
case htmlLink = "url"
}
let title: String
let htmlLink: URL
let category: Category
let views: Int
}
let blogPost: BlogPost = try! JSONDecoder().decode(BlogPost.self, from: jsonData)
print(blogPost.htmlLink) // Prints: "https://www.onlinecode.org/swift/optionals-in-swift-explained-5-things-you-should-know/"
As you can see, we defined a custom mapping to convert the JSON key url
into the Swift property name htmlLink
.
As we’re not changing the name of title, category, and views, we can keep this case the same. We do have to include those keys as the JSONDecoder
will switch to our defined mapping for all defined properties. If we wouldn’t do it, we would run into the following error:
Type ‘BlogPost’ does not conform to protocol ‘Decodable’
Conversion between camel case and snake case
A common reason to define custom mapping for keys is that the backend you’re using uses snake case for naming properties. In Swift, we’re mostly using camel case which means that we start with a lowercase letter and then capitalize the first letter of subsequent words: htmlLink
or numberOfBlogPosts
. The same words in snake case look as follows: html_link
and number_of_blog_posts
.
Luckily enough, we don’t have to define a custom mapping for each defined key. Take the following example JSON of a blog:
{
"title": "A weekly Swift Blog on Xcode and iOS Development - onlinecode",
"url": "https://www.onlinecode.org",
"total_visitors": 378483,
"number_of_posts": 47093
}
We can easily decode that JSON by setting the keyEncodingStrategy
of our decoder to .convertFromSnakeCase
:
struct Blog: Decodable {
let title: String
let url: URL
let totalVisitors: Int
let numberOfPosts: Int
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let blog: Blog = try! decoder.decode(Blog.self, from: jsonData)
print(blog.numberOfPosts) // Prints: 47093
That was super easy! This also works fine with custom-defined keys. So if you would like to map url
to htmlLink
just like we did before, you can easily do that as follows:
struct Blog: Decodable {
enum CodingKeys: String, CodingKey {
case title, totalVisitors, numberOfPosts
case htmlLink = "url"
}
let title: String
let htmlLink: URL
let totalVisitors: Int
let numberOfPosts: Int
}
Decoding JSON dates with custom formats
Dates in JSON are defined as a String or time interval and require a conversion strategy. We can set such a strategy on our JSONDecoder
, just like we did for converting camel case to snake case.
Take the following JSON example of a blog post:
{
"title": "Optionals in Swift explained: 5 things you should know",
"date": "2019-10-21T09:15:00Z"
}
The date in this example is defined with the following format: yyyy-MM-dd'T'HH:mm:ss
. We need to create a custom DateFormatter
with this format and apply this to our decoder by setting the dateDecodingStrategy
to formatted
:
struct BlogPost: Decodable {
let title: String
let date: Date
}
let decoder = JSONDecoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.locale = Locale(identifier: "en_US")
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let blogPost: BlogPost = try! decoder.decode(BlogPost.self, from: jsonData)
print(blogPost.date) // Prints: 2019-10-21 09:15:00 +0000
There are a few other strategies available to set:
deferredToDate
: Uses Apple’s own data format that tracks the number of seconds and milliseconds since January 1st of 2001. This is mainly useful to use directly with Apple’s platforms.millisecondsSince1970
: This format tracks the number of seconds and milliseconds since January 1st of 1970 and is a lot more common to use.secondsSince1970
: Tracks the numbers of seconds since January 1st of 1970.iso8601
: Decodes the Date as an ISO-8601-formatted string (in RFC 3339 format).
Depending on how the API you’re using returns the dates you can choose between those strategies.
Conclusion
Swift makes decoding JSON really easy. There’s no need to use a custom library for JSON parsing as the default API brings everything we need, from custom key mapping to formatting dates.
If you like to improve your Swift knowledge, even more, check out the Swift category page. Feel free to contact me or tweet to me on Twitter if you have any additional tips or feedback.
Thanks!
<!– Disable cross link to Medium
Also published on Medium.
–>
Hope this code and post will helped you for implement JSON Parsing in Swift explained with code examples – onlinecode. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs