How to change Realm singleton attribute value - swift

I have a Realm object:
class TransactionDB: Object {
dynamic var transactionID : Int = -1
dynamic var registrationPlate : String = ""
dynamic var locationID : Int = 0
dynamic var time : String = ""
dynamic var subscription : String = ""
dynamic var startTime : NSDate = NSDate()
dynamic var endTime : NSDate = NSDate()
dynamic var status : Int = -2
dynamic var requestType : Int = -1
var extensions : List<ExtensionDB> = List<ExtensionDB>()
dynamic var price : Double = 0
dynamic var currency : String = ""
private dynamic var test : Int = 10
override static func primaryKey() -> String? {
return "transactionID"
}
class var sharedInstance : TransactionDB {
struct Singleton {
static let instance = TransactionDB()
}
return Singleton.instance
}
static func saveOrUpdate {
// ......
}
and a singleton version for it. So I have one object over many controllers when screens change.
A few days back I was using some older Objective-C version of Realm but now I changed to the Swift-only version 1.0.2 and I'm trying to fix all the problems.
So now it came to part that when I try to call stuff like:
TransactionDB.sharedInstance.time = ""
I get an exception. However, after I do the following, it works:
let realm = try! Realm()
try! realm.write {
TransactionDB.sharedInstance.time = ""
}
So am I creating the singleton wrong or is this just the way it has to be done? Because, for me, it is a little annoying that I would always have to use a try block when I want to change the value of some attribute.

Take a look at the first line of the Realm docs for the write section.
It states:
All changes to an object (addition, modification and deletion) must be done within a write transaction.
So yea, it's just how you have to do it.

Related

How to save and load GKGameModelPlayer from Realm in Swift?

I am attempting to implement a GKGameModel in my application. In it, it holds variables to a few things, but for the purposes of my question I'm interested in the following two variables:
import GameplayKit
final class GameModel: NSObject, GKGameModel {
var players: [GKGameModelPlayer]?
var activePlayer: GKGameModelPlayer?
}
I do something like this to initialise the game with 3 players (not exact)
let game = GameModel.init()
game.players = [Player(),Player(),Player()] // Create 3 players
guard let firstPlayer = game.players.first else {
return
}
game.activePlayer = firstPlayer
A player class is defined as:
class Player : NSObject, GKGameModelPlayer {
var playerId: Int // GKGameModelPlayer protocol variable
let name: String
var cash: Int = 0
}
In my project I have Realm Entities and the models seperated. So there will be a PlayerEntity and a Player class.
I'm wanting to use RealmSwift to save and load the GKGameModelPlayer data, and more specifically the ability to store/re-store the active player.
I think the key here is the playerId variable; but I am not sure.
But what I'm not sure about is retrieving this information and then re-mapping it into a valid GKGameModelPlayer format
My current idea/theory is that I need to map my model to an entity class and vice-versa.
Ie:
// [REALM] Player entity
class PlayerEntity: Object {
#objc dynamic var id = UUID().uuidString
#objc dynamic var playerId: Int = 0
#objc dynamic var name: String = ""
#objc dynamic var cash: Int = 0
override static func primaryKey() -> String {
return "id"
}
}
And then I extend this class to do some "mapping":
extension PlayerEntity {
// Map model -> entity
convenience init(model: Player) {
self.init()
self.playerId = model.playerId
self.name = model.name
self.cash = model.cash
}
}
extension Player {
// Map entity -> model
convenience init(entity: PlayerEntity) {
let playerId = entity.playerId
let name = entity.name
let cash = entity.cash
self.init(id: playerId, name: name, cash: cash)
}
}
Right now, the playerId is always zero (0) because I'm not really sure how to set it.
I can save a player to realm.
The issue comes from when I try to restore the player, and I want to restore the activePlayer variable in the GameModel
Therefore, my question is:
How would I go about saving and restoring the activePlayer variable so that it continues to comply to GKGameModelPlayer?
I appreciate any assistance on this.
With thanks
While you could use those extensions, sometimes simpler is better. Here's a rough example:
class PlayerEntity: Object {
#objc dynamic var playerId: Int = 0
#objc dynamic var name: String = ""
#objc dynamic var cash: Int = 0
convenience init(withPlayer: PlayerClass) {
self.init()
self.playerId = withPlayer.playerId
self.name = withPlayer.name
self.cash = withPlayer.cash
}
func getPlayer() -> Player {
let p = Player()
p.playerId = self.playerId
p.name = self.name
p.cash = self.cash
return p
}
override static func primaryKey() -> String {
return "playerId"
}
}
to load all the players into an array... this will do it
let playerResults = realm.objects(PlayerEntity.self)
for player in playerResults {
let aPlayer = player.getPlayer()
self.playerArray.append(aPlayer)
}
Notice the removal of
#objc dynamic var id = UUID().uuidString
because it's not really being used to identify the object as a primary key.
The primary key is really
var playerId: Int // GKGameModelPlayer protocol variable
which is fine to use as long as it's unique.

Get associated object value from filter query using Realm swift

So Im pretty new to realm and i feel my question is very basic but i cant find the answer to it.
Basically I'm trying to query Realm for all playerName associated with a specific TeamID (ie. TeamID is not the primary key), however Im having trouble finding the solution. I keep getting a Value of type 'Results<playerInfoTable>' has no member 'playerName' error.
Below is my Realm class:
`class playerInfoTable: Object {
#objc dynamic var playerID: Int = 0
#objc dynamic var playerName: String = ""
#objc dynamic var jerseyNum: Int = 0
#objc dynamic var TeamID: String = ""
#objc dynamic var goalCount: Int = 0
#objc dynamic var shotCount: Int = 0
override class func primaryKey() -> String {
return "playerID"
}
}`
And the Code I'm using the query Realm:
let mainPlayerFilter = NSPredicate(format: "teamID == %#", "1")
let mainPlayerStrings = realm.objects(playerInfoTable.self).filter(mainPlayerFilter)
let mainPlayerTeamName = mainPlayerStrings.playerName
Solution!
let mainPlayerFilter = NSPredicate(format: "TeamID == %#", String(homeTeam!))
let mainPlayerStrings = realm.objects(playerInfoTable.self).filter(mainPlayerFilter)
let mainPlayerTeamName = mainPlayerStrings.value(forKeyPath: "playerName") as! [String]
I suppose you get the error when you declare the mainPlayerTeamName constant. Try the following:
let mainPlayerTeamName = mainPlayerStrings.first?.playerName
And I noticed that in your playerInfoTable class you declare "teamID" as "TeamID", while in your predicate you refer to it as "teamID". Decide which one you want because NSPredicate is case sensitive by default.

Swift Get value from function

I have two class and i would like to get a variable with the value (the variable is in a function) to my second class :
public class StreamPlayer {
class var sharedInstance : StreamPlayer{
struct Static {
static let instance : StreamPlayer = StreamPlayer()
}
return Static.instance
}
public var intermediate = NSString()
func metaDataUpdated(metaData : NSString){
var result : String = ""
var listItems = metaData.componentsSeparatedByString(";") as [String]
if (listItems.count > 0){
var containerName = listItems[0]
result = "StreamTitle=\'([^\"]*)\'".matchesForRegexIn(containerName, atRangeIndex: 1)
self.intermediate = result
}
}
}
and the second class
class RadioViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
println(test + StreamPlayer.sharedInstance.intermediate)
}
}
The problem is that the var intermediate doesn't change and don't get the value of result (in my first class)
I've copied your StreamPlayer class code into a playground. I've just commented out the matchesForRegexIn method as it seems it's your String extension so my code looks like this:
public class StreamPlayer {
class var sharedInstance : StreamPlayer{
struct Static {
static let instance : StreamPlayer = StreamPlayer()
}
return Static.instance
}
public var intermediate = String()
func metaDataUpdated(metaData : NSString){
var result : String = ""
let listItems = metaData.componentsSeparatedByString(";") as [String]
if (listItems.count > 0){
// var containerName = listItems[0]
result = "StreamTitle=\'([^\"]*)\'" //.matchesForRegexIn(containerName, atRangeIndex: 1)
intermediate = result
}
}
}
// calling the method to make sure intermediate gets updated
StreamPlayer.sharedInstance.metaDataUpdated("asd")
// check if it got updated
print(StreamPlayer.sharedInstance.intermediate)
The last line prints StreamTitle=\'([^\"])\'* so all is good. Just make sure to call StreamPlayer.sharedInstance.metaDataUpdated before checking intermediate
PS. I'm really not sure what you're trying to achieve by sharing intermediate results from a function to the outside world but it feels off. Think about splitting metaDataUpdated method into two methods maybe?
PPS. metaDataUpdated is a really bad name for a function
PPPS. If I were you I'd declare intermediate as String?
self.intermediate is a NSString while result is a String
Try
self.intermediate = result as NSString

RealmSwift replacement for RLMobject

Whats the correct way todo this with RealmSwift, it used to be RLMobject
var stream:Results<streams>
stream = Realm().objects(streams)
this first one lives on my class as a global the second line in my viewdidload
this is what i try todo: https://dpaste.de/AKKJ
class tabelviewcontroller has no initializers
the model
class streams: Object {
dynamic var br = ""
dynamic var categorie = 0
dynamic var ct = ""
dynamic var lc = ""
dynamic var ml = ""
dynamic var mt = ""
dynamic var name = ""
dynamic var shoutcatid = 0
dynamic var stationid = 0
override static func primaryKey() -> String? {
return "stationid"
}
}
A few quick notes, its good to keep class names singular, my model would look like this:
class Stream: Object {
...
}
If you want to get all objects from streams you can just do this:
let results = Realm().objects(Stream)
var stream:Results<streams>!
solved it

Swift: Realm error at init "NULL is not supported as an RLMObject property". But I don't have a NULL

It seems most people with this error are trying to create null strings. I just have three properties
dynamic var babyEvent: Int
dynamic var eventDate: NSDate
dynamic var timeSpent: Int
which are initialized in init() to
override init()
{
self.babyEvent = BabyWet
self.eventDate = NSDate()
self.timeSpent = 5
super.init()
}
but by the time super.init() is called I get
'(null)' is not supported as an RLMObject property.
There are two Ints and one NSDate, all of which are valid Realm property types. So why am I getting this error?
Realm doesn't support Swift enum's with no raw value. But adding a raw type to the BabyEvent enum and assigning the raw value to your realm objects works:
enum BabyEvent: Int {
case BabyWet, case BabyDry
}
class MyRealmObject: RLMObject {
dynamic var babyEvent = BabyEvent.BabyWet.rawValue
dynamic var eventDate = NSDate()
dynamic var timeSpent = 0
}
In Swift Enums have a specific type. So while you think you are passing an Int for BabyWet you are actually passing something of that specific type.
It seems that you have an Enum for the BabyEvent, so you should really have a look at the rawValue property:
self.babyEvent = BabyWet.rawValue
As I wrote, you can just set the starting values in the model definitions:
class TestClass: RLMObject {
dynamic var babyEvent: Int = 1
dynamic var eventDate: NSDate = NSDate()
dynamic var timeSpent: Int = 5
}
but this also works for me:
class TestClass: RLMObject {
dynamic var babyEvent: Int
dynamic var eventDate: NSDate
dynamic var timeSpent: Int
override init() {
babyEvent = 1
eventDate = NSDate()
timeSpent = 5
super.init()
}
}
In both cases I simply use
let realm = RLMRealm.defaultRealm()
var myTestObject = TestClass()
realm.beginWriteTransaction()
realm.addObject(myTestObject)
realm.commitWriteTransaction()
to create and add the object to the Realm.