Search code examples
swiftfirebasefirebase-realtime-databasensuserdefaults

Saving Firebase snapshot array to NSUserDefaults


I am using Swift to retrieve data from my Firebase database. When the user first logs in, I'd like to save the 'places' from my Firebase snapshot as a UserDefault.

static func getAllPlaces(){

    databaseRef = Database.database().reference()

    databaseRef.database.reference().child("places").observe(.childAdded) { (snapshot: DataSnapshot) in

        if let value = snapshot.value as? NSDictionary {

            let place = Place()

            let id = value["id"] as? String ?? "ID not found"
            let title = value["title"] as? String ?? "Title not found"
            let type = value["type"] as? String ?? ""

            place.id = id
            place.title = title
            place.type = type

            DispatchQueue.global().async {
                // Something here to append place data to UserDefaults?
                places.append(place) // appends to NSObject for later use
            }
        }

    }
}

The current code works fine - I just need to add something to get it stored so I can grab it later.

Bonus question: I am storing a good few hundred snapshots in the Firebase database. The reason I want to store them on the device is so that the user doesn't have to keep downloading the data. Is this a good idea? Would it take up a lot of memory?

Any help would be appreciated.


Solution

  • One way to save custom classes/data to UserDefaults is to encode them like this:

    let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: place)
    UserDefaults.standard.set(encodedData, forKey: "place")
    UserDefaults.standard.synchronize()
    

    Then you can decode it like this:

    if UserDefaults.standard.object(forKey: "place") != nil{
        let decodedData = UserDefaults.standard.object(forKey: "place") as! Data
        let decodedPlace = NSKeyedUnarchiver.unarchiveObject(with: decodedData) as! Place
    }
    

    Updated for swift 4 and iOS 12:

    do {
        let encodedData: Data = try NSKeyedArchiver.archivedData(withRootObject: place, requiringSecureCoding: false)
        UserDefaults.standard.set(encodedData, forKey: "place")
        UserDefaults.standard.synchronize()
    } catch {
            //Handle Error
    }
    
    do {
        if UserDefaults.standard.object(forKey: "place") != nil{
            let decodedData = UserDefaults.standard.object(forKey: "place") as! Data
            if let decodedPlace = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(decodedData) as? Place {
                 //Do Something with decodedPlace
            }
        }
    }
    catch {
            //Handle Error
    }