Попытка заполнить массив массивов NSManagedObjects - PullRequest
0 голосов
/ 12 января 2019

Я получаю данные из модели CoreData и отлично работает. Я получаю массив NSManagedObjects (NSMO), каждый из которых является документом с некоторыми другими атрибутами.

Одним из атрибутов NSMO является дата, и для заполнения TableView я использую «год» с даты в качестве разделов в TableView.

Чтобы получить NSMO за каждый год (раздел), я должен отфильтровать массив. Но если я сделаю фильтрацию в cellForRowAtIndexPath, приложение будет очень неэффективным. Так что я подумал об одном решении:

Сразу после извлечения всех документов в одном массиве я могу отфильтровать массив для каждого года и заполнить массив массивов NSMO.

var documentArray = [Document]()  // To fetch all the documents.
var documentArrayPerSection = [[Document]]()  // To filter per section.

Где «Документ» - NSMO.

И, например, для первого раздела у нас есть массив:

documentArrayPerSection[0]

и т. Д.

var documentArray = [Document]()
var documentArrayPerSection = [[Document]]()
let yearSections = ["2005","2006","2007","2008","2009","2010","2011","2012","2013"]

func fetchDocuments() {

    // We make the request to the context to get the documents we want.

    do {

        documentArray = try context.fetchMOs(requestedEntity!, sortBy: requestedSortBy, predicate: requestedPredicate)

        // Arrange the documentArray per year using the variable documentArrayPerSection.
        for index in 0...yearSections.count - 1 {

            documentArrayPerSection[index] = documentArray.filter({ (document) -> Bool in
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy"
                let yearSection = formatter.string(from: document.date!)
                return yearSection == self.yearSections[index]
            })

        }

    } catch {

        print("Error fetching data from context \(error)")

    }

}

И приложение всегда вылетает, говоря "индекс вне диапазона". И я не знаю, как это исправить, потому что переменная должна быть глобальной, чтобы получить доступ из "cellForRowAtIndexPath" и должна быть пустой для инициализации.

Ответы [ 2 ]

0 голосов
/ 13 января 2019

Swift 4+ предоставляет очень простой и удобный способ группировки массива: Dictionary(grouping:by:)

let calendar = Calendar.current
let groupedDictionary = Dictionary(grouping: documentArray, by: {calendar.component(.year, from: $0.date)})

возвращает словарь с годами в качестве ключей (как Int) и массивом Document в качестве значения соответственно.

Если вы хотите, чтобы строковые ключи изменили закрытие на

{ String(calendar.component(.year, from: $0.date)) }

Тогда вы можете получить массив разделов с помощью

let yearSections = groupedDictionary.keys.sorted()

и получите соответствующие массивы с помощью

let yearArrays = yearSections.map{ groupedDictionary[$0]! }

A Dateformatter не требуется

0 голосов
/ 13 января 2019

Я думаю, вы можете выбрать другой способ создания своих разделов. Вот быстрый пример для вас. В этом случае я создаю тестовую структуру Document, структуру Section и SectionManager, которые могут помочь вам вернуть раздел для заполнения tableView.

Структура документа Это будет в значительной степени объект Document, который у вас уже есть.

struct Document {
    let date : String
    let foo : String
    init(date: String!, foo: String!) {
        self.date = date
        self.foo = foo
    }
}

Затем вы можете создать Структуру раздела :

struct Section {

    var title: String
    var items : [Document]

    init(title: String, documents : [Document]) {
        self.title = title
        items = documents
    }
}

Тогда ваш sectionManager :

class SectionsManager {
    // Singleton
    static let shared = SectionsManager()
    private init() {}
    func getSectionsFromDictionary(dictionary: [String: [Document]]) -> [Section] {
        var sectionsArray = [Section]()
        for (title, objects) in dictionary.sorted(by: {$0.0 > $1.0}) {
            let section = Section(title: title, documents: objects)
            sectionsArray.append(section)
        }
        return sectionsArray
    }
}

Заметьте, я использую там синглтон.

Наконец, вы можете просто использовать этот код для создания своих разделов в viewController. Здесь я использую collectionView, потому что они мне нравятся больше, но вместо этого вы можете использовать tableView.

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    lazy var collectionView : UICollectionView = {
        let layout = UICollectionViewLayout()
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.dataSource = self
        collectionView.delegate = self
        return collectionView
    }()

    let documents : [Document] = [Document(date: "2005", foo: "bar"), Document(date: "2005", foo: "bar"), Document(date: "2004", foo: "bar")]
    var documentsBySection : [String : [Document]] = ["2005": [], "2004" : []]
    var sections: [Section] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(collectionView)

        for document in self.documents {
            let date = document.date
            self.documentsBySection[date]?.append(document)
        }
        sections = SectionsManager.shared.getSectionsFromDictionary(dictionary: documentsBySection)
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return sections.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        print(sections[section].items.count)
        return sections[section].items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        return UICollectionViewCell()
    }
}

Затем вы можете повторно использовать менеджер в своем приложении для заполнения любой другой коллекции. Если вы скопируете и вставите весь код, вы можете проверить, как он работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...