I'm facing an issue with my application. Some users when trying to open the app get an error from readDatabase closure. This affects like 20% of the users.
In this code i have to main function, one is readDatabaseChina that reads from a json hosted in Hong Kong as firebase is not working in China. The second one is readDatabase that gets data from Firebase real time database. The other called function are normal sync functions that selects data from NSArrays.
import Foundation
import Firebase
import FirebaseDatabase
struct FirebaseFetch {
enum collectionType {
case astronomyLockscreens, colorLockscreens, emojiLockscreens, photoLockscreens, weatherLockscreens
}
public func readDataBaseChina(completion: @escaping ((lockscreens: [Lockscreen], creators: [Creator], collections: [Collection], widgets: [Widget]), Error?) -> Void) {
var lockscreens: [Lockscreen] = [Lockscreen]()
var creators: [Creator] = [Creator]()
var collections: [Collection] = [Collection]()
var widgets: [Widget] = [Widget]()
let urlString = "JSONURL"
if let url = URL(string: urlString) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
DispatchQueue.main.async {
guard error == nil else {
print("Something went wrong during Firebase/Database fetch.")
completion(([Lockscreen](), [Creator](), [Collection](), [Widget]()), error)
return
}
do {
if let data = data,
let snapshotDictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let fetchedCreators = snapshotDictionary["Creators"] as? NSArray ?? []
let fetchedCollections = snapshotDictionary["Collections"] as? NSArray ?? []
let fetchedWidgets = snapshotDictionary["Widgets"] as? NSArray ?? []
let astronomyLockscreens = snapshotDictionary["AstronomyLockscreens"] as? NSArray ?? []
let colorLockscreens = snapshotDictionary["ColorLockscreens"] as? NSArray ?? []
let emojiLockscreens = snapshotDictionary["EmojiLockscreens"] as? NSArray ?? []
let photoLockscreens = snapshotDictionary["PhotoLockscreens"] as? NSArray ?? []
let weatherLockscreens = snapshotDictionary["WeatherLockscreens"] as? NSArray ?? []
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: astronomyLockscreens, type: .astronomyLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: colorLockscreens, type: .colorLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: emojiLockscreens, type: .emojiLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: photoLockscreens, type: .photoLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: weatherLockscreens, type: .weatherLockscreens))
creators.append(contentsOf: self.fetchCreators(creators: fetchedCreators))
collections.append(contentsOf: self.fetchCollections(collections: fetchedCollections, lockscreens: lockscreens))
widgets.append(contentsOf: self.fetchWidgets(widgets: fetchedWidgets))
completion((lockscreens: lockscreens, creators: creators, collections: collections.reversed(), widgets: widgets), nil)
}
} catch let error as NSError {
print("Something went wrong during Firebase/Database fetch.")
completion(([Lockscreen](), [Creator](), [Collection](), [Widget]()), error)
return
}
}
}.resume()
}
}
public func readDatabase(completion: @escaping ((lockscreens: [Lockscreen], creators: [Creator], collections: [Collection], widgets: [Widget]), Error?) -> Void) {
var lockscreens: [Lockscreen] = [Lockscreen]()
var creators: [Creator] = [Creator]()
var collections: [Collection] = [Collection]()
var widgets: [Widget] = [Widget]()
var ref: DatabaseReference!
ref = Database.database().reference()
DispatchQueue.global(qos: .userInitiated).async {
ref.getData(completion: { error, snapshot in
guard error == nil,
let snapshotDictionary = snapshot.value as? NSDictionary
else {
print("Something went wrong during Firebase/Database fetch.")
completion(([Lockscreen](), [Creator](), [Collection](), [Widget]()), error)
return
}
let fetchedCreators = snapshotDictionary["Creators"] as? NSArray ?? []
let fetchedCollections = snapshotDictionary["Collections"] as? NSArray ?? []
let fetchedWidgets = snapshotDictionary["Widgets"] as? NSArray ?? []
let astronomyLockscreens = snapshotDictionary["AstronomyLockscreens"] as? NSArray ?? []
let colorLockscreens = snapshotDictionary["ColorLockscreens"] as? NSArray ?? []
let emojiLockscreens = snapshotDictionary["EmojiLockscreens"] as? NSArray ?? []
let photoLockscreens = snapshotDictionary["PhotoLockscreens"] as? NSArray ?? []
let weatherLockscreens = snapshotDictionary["WeatherLockscreens"] as? NSArray ?? []
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: astronomyLockscreens, type: .astronomyLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: colorLockscreens, type: .colorLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: emojiLockscreens, type: .emojiLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: photoLockscreens, type: .photoLockscreens))
lockscreens.append(contentsOf: self.fetchLockscreens(lockscreens: weatherLockscreens, type: .weatherLockscreens))
creators.append(contentsOf: self.fetchCreators(creators: fetchedCreators))
collections.append(contentsOf: self.fetchCollections(collections: fetchedCollections, lockscreens: lockscreens))
widgets.append(contentsOf: self.fetchWidgets(widgets: fetchedWidgets))
completion((lockscreens: lockscreens, creators: creators, collections: collections.reversed(), widgets: widgets), nil)
})
}
}
}
Than i use fetched data like this:
var database: () -> Effect<(lockscreens: [Lockscreen], creators: [Creator], collections: [Collection], widgets: [Widget]), Error> = {
.future { complete in
let firebaseFetch: FirebaseFetch = FirebaseFetch()
let locale = Locale.current
if locale.regionCode == "CN" || locale.regionCode == "HK" || locale.regionCode == "MO" {
firebaseFetch.readDataBaseChina() { db, error in
guard error == nil,
!db.lockscreens.isEmpty,
!db.collections.isEmpty,
!db.widgets.isEmpty
else {
print("Something went wrong with firebaseFetch closure in App+Core.")
return complete(.failure(.cannotReadFromFirebase))
}
return complete(.success(db))
}
} else {
firebaseFetch.readDatabase() { db, error in
guard error == nil,
!db.lockscreens.isEmpty,
!db.collections.isEmpty,
!db.widgets.isEmpty
else {
print("Something went wrong with firebaseFetch closure in App+Core.")
return complete(.failure(.cannotReadFromFirebase))
}
return complete(.success(db))
}
}
}
.receive(on: DispatchQueue.main)
.eraseToEffect()
So basically in my Crashalytics i have a log of complete(.failure(.cannotReadFromFirebase)) that says that 20% of users faced this issue.
What is the problem here? Could the problem be DispatchQueue.global(qos: .userInitiated).async { inside read database?