2016-06-28 3 views
0

У меня есть небольшая проблема в понимании двумерных словарей. Моя функция должна возвращать словарь для UITableView с разделами. 1 тип шаблона может иметь несколько строк шаблона. Поэтому, когда в fetchedData есть 2 или более текста с похожими типами, они должны быть в массиве [String] с 1 ключом - String. Код, приведенный ниже, является абсолютно правильным с точки зрения соответствия. Что касается меня, то что-то не так, но хорошие автоматические доработки заставляют меня думать, что все в порядке. Очевидно, что возвращает пустой словарь [:]Swift 1D Dictionary to 2D

func fetchTemplates() -> Dictionary<String, [String]> { 
    var templates: Dictionary<String, [String]> = [:] 
    let fetchRequest: NSFetchRequest<Template> = Template.fetchRequest() 
    fetchRequest.sortDescriptors = [SortDescriptor.init(key: "templateType", ascending: true)] 
    let fetchedData = try! context.fetch(fetchRequest) 
    if (!fetchedData.isEmpty) { 
     for templateItem in fetchedData { 
      templates[templateItem.templateType!]?.append(templateItem.templateText!) 
     } 
     return templates 
    } 
    else { 
     return templates 
    } 
} 

P.S. fetchedData возвращается:

<Template: 0x003281h4> (entity: Template; id: 0x003281h4 <x-coredata:///Template/> ; data: { 
    templateText = "Example"; 
    templateType = "First"; 
}) 
+0

Сторона примечания: нет необходимости делать эту проверку для '! FetchedData.isEmpty'. Если он пуст, цикл for будет повторяться 0 раз, то есть он просто будет пропущен. – Alexander

ответ

1

вопрос лежит на этой линии:

templates[templateItem.templateType!]?.append(templateItem.templateText!) 

templates был инициализирован с помощью этой строки: var templates: Dictionary<String, [String]> = [:]. На данный момент templates - это пустой словарь.

Давайте разберем эту линию вниз, шаги, которые происходят в хронологическом порядке:

  1. templateItem.templateType доступ, и заставить развернутый. Авария произойдет, если это nil.
  2. templateItem.templateType! используется как ключ в словаре templates. Это всегда будет возвращаться nil. Словарь пуст, поэтому он не имеет значений для любых ключей, включая этот.
  3. ?.append() называется, при условии, что он не вызывается на nil. Если он вызван на nil, ничего не произойдет.

3 является причиной вашей проблемы. Вы должны инициализировать новый массив, если один не существует для ключа еще:

func fetchTemplates() -> Dictionary<String, [String]> { 
    var templates: Dictionary<String, [String]> = [:] 
    let fetchRequest: NSFetchRequest<Template> = Template.fetchRequest() 
    fetchRequest.sortDescriptors = [SortDescriptor.init(key: "templateType", ascending: true)] 
    let fetchedData = try! context.fetch(fetchRequest) 
    if (!fetchedData.isEmpty) { //see note 2 
     for templateItem in fetchedData { 
      let type = templateItem.templateType! 
      var array = templates[type] ?? [] //see note 1 
      array!.append(templateItem.templateText!) 
      templates[type] = array 
     } 
     return templates 
    } 
    else { 
     return templates 
    } 
} 

Эта функция может быть упрощена:

func fetchTemplates() -> [String : [String]] { 
    let fetchRequest = Template.fetchRequest() 
    fetchRequest.sortDescriptors = [SortDescriptor(key: "templateType", ascending: true)] 

    let fetchedData = try! context.fetch(fetchRequest) 

    var templates = [String, [String]]() 
    for templateItem in fetchedData { 
     let type = templateItem.templateType! 
     templates[type] = (templates[text] ?? []) + [templateItem.templateText!] 
    } 
    return templates 
} 

и уменьшают можно использовать вместо:

func fetchTemplates() -> [String : [String]] { //see note 3 
    let fetchRequest = Template.fetchRequest() //see note 4 
    fetchRequest.sortDescriptors = [SortDescriptor(key: "templateType", ascending: true)] //see note 5 

    let fetchedData = try! context.fetch(fetchRequest) 

    return fetchedData.reduce([String, [String]]()){templates, templateItem in 
     (templates[templateItem.tempalteText!] ?? []) + [templateItem.templateText!] 
    } //see note 6 
} 

Примечания
  1. если template[text] не nil, он присваивается array. В противном случае для массива присваивается новый массив ([]).
  2. эта проверка не нужна
  3. Dictionary<String, [String]> можно записать как только [String : [String]]
  4. Нет необходимости явного типа signiture
  5. X.init() может быть записана как только X()
  6. Проверка пустоты ненужна, и весь for петля может быть изменена на вызов reduce.
0

Вопрос является:

templates[templateItem.templateType!] всегда nil, потому что словарь пуст.

Поэтому ничего нельзя добавить.