Wilmer Wilmer - 1 month ago 22
Swift Question

Appending to list property of persisted realm object?

have to preface with saying im a beginner programmer pardon any other glaring mistakes. Working with a simple database of two objects, A Show objects and it's corresponding episodes, who's details are fetched from a json request.

In the view that displays the persisted shows, i wrote a function to fire on a button press where the json file is checked for new & or missing episodes not present in the Shows episode List property. The function that i wrote below produces the unable to add objects with existing primary keys. (Don't recall the exact name off the top of my head at the moment)

I've done a test where i delete some episodes from the persisted shows and fire the method that initially saves the shows to the database and for some reason that accomplishes my desired functionality of adding only the deleted episodes without any crash or adding duplicates.

Not sure of any other moves at this point. Much thanks in advanced.

Realm constant in AppDelegate

let database = try! realm()


Realm Object Models

Class Show: Object {
dynamic var title: String? = nil
var episodes = List<Episode>()

class func showWithData (JSONShowObject) -> Show? {
let showTobeSaved = Show()
showTobeSaved.title = JSONShowObject.title

for episode in JSONShowObject.episodeArray {
let episodeToBeSaved = Episode.episodeWithData(episode)
showTobeSaved.episodes.append(episodeToBeSaved!)
}
return showToBeSaved
}

override static func primaryKey() -> String? {
return "title"
}
}

class Episode: Object {
dynamic var title: String? = nil

class func episodeWithData (JSONEpisodeObject) -> Episode? {
let episodeToBeSaved = Episode()
episodeToBeSaved.title = JSONEpisodeObject.title
return episodeToBeSaved
}

override static func primaryKey() -> String? {
return "title"
}
}


Function that adds show to Realm Database

func saveShowToDatabase(JSONShowObject) {
try! database.write() {
database.add(Show.showWithData(JSONShowObject), update: true)
}
}


View Controller for Persisted Shows

class ShowVC: UIViewController {

var shows: Results<Show>!

override func viewDidLoad() {
super.viewDidLoad()
shows = database.objects(Show.self)
}

@IBAction func updateShowEpisodes(_ sender: UIButton) {
updateEpisodesForStoredShows(showsInDatabase: shows)
}

func updateEpisodesForStoredShows (showsInDatabase: Results<Show>!) {
for showToUpdate in showsInDatabase {
for episodeToBeSaved in JSONShowObject.episodeArray {
try! database.write() {
showToUpdate.episodes.append(episodeToBeSaved)
}
}
}
}
}


Code Added after question answer

//Added To Show Model
func updateShowEpisodes() -> Show ? {
for episode in JSONShowObject.episode) {
if let episodeToBeSaved = database.object(ofType: Show.self, forPrimaryKey: episode.title) {
self.episodes.append(episodeToBeSaved)
} else {
self.episodes.append(Episode.episodeWithData(episode))
}
}
return self
}


//Changed Func in VC For Persisted Shows
func updateEpisodesForStoredShows(showsInDatabase: Results<Show>!) {
for showToUpdate in showsInDatabase {
try! database.write {
database.add(showToUpdate.updateEpisodeFeed()!, update: true)
}
}
}

TiM TiM
Answer

'Appending' an object to a Realm List counts as 'adding' a new copy of that object to the database. If another object already exists in the database with the same primary key; this will throw an exception. It will be necessary to query for that previously existing specific object instead of creating a new object with the same primary key (Which is what your JSON parser is doing).

It's possible to easily check if an object with a specific primary key already exists using the Realm().object(ofType:forPrimaryKey:) method. In this case, it would be more appropriate to use that method to first query that an object with that key exists, and if it does, use that one, instead of the one generated by JSON.

On a side-note, I'd also recommend you make your primary key values a little more unique. There's definitely been instances of different shows with identical names in the past (e.g, "Battlestar Galactica"), and easily episodes from different series having the same name (a lot of them usually have an episode called 'Pilot' somewhere in there. :)).

Getting the JSON to send down a unique primary key value for each show/episode would be the best, but you could also use the JSON information to 'construct' a primary key string that's more unique too.

Comments