1

I'm trying to parse some data that I cached using Haneke Swift. I've cached the data and have written the parser to accomplish this. This parser is in a separate class called AssembleCalendar().

Using Haneke's example code for fetching, I've tried with complete and utter failure to actually return a value from the closure.

My attempt

func getScheduledItems() -> [ScheduledItem] {
    
    var scheduledItem = [ScheduledItem]() // initialize array

    let cache = Shared.dataCache
    cache.fetch(key: "CalendarData").onSuccess { data in
        
        scheduledItem = AssembleCalendar().assimilate(data) // update array
        print(scheduledItem) // array returns expected value
        
    }

    print(scheduledItem) // array returns nil
    return scheduledItem // returns nil
}

What I know

I understand that this is an asynchronous issue. My code isn't waiting for my AssembleCalendar() parser to finish. It's just running each line and returns nil long before my scheduledItem receives a value. I've tried many, many solutions and read quite a few examples online but I cannot figure out how to retrieve a value from this closure in this scenario.

My question

How can I get .fetch() to return a value before my function hits nil?


update:

Here's my code in context:

class Schedule {

    var items : [ScheduledItem]
    
    init() {
        items = getScheduledItems() // Schedule.getScheduledItems()
    }
    
    func getScheduledItems(completion: (items: [ScheduledItem]) -> ()) {
        
        var scheduledItem = [ScheduledItem]() // initialize array
        
        let cache = Shared.dataCache
        cache.fetch(key: "CalendarData").onSuccess { data in
            
            scheduledItem = AssembleCalendar().assimilate(data) // update array
            print(scheduledItem) // array returns expected value
            completion(items: scheduledItem)
            
        }
    }
}
Community
  • 1
  • 1
Dan Beaulieu
  • 19,406
  • 19
  • 101
  • 135
  • If you're passing an array of ScheduledItem into the init function, why are you not setting that to the classes items variable instead of calling a function to get them? Or if you do need to use that function, do it before calling the init function of Schedule – Swinny89 Sep 10 '15 at 20:37
  • ignore that line, it was part of a temporary work-around so I could continue developing, I'll remove that line – Dan Beaulieu Sep 10 '15 at 20:39
  • I understand that you're trying to use a factory method here but in this case I don't believe it is the right approach. If you need to get your data in an asynch way then I would call that before instantiating the class. I will amend my answer to show you. – Swinny89 Sep 10 '15 at 20:44
  • Thanks Swinny, I'm looking at some of your other useful answers on this topic. – Dan Beaulieu Sep 10 '15 at 20:45
  • No problem, I have updated my answer to show a possible solution – Swinny89 Sep 10 '15 at 20:47

1 Answers1

1

Fetch() is using a completion handler, this means that the block of code called in there is actually executing AFTER your return statement has been executed. This is why it is returning nil. To get around this, you can use your own completion handler to return the information:

class Schedule {

    var items = [ScheduledItem]()

    init(items: [ScheduledItem]) {
        self.items = items
    }

    class func getScheduledItems(completion: (items: [ScheduledItem]) -> ()) {

        var scheduledItem = [ScheduledItem]() // initialize array

        let cache = Shared.dataCache
        cache.fetch(key: "CalendarData").onSuccess { data in

            scheduledItem = AssembleCalendar().assimilate(data) // update array
            print(scheduledItem) // array returns expected value
            completion(items: scheduledItem)

        }
    }
}

Then initialise the class using this:

Schedule.getScheduledItems { (items) -> () in
    var schedule = Schedule(items: items)
}
Swinny89
  • 7,273
  • 3
  • 32
  • 52