2017-08-25 2 views
1

i travailler avec rapide 4 pour Mac OS et j'ai un NSOutlineView:vue aperçu rapide avec deux enfants sous

enter image description here

i obtenir les données à partir des données de base.

Structure

:

  • entité Personne (relation à l'entité Livre)
  • entité livre

Mon code pour ce résultat:

@IBOutlet weak var myOutlineView: NSOutlineView! 

    let context = (NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 
    var people = [Person]() 

    override func viewWillAppear() { 
     requestPeople() 
    } 

    func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { 
     let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: self) as? CustomCell 
     if let person = item as? Person { 
      // Show Person 
     } else if let book = item as? Book { 
      // Show Books 
     } 
     return view 
    } 


    func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { 
     if let person = item as? Person { 
      return person.books.count 
     } 
     return people.count 
    } 


    func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { 
     if let person = item as? Person { 
      return person.books[index] 
     } 
     return people[index] 
    } 


    func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { 
     if let person = item as? Person { 
      return person.books.count > 0 
     } 
     return false 
    } 



    func requestPeople() { 
     let request = NSFetchRequest<Person>(entityName: "Person") 
     do { 
      people = try context.fetch(request) 
      myOutlineView.reloadData() 
     } catch { print(error) } 
    } 

maintenant mon problème: i voudrais créer une autre vue de contour.

Mon entité du livre ressemble à ceci (attributs):

  • Nom
  • creationDate

Mon nouveau outlineview devrait obtenir cette structure:

+ Year 
++ Month 
+++ Bookname 

, mais je ne sais pas comment puis-je réaliser cette structure. Il est différent de ma première vue de plan.

Quelqu'un peut-il m'aider?

=======

je suppose que je dois créer des tableaux pour l'année et le mois sans doublons. Pour cela, je essayer une cette fonction pour obtenir les données:

var year = [String]() 
var month = [String]() 
var books = [Book]() 

    func requestBooks() { 
     let request = NSFetchRequest<Book>(entityName: "Book") 
     do { 
      books = try context.fetch(request) 

      for x in 0 ...< books.count { 

       if !year.contains("\(Calendar.current.component(.year, from: books[x].creationDate))") { 
        year.append("\(Calendar.current.component(.year, from: books[x].creationDate))") 
       } 

       if !month.contains("\(Calendar.current.component(.month, from: books[x].creationDate))") { 
        month.append("\(Calendar.current.component(.month, from: books[x].creationDate))") 
       } 

      } 

      myOutlineView.reloadData() 
     } catch { print(error) } 
    } 

Répondre

0

Un aperçu multi-niveaux est plus facile à gérer lorsque votre structure de données sous-jacente est hiérarchique (à savoir une structure arborescente).

Voici un exemple de la façon dont vous pouvez créer une classe de noeud « Tree » pour vos livres:

class BookNode 
{ 
    // levels and relationships, from parent to children 
    enum Level { case Top, Year, Month, Book }  
    let subLevels:[Level:Level] = [ .Top:.Year, .Year:.Month, .Month:.Book ]  

    var label = ""    // description and unique "key" 
    var level = Level.Top   
    var children : [BookNode] = []  
    var book  : Book! = nil  // .Book level will store the actual Book 

    // add book to hierarchy, auto-create intermediate levels   
    func add(_ book:Book) 
    { 
     var subLabel = "" 
     switch level 
     { 
     case .Top : subLabel = String(Calendar.current.component(.year, from:book.creationDate)) 
     case .Year : subLabel = String(Calendar.current.component(.month, from:book.creationDate)) 
     case .Month : subLabel = book.name 
     case .Book : self.book = book // last level stores the book 
         return    // and has no children 
     }      
     // Add branch (.Year, .Month) or leaf (.Book) node as needed 
     var subNode:BookNode! = children.first{$0.label == subLabel} 
     if subNode == nil 
     { 
     subNode  = BookNode() 
     subNode.level = subLevels[level]! 
     subNode.label = subLabel 
     children.append(subNode) 
     } 
     // keep adding recursively down to .Book level   
     subNode.add(book) 
    } 
} 

Vos données seront stockées dans une hiérarchie de BookNodes que vous pouvez charger de votre demande d'extraction (vous peut pré-tri, comme je l'ai fait, ou laisser cela à la classe Booknode)

var topNode = BookNode() 

func requestBooks() 
{ 
    let request = NSFetchRequest<Book>(entityName: "Book") 
    do { 
     let books = try context.fetch(request) 

     topNode = BookNode() 
     for book in books.sorted(by:{$0.creationDate < $1.creationDate}) 
     { 
      topNode.add(book) 
     } 
    } 
} 

Avec cela, il sera facile de répondre à vos protocoles de contour en utilisant les BookNodes que les éléments de contour:

func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? 
{ 
    let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: self) as? CustomCell 

    let node = (item as? BookNode) ?? topNode 
    switch node.level 
    { 
    case .Year : // show year  : node.label 
    case .Month : // show month  : node.label 
    case .Book : // show book name : node.label and/or node.book 
    default  : break 
    } 

    return view 
} 

func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int 
{   
    let node = (item as? BookNode) ?? topNode 
    return node.children.count   
} 


func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any 
{ 
    let node = (item as? BookNode) ?? topNode 
    return node.children[index]   
} 


func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool 
{ 
    let node = (item as? BookNode) ?? topNode 
    return node.children.count > 0   
} 

Si vous programmez doit permettre d'ajouter/modifier/supprimer des livres individuels, la classe BookNode peut être utilisée pour refléter la personne modifiée (par ex. retirer un livre enfant ou en ajouter un nouveau). Vous n'aurez ensuite qu'à appeler reloadData() sur le plan sans avoir à tout récupérer depuis la base de données.

+0

merci beaucoup :) – Ghost108