-1

I have a struct called DailyEvents that initializes as a dictionary. We attempt to append to the dictionary in another class, however, receive the error:

Cannot use mutating member on immutable value because allEvents is a get-only property.

Here is the function where we try to make use of the struct and append:

DispatchQueue.main.async {
   self.carePlanManager.store.enumerateEvents(of: ockActivity, startDate: self.startDate as DateComponents, endDate: self.endDate as DateComponents, handler: { (event, _) in
        if let event = event {
            self.dailyEvents?.allEvents.append(event)
        }
    }, completion: { (_, _) in
        innersemaphore.signal()
    })
}

Here is the definition of the struct:

struct DailyEvents {
    // MARK: Properties

    private var mappedEvents: [NSDateComponents: [OCKCarePlanEvent]]

    var allEvents: [OCKCarePlanEvent] {
        return Array(mappedEvents.values.flatMap{$0})
    }

    var allDays: [NSDateComponents] {
        return Array(mappedEvents.keys)
    }

    subscript(day: NSDateComponents) -> [OCKCarePlanEvent] {
        get {
            if let events = mappedEvents[day] {
                return events
            }
            else {
                return []
            }
        }

        set(newValue) {
            mappedEvents[day] = newValue
        }
    }

    // MARK: Initialization

    init() {
        mappedEvents = [:]
    }
}

I was thinking the subscript takes care of the functionality for querying or appending to the data structure but it doesn't. Should I create an append function directly in the DailyEvents struct?

ielyamani
  • 17,807
  • 10
  • 55
  • 90
Laurence Wingo
  • 3,912
  • 7
  • 33
  • 61
  • 3
    No. `allEvents` is a computed property whose value derives from `mappedEvents`. You have to define a method to add the key to `mappedEvents` – Code Different Oct 20 '18 at 08:21
  • 2
    You have to think about your data structure. If you add an event directly to `allEvents`, how would `mappedEvents` reflect that? – ielyamani Oct 20 '18 at 09:22
  • 1
    As already mentioned in your [previous question](https://stackoverflow.com/questions/52902695/how-can-i-use-nscalendar-range-function-within-calendar) don't use `NSDate...` if there is a native counterpart for example `DateComponents`. And *semaphore* looks frightening. Don't try to make asynchronous stuff synchronous. Learn how asynchronous data processing works. – vadian Oct 20 '18 at 11:02
  • 1
    Also how can `mappedEvents[day] = newValue` be right? You are throwing away the existing events for that day. Really? You don’t want to append the new events for that day to the existing events for that day? The whole thing makes no sense. – matt Oct 20 '18 at 11:07
  • @matt OCKCarePlanEvent is a CareKit data type and is available http://carekit.org/docs/Classes/OCKCarePlanEvent.html – Laurence Wingo Oct 20 '18 at 16:16
  • OK sorry about that one. But I still think the mapping from an event to a date components needs to be made explicit as part of the struct. You need to be able to hand the struct an event and let _it_ put the event into the right place in the dictionary. So far, you are not doing that; your subscript certainly does not do it. – matt Oct 20 '18 at 16:22

1 Answers1

0

Your struct is misconceived. You have this:

struct DailyEvents {
    private var mappedEvents: [NSDateComponents: [OCKCarePlanEvent]]
    // ...
}

So you have a private dictionary that maps an OCKCarePlanEvent to a date components (so that you can look up events quickly by day, I presume), but you have public methods that require the caller to pass both an event and a data components. In effect, this means that you expect everyone else to do the mapping for you!

That's wrong. This is your mapping (you, the struct). You need a way of accepting an event, pure and simple, and mapping it yourself, as part of the struct, so as to put it into the right place in the dictionary, whatever that may mean. It is not every else's job to maintain the dictionary. It is your job (you, the struct).

When you start thinking about your struct that way, encapsulating correctly, its public API will begin to fall into place.

matt
  • 515,959
  • 87
  • 875
  • 1,141