5

Edited to simplify my question...

I'm new to Realm and so far, it's pretty cool, but I'm having an extremely hard time figuring out how to querying my Realm DB to check if a specific item exists in it.

Here's my Realm Model:

import Foundation
import RealmSwift

class ChartCount: Object{

    dynamic var date: Date = Date()
    dynamic var count: Int = Int(0)
}

In my main ViewController I'm storing a series of ChartCount objects for the 7 days of the current week using the following function:

// function to check if this weeks days have been created in Realm DB yet and creates them if not
    let realm = try! Realm()
    lazy var visitors: Results<VisitorCount> = { self.realm.objects(VisitorCount.self)}()
    let startOfWeekDate = Date().startOfWeek(weekday: 1)
    let nextDay = 24 * 60 * 60

    var startOfWeek = try! Realm().objects(VisitorCount.self)

func setThisWeeksDays(){
            if charts.count == 0 {
                try! realm.write() {


                    let defaultVisitorDates = [startOfWeekDate, startOfWeekDate + TimeInterval(nextDay), startOfWeekDate + TimeInterval(nextDay*2), startOfWeekDate + TimeInterval(nextDay*3), startOfWeekDate + TimeInterval(nextDay*4), startOfWeekDate + TimeInterval(nextDay*5), startOfWeekDate + TimeInterval(nextDay*6)]

                    for visitors in defaultChartrDates {
                        let newChartDate = ChartCount()
                        newChartDate.date = visitors
                        self.realm.add(newChartrDate)
                    }
                }

                visitors = realm.objects(ChartCount.self)
            }
        }

And this to create the StartOfWeekDate

// Finds the start/end of the current week ----------------------------------------------- //
extension Date {
    func startOfWeek(weekday: Int?) -> Date {
        var cal = Calendar.current
        var component = cal.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)
        component.to12am()
        cal.firstWeekday = weekday ?? 1
        return cal.date(from: component)!
    }

    func endOfWeek(weekday: Int) -> Date {
        let cal = Calendar.current
        var component = DateComponents()
        component.weekOfYear = 1
        component.day = -1
        component.to12pm()
        return cal.date(byAdding: component, to: startOfWeek(weekday: weekday))!
    }

    func monthDay() -> String? {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMM dd"
        return dateFormatter.string(from: self)
    }
}
internal extension DateComponents {
    mutating func to12am() {
        self.hour = 0 + 24
        self.minute = 0
        self.second = 0
    }

    mutating func to12pm(){
        self.hour = 0
        self.minute = 0
        self.second = 0
    }
}// </end> Finds the start/end of the current week ------------------------------------------ //

All I want to do is check the 'date' column of my ChartDate model to see if there is an object in it that contains the first day of this week (e.g. startOfWeekDate).

jammyman34
  • 1,399
  • 4
  • 15
  • 22
  • What happens if you make `startOfWeek` lazy like how `visitors` is right now, initialized by a closure? That should stop Swift from complaining about using an instance variable when initializing another instance variable. – AustinZ Apr 20 '17 at 20:50
  • I'm confused by your filter code - you seem to be comparing a Date field to a literal text string 'startOfWeekDate' – Russell Apr 20 '17 at 21:16
  • As Russell mentions, your filter is malformed. Instead of "date = 'startOfWeekDate'", try "date = \\(startOfWeekDate)" – Mozahler Apr 20 '17 at 21:18
  • @AustinZ changing it to "lazy var startOfWeek: Results = {self.realm.objects(VisitorCount.self).filter("date = 'startOfWeekDate'")}()" did indeed get rid of the error, but ultimately I think Russell is correct that the Filter method I was using is an incorrect way of doing it. I've also tried doing something like "lazy var startOfWeek: Results = {self.realm.objects(VisitorCount.self).filter("date = 'startOfWeekDate'")}()" from Realm's documentation, but I couldn't get it to work either. Basically I just want to check against the 'date' objects. – jammyman34 Apr 20 '17 at 21:19
  • @Mozahler if you mean this: var startOfWeek = realm.objects(VisitorCount.self).filter("date = '\(startOfWeekDate)'") I'm still getting the "Connot use instance member 'realm'..." Xcode error. Again, though, I'm not even sure using a Filter is necessary as I just want to query the entire DB to see if a specific Date exists. – jammyman34 Apr 20 '17 at 21:23
  • No. see my revised comment. No single quotes., surround the date variable with parens and precede it with a backslash. (it took me a few tries to figure out what the editor was doing...) – Mozahler Apr 20 '17 at 21:25
  • @Mozahler Still gets the same Xcode error unfortunately – jammyman34 Apr 20 '17 at 21:28
  • OK. I think you have more than one problem. I'll check back later to see how you're doing.  – Mozahler Apr 20 '17 at 21:30
  • heh, I'm sure that's the case for sure :) – jammyman34 Apr 20 '17 at 21:32
  • I'll try to take a closer look at this later, but another issue is that you need to pass in a proper `NSPredicate` format string rather than using Swift string interpolation. Check this link out for more details. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html – AustinZ Apr 20 '17 at 21:58
  • so looking back at Realm's documentation on filters (https://realm.io/docs/swift/latest/#filtering) and based on what @AustinZ said, I tried this: lazy var startOfWeek: Results = {self.realm.objects(ChartCount.self).filter("date = 'startOfWeekDate'")}() let predicate = NSPredicate(format: "date = %@ 'startOfWeekDate'") startOfWeek = realm.objects(ChartCount.self).filter(predicate).. Xcode error = Expected declaration on the startOfWeek = real.objects etc line – jammyman34 Apr 20 '17 at 22:59
  • OK, I've updated my sample code to use the Realm Filter w/ Predicate code which does not generate any Xcode errors. The problem I have now is how do I use it to check if startOfWeekDate exists in the DB? If I place this in a button and tap it I get a terminating error: var startOfWeek = realm.objects(VisitorCount.self).filter("date = 'startOfWeekDate'") let predicate = NSPredicate(format: "date = %@ 'startOfWeekDate'") startOfWeek = realm.objects(VisitorCount.self).filter(predicate) print(startOfWeek) – jammyman34 Apr 21 '17 at 16:42
  • I think I've tried 15 different things in order to filter on the date of my Realm Model and every time I attempt to simply print the results after tapping a button I get an exception error. I can't believe that this is proving to be as difficult as it is?! I just want to check my Realm DB's 'date' column for a specific entry. Why is this so freaking difficult?!! – jammyman34 Apr 21 '17 at 20:50

3 Answers3

4

For anyone looking to access Realm objects by Primary Key (Like I was) here's the code:

let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: myPrimaryKey)
Matjan
  • 3,591
  • 1
  • 33
  • 31
2

You cannot access Realm in the initializer, but you already have the answer in your code. Make start of week lazy just like you have for visitors and it will not be initialized until its used, and by the time your init is done. This is the way most of the realm examples are done.

lazy var startOfWeek: Result<ChartCount> = {
    return realm.objects(ChartCount.self).filter("date = 'startOfWeekDate'")
}()

Alternatively you can make start of week an implicitly unwrapped optional and initialize it in viewDidLoad or just make it a regular optional

var startOfWeek: Result<ChartCount>!
...
//ViewDidLoad
realm.objects(ChartCount.self).filter("date = 'startOfWeekDate'")
Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • so with your first change I'm getting this Xcode error = Instance member 'realm' cannot be used on type 'ViewController' – jammyman34 Apr 20 '17 at 21:39
0

OK, I think I've got it working. This is what I did:

To check if the Realm DB has the startOfWeekDate record I created this function:

func searchForStartOfWeek(findDate: Date) -> ChartCount?{
        let predicate = NSPredicate(format: "date = %@", findDate as CVarArg)
        let dateObject = self.realm.objects(ChartCount.self).filter(predicate).first

        if dateObject?.date == findDate{
            return dateObject
        }
        return nil
    }

Then I used it to check if it exists:

func setThisWeeksDays(){
        if searchForStartOfWeek(findDate: startOfWeekDate) == nil {
            try! realm.write() {


                let defaultChartDates = [startOfWeekDate, startOfWeekDate + TimeInterval(nextDay), startOfWeekDate + TimeInterval(nextDay*2), startOfWeekDate + TimeInterval(nextDay*3), startOfWeekDate + TimeInterval(nextDay*4), startOfWeekDate + TimeInterval(nextDay*5), startOfWeekDate + TimeInterval(nextDay*6)] // 3

                for charts in defaultChartDates {
                    let newChartDate = ChartCount()
                    newChartDate.date = charts
                    self.realm.add(defaultChartDates)
                }
            }

            visitors = realm.objects(ChartCount.self)
        }
    }

Thanks for everyones help!

jammyman34
  • 1,399
  • 4
  • 15
  • 22