I am working on an app which fetches data from Firebase. The code I am going to show you works just fine but even as a rookie I know that the implementation should be waaaaay better. I just can't really figure out how to refactor this.
Here's the TLDR:
I have created a Data Model which I used for pasing BlogPosts. I use a Struct for this and in the initial version all of my properties were of type String.
However, apart from Strings for Title and Summary, my Posts also contain an URL to an image and also a Date (post date).
I want to be able to return from my BlogPost object more concrete objcets such as an already created URL or a Date object.
Like I said, I know my implementation is bad, and I want to learn a better way of typecasting in such a way that I can achieve the behaviour described above.
Here is the implementation of my BlogPost data model:
import Foundation
import FirebaseDatabase
struct BlogPost {
let key: String
let title: String
let body: String
let summary: String
let author: String?
let liveSince: Date
let featuredImageLink: URL?
let itemReference:DatabaseReference?
init(snapshot: DataSnapshot) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-mm-dd"
key = snapshot.key
itemReference = snapshot.ref
if let snapshotDictionary = snapshot.value as? NSDictionary, let postTitle = snapshotDictionary["Title"] as? String {
title = postTitle
} else {
title = "Cannot display Title for this item :("
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postBody = snapshotDictionary["Body"] as? String {
body = postBody
} else {
body = "Cannot display Body for this item :("
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postSummary = snapshotDictionary["Summary"] as? String {
summary = postSummary
} else {
summary = "Due to some weird error, the Summary for this item cannot be displayed. Insert more coffee and Pizza in developer"
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postAuthor = snapshotDictionary["Author"] as? String {
author = postAuthor
} else {
author = "Nobody wrote this :("
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let postImageLink = snapshotDictionary["FeaturedImage"] as? String {
featuredImageLink = URL(string: postImageLink)!
} else {
featuredImageLink = URL(string:"https://someimagelink")!
}
if let snapshotDictionary = snapshot.value as? NSDictionary, let liveDate = snapshotDictionary["LiveSince"] as? String {
if let live = dateFormatter.date(from: liveDate) {
liveSince = live
} else {
liveSince = dateFormatter.date(from: "1990-06-26")!
}
} else {
liveSince = dateFormatter.date(from: "1990-06-26")!
}
}
}
Any constructive feedback is more than welcome as I do really want to understand how to do this properly or if it even makes sense to do so in the first place!
Thank you very much for your replies in advance!
I have some suggestions. It looks you keep using conditional binding to unwrap the snapshsot.value while casting it as an NSDictionary. Since unwrapping this value is prerequisite to unwrapping the other values, why not just use a guard statement to unwrap it? In your guard statement, you can then default initialize all the properties in your struct. Alternatively, if you are not adamant about default initializing your properties, you can just use a failable initializer and just return nil in the guard statement.
guard let snapshotDictionary = snapshot.value as? NSDictionary else {
title = "Cannot display Title for this item :("
body = "Cannot display Body for this item :("
summary = "Due to some weird error, the Summary for this item cannot be
displayed. Insert more coffee and Pizza in developer"
...
...
}