Josh Kopecek Josh Kopecek - 3 years ago 116
Swift Question

Thread-safe way of instantiating optional Realm objects

What I am trying to do is set up a series of AVPlayers which can be accessed via instance variables. Everything is stored in Realm and I've instantiated Collection with all the Realm vars in the previous view. Once the view loads, I want to load all the players, and then trigger them using some parameters from location. The thing is, when

locationManager
gets called, the player returns
nil
on the Player instance.

I'm guessing this is due to
locationManager
being called on a separate thread? What would be the thread-safe way of making sure the players have been instantiated if that is the case?

Here's the view with
locationManager
and the loader

class WalkMapViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate {
/* …lots of outlets */
var collection:Collection!

override func viewDidLoad() {
/* …lots of other init stuff */
self.loadPlayers()
}

func loadPlayers() {
// get a url from somewhere
for (i,_) in self.collection.players.enumerated() {
// loop through the players and load them
self.collection.players[i].player = AVPlayer(url: url)
}
}

func locationManager(_ manager:CLLocationManager, didUpdateLocations locations:[CLLocation]) {
for (i, _) in self.collection.players.enumerated() {
self.collection.players[i].play()
}
}
}


This is the heavily shortened Collection class which is a Realm object and which has
players
in ignoreProperties.

class Collection: Object, Mappable {
var players = List<Player>()
}


This is the Player class which is also a Realm object embedded in Collection, and has
player
in ignoreProperties

class Player: Object, Mappable {
var player:AVPlayer?
}

Answer Source

Your problem exists due to the fact that you are using ignored properties, which are not persisted by Realm. According to this GitHub issue about ignored properties, what you experience is the expected behaviour.

From the linked issue:

"Ignored properties are only guaranteed to be consistent across individual Swift instances, but retrieving an object from a collection creates a new Swift instance each time, thus the behavior that you see."

This means that the self.collection.players[i] inside locationManager(didUpdateLocations:) is actually a new Swift instance of the same Realm object that you created in loadPlayers(), which is not an issue with normal Realm properties, since they are fetched from the Realm database, but is causes an issue with ignored properties, since they are linked to a specific Swift instance and only exist in memory. Hence, when you retrieve a specific object from a collection (Player instance from `List'), all ignored properties are lost.

To sum it up, you won't be able to use ignored Realm properties in collections.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download