1

I'd like to build a dictionary using a functional programming style. My reduce() doesn't seem to work - I get a "fatal error: unexpectedly found nil while unwrapping an Optional value"

func loadMoveToCalendarsRules(calendarIndex: Int) -> [String]? {
//    return something like ["phone call", "buzz", "ring"]
    return NSUserDefaults.standardUserDefaults().objectForKey(generateMoveToCalendarsRules_NSUserDefaultsKey(calendarIndex)) as? [String]
}

// Add indeces to an array of any type
func addIndices<T>(toArray: [T]) -> [(index: Int, value: T)] {
    return Array(zip(toArray.indices, toArray))
}

typealias CalendarRules = [EKCalendar : [String]]?
func buildCalendarRules(cals: [EKCalendar]) -> CalendarRules {
    let sortedCals = cals.sort { $0.title.lowercaseString < $1.title.lowercaseString }

    // build move to cal rules.
    let indexedCalList = addIndices(sortedCals)
    // go through the sorted calendars and build a dictionary that associates each calendar with a string array. (These are keywords that apply to the given calendar.)
    let calendarRules = indexedCalList.reduce(nil as CalendarRules) {
        accumulator, nextValue in
        var retVal: [EKCalendar : [String]]? = accumulator
        // if there are values found in NSUserDefaults for this calendar index then retrieve them.
        if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
            retVal![nextValue.value] = rulesForCurrentCal       // fatal error: unexpectedly found nil while unwrapping an Optional value
        }
        return retVal
    }

    print("------------ built calendar rules -------------")
    print(Array(arrayLiteral: calendarRules?.keys))
    print(Array(arrayLiteral: calendarRules?.values))

    return calendarRules
}

2 Answers 2

1

Your retVal is optional, and starts as nil (the initial value you pass in), yet you are using retVal! to force-unwrap it. You could just use [:] (an empty dictionary) as the initial value, and then retVal wouldn't need to be optional at all.

Sign up to request clarification or add additional context in comments.

Comments

1

You are starting with nil, and never instantiate a CalendarRules dictionary, so the attempt to performed a forced unwrapping of it with ! is going to fail. Instead, test to see if it's nil and if so, instantiate one.

Before I get to that, I'd first suggest defining calendar rules as a non-optional type. It makes things less confusing this way:

typealias CalendarRules = [EKCalendar : [String]]

Then, you could use nil-coalescing operator, ??, to instantiate the CalendarRules object when needed:

let calendarRules = indexedCalList.reduce(nil as CalendarRules?) { accumulator, nextValue in
    if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
        var retVal = accumulator ?? CalendarRules()
        retVal[nextValue.value] = rulesForCurrentCal
        return retVal
    }
    return accumulator
}

It strikes me that there might be more efficient approaches, but this should address your "unexpectedly found nil" error.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.