I just start to learn Realm data persistence, I start it from a iOS test project.
The realm object is declared like this:
class AchievementRecord: Object {
dynamic var dateID:String = "1111-00-00"
dynamic var date:String = "0000-00-00"
dynamic var apple:Int = Int(0)
override static func primaryKey() -> String? {
return "dateID"
}
}
I initialise the object in View Controller's viewDidLoad() method as this:
class AchievementRecord: Object {
dynamic var dateID:String = "1111-00-00"
dynamic var date:String = "0000-00-00"
dynamic var apple:Int = Int(0)
override static func primaryKey() -> String? {
return "dateID"
}
}
then I declare another function to obtain the save data as:
let appleOn_05 = defaultRealm.objects(AchievementRecord.self).filter("dateID = '05-06-2017'")
print(appleOn_05)
In the console, Xcode says:
Because I need to retrieve the apple's number, which is 22 in the console. How can I retrieve the apple's number to demo it on the screen, how can I do it? Thanks in advance.
Results works like native Swift collections in many ways. If you are fetching a single object, you can just access it with Results.first let appleOn_05 = defaultRealm.objects(AchievementRecord.self).filter("dateID = '05-06-2017'").first
Subclasses of Object work like any other native class instance in Swift, so you can access their properties using the dot syntax.
let apple = appleOn_05.apple
Combining the two:
if let appleOn_05 = defaultRealm.objects(AchievementRecord.self).filter("dateID = '05-06-2017'").first {
let apple = appleOn_05.apple
}
Related
These are my realm classes and functions:
class RealmItems: Object {
#objc dynamic var header = String()
#objc dynamic var specification = String()
#objc dynamic var day = Int()
#objc dynamic var month = Int()
#objc dynamic var deadline = String()
#objc dynamic var status = String()
}
class RealmModel {
static let shared = RealmModel()
private let realm = try! Realm()
func addTask(headerTask: String, specificationTask: String, dayTask: Int, monthTask: Int, deadlineTask: String, statusTask: String) {
let new = RealmItems()
new.header = headerTask
new.specification = specificationTask
new.day = dayTask
new.month = monthTask
new.deadline = deadlineTask
new.status = statusTask
try! realm.write {
realm.add(new)
}
}
func deleteTask(name: RealmItems) {
try! realm.write {
realm.delete(name)
}
}
func getTasks() -> [RealmItems] {
var arrayTasks: [RealmItems] = []
for task in realm.objects(RealmItems.self) {
arrayTasks.append(task)
}
return arrayTasks.sorted{$0.day > $1.day}
}
}
function getTasks() doesn't work the way i want it works. Now collection shows oldest cells higher than newest - that's wrong. I want to newest were higher than oldest
A few things to be aware of.
First, read Realm Objects Are Lazily Loaded e.g. don't cast them to an array or sort them using Swift functions. Well, you can but it can lead to other issues so best to avoid that unless there's a specific use case that requires it.
Secondly, Realm Results do not have a guaranteed order unless you specify that order. On the other hand, a List object maintains it's order.
Ordering a Results collection is simple, and actually keeps the objects in the results in order as object properties change, for example
let orderedResults = realm.objects(RealmItems.self).sorted(byKeyPath: "day", ascending: false)
Will load all of the RealmItems objects sorted by day, descending (e.g. 20th will be at the top and the 1st will be at the bottom)and the results will maintain their order. e.g. if a day changes, it will auto sort within the list. Pretty magical, huh?
I'm trying to add to an embedded "Conversation" object within my user collection (for a chat app) in Mongo Realm. I would like to create a "default" conversation when the user account is created, such that every user should be a member of at least one conversation that they can then add others to.
The app currently updates the user collection via a trigger and function in Realm at the back end using the email / Password authentication process.
My classes are defined in Swift as follows:
#objcMembers class User: Object, ObjectKeyIdentifiable {
dynamic var _id = UUID().uuidString
dynamic var partition = "" // "user=_id"
dynamic var userName = ""
dynamic var userPreferences: UserPreferences?
dynamic var lastSeenAt: Date?
var teams = List<Team>()
dynamic var presence = "Off-Line"
var isProfileSet: Bool { !(userPreferences?.isEmpty ?? true) }
var presenceState: Presence {
get { return Presence(rawValue: presence) ?? .hidden }
set { presence = newValue.asString }
}
override static func primaryKey() -> String? {
return "_id"
}
#objcMembers class Conversation: EmbeddedObject, ObjectKeyIdentifiable {
dynamic var id = UUID().uuidString
dynamic var displayName = ""
dynamic var unreadCount = 0
var members = List<Member>()
}
So my current thinking is that I should code it in Swift as follows which I believe should update the logged in user, but sadly can't get this quite right:
// Open the default realm
let realm = try! Realm()
try! realm.write {
let conversation = Conversation()
conversation.displayName = "My Conversation"
conversation.unreadCount = 0
var user = app.currentUser
let userID = user.id
let thisUser = User(_id: userID)
realm.add(user)
}
Can anyone please spot where I'm going wrong in my code?
Hours spent on Google and I'm missing something really obvious! I have a fair bit of .NET experience and SQL but struggling to convert to the new world!
I'm a noob when it comes to NoSQL databases and SwiftUI and trying to find my way looking at a lot of Google examples. My example us based on the tutorial by Andrew Morgan https://developer.mongodb.com/how-to/building-a-mobile-chat-app-using-realm-new-way/
I am a bit unclear on the exact use case here but I think what's being asked is how to initialize an object with default values - in this case, a default conversation, which is an embedded object.
If that's not the question, let me know so I can update.
Starting with User object
class UserClass: Object {
#objc dynamic var _id = ObjectId.generate()
#objc dynamic var name = ""
let conversationList = List<ConversationClass>()
convenience init(name: String) {
self.init()
self.name = name
let convo = ConversationClass()
self.conversationList.append(convo)
}
override static func primaryKey() -> String? {
return "_id"
}
}
and the EmbeddedObject ConversationClass
class ConversationClass: EmbeddedObject {
dynamic var displayName = "My Conversation"
dynamic var unreadCount = 0
var members = List<MemberClass>()
}
The objective is that when a new user is created, they have a default conversation class added to the conversationList. That's done in the convenience init
So the entire process is like this:
let realm = Realm()
let aUser = UserClass(name: "Leroy")
try! realm.write {
realm.add(aUser)
}
Will initialize a new user, set their name to Leroy. It will also initialize a ConversationClass Embedded object and add it to the conversationList.
The ConversationClass object has default values set for displayName and unread count per the question.
I have a realm database model object that I transfer from one controller to another. On another controller, I need to get data from this object, which stores the object of the type List. I need it in 'cellForRowAt' method.
This is my model:
class Route: Object {
#objc dynamic var routeImage: Data?
#objc dynamic var routeName: String?
#objc dynamic var numberOfPersons = 0.0
#objc dynamic var dateOfDeparture: String?
#objc dynamic var dateOfArrival: String?
let placeToVisit = List<Place>()
let person = List<Person>()
}
class Place: Object {
#objc dynamic var placeName = ""
convenience init(placeName: String) {
self.init()
self.placeName = placeName
}
}
on second VC I created:
var currentRoute: Route?
and in viewDidLoad I set:
currentRoute = UserSelectedRoute.shared.selectedRoute!
I can get data from other properties but not from the list type. I tried to implement 'reduce' method, but it doesn't work. It returns list type too. I think I need convert list to type Results but I don't know how I can return values from current object?
cellForRowAt image
As Jay suggested to me, the following solution helped me:
cell.textLabel!.text = currentRoute?.placeToVisit[indexPath.row].placeName
I thought this would be pretty straightforward after reading here and here but I'm a bit stuck.
I have a 'favouriteWorkout' object that looks like this :
class FavouriteObject: Object {
#objc dynamic var favouriteWorkoutName = ""
#objc dynamic var workoutReference = WorkoutSessionObject()
override class func primaryKey() -> String? {
return "favouriteWorkoutName"
}
}
What I'm trying to do here is reference a WorkoutSessionObject in Realm that links from a WorkoutName when a workout is saved as a favourite.
My WorkoutSessionObject has a primary key of workoutID which is a UUID string. It looks like this :
class WorkoutSessionObject: Object {
#objc dynamic var workoutID = UUID().uuidString
#objc dynamic var workoutType = ""
let exercises = List<WorkoutExercise>()
#objc dynamic var totalExerciseCount = 0
#objc dynamic var rounds = 0
#objc dynamic var favourite : Bool = false
override class func primaryKey() -> String? {
return "workoutID"
}
}
I've then tried to save using this :
let favouriteWorkout = FavouriteObject()
favouriteWorkout.favouriteWorkoutName = favouriteName
favouriteWorkout.workoutReference = (realm.object(ofType: WorkoutSessionObject.self, forPrimaryKey: self.workoutID))!
do {
try realm.write {
realm.add(favouriteWorkout)
}
} catch {
print ("Error adding favourite")
}
but i get a crash when I run of :
'RLMException', reason: 'The FavouriteObject.workoutReference property must be marked as being optional.
However, when I then try to make it optional (by adding ?) it says
"Cannot use optional chaining on non-optional value of type 'WorkoutSessionObject"!
Summary
I want to save a reference of the workoutID of a WorkoutSessionObject in my FavouriteObject which is an actual link to the WorkoutSessionObject (so the properties can be accessed from favourites)
Update
using the answers below I've now sorted the problem of the workout reference. This is now showing in Realm as the proper format () under "workoutReference". However, I'm now getting "nil" in "workoutReference" when trying to save. I know the workoutID is coming through correctly as I am printing it in the console.
You need to change the declaration of workoutReference. First of all, you need to make it Optional by writing ? after the type. Secondly, you shouldn't assign a default value to it, it needs to be Optional for a reason. The linked docs clearly state that
to-one relationships must be optional
, and workoutReference is clearly a to-one relationship.
class FavouriteObject: Object {
#objc dynamic var favouriteWorkoutName = ""
#objc dynamic var workoutReference:WorkoutSessionObject?
override class func primaryKey() -> String? {
return "favouriteWorkoutName"
}
}
In property-cheatsheet you can see that a non-optional Object-property is not allowed, so you have to change it like the following:
class FavouriteObject: Object {
#objc dynamic var favouriteWorkoutName = ""
// here you have to make the property optional
#objc dynamic var workoutReference: WorkoutSessionObject?
override class func primaryKey() -> String? {
return "favouriteWorkoutName"
}
}
I am trying to add a non-realm class object to realm object something like this.
class TrainTripItinerary: Object {
dynamic var departStationName: String?
dynamic var departStationCode: String?
var runningStatus: TrainRunningStatus?
override static func ignoredProperties() -> [String] {
return ["runningStatus"]
}
}
While TrainRunningStatus is not a realm class.
class TrainRunningStatus {
var trainDataFound: String?
var startDate: String?
var startDayDiff: String?
}
I am not able to update runningstatus property now. Anyone know how it works? I fetch separately runnningstatus and assign it to the realm object later but it stays nil even after the assignment.
eg.
let runningStatus = TrainRunningStatus()
trainTripItinerary.runningStatus = runningStatus
This line is not working, trainTripItinerary runningStatus property is not set properly its always nil.
As suggested in comments make sure you use the same instance of TrainTripItinerary because ignored properties won’t automatically update their value across different instances.
See an example code below that demonstrates how ignored properties work
let realm = try! Realm()
try! realm.write {
realm.deleteAll()
}
let runningStatus = TrainRunningStatus()
var trainTripItinerary = TrainTripItinerary()
trainTripItinerary.runningStatus = runningStatus
assert(trainTripItinerary.runningStatus != nil)
try! realm.write {
realm.add(trainTripItinerary);
}
assert(trainTripItinerary.runningStatus != nil)
trainTripItinerary = realm.objects(TrainTripItinerary.self).first!
assert(trainTripItinerary.runningStatus == nil)
Firstly, your code is not correct.
class TrainTripItinerary: Object {
dynamic var departStationName: String?
dynamic var departStationCode: String?
var runningStatus: TrainRunningStatus?
override static func ignoredProperties() -> [String] {
return ["runningStatus"]
}
}
func ignoredProperties() -> [String] is only used on Realm properties. Since your property var runningStatus: TrainRunningStatus? does not begin with dynamic, it is not a Realm property. You don't need to use func ignoredProperties() -> [String] here.
var runningStatus: TrainRunningStatus? here is called a "transient property" in Realm. Usually a transient property is something calculated basing on current date or on Realm properties, Realm won't do anything on transient properties and you should maintain them yourself.
So if you just want to use runningStatus as a transient property, you can simply remove the code override static func ignoredProperties() -> [String].