快速大纲视图与两个子孩子

时间:2017-08-25 08:50:28

标签: swift macos cocoa nsoutlineview

我使用swift 4 for macOS,我有一个NSOutlineView:

enter image description here

我从核心数据中获取数据。

结构:

  • 实体人(与实体书的关系)
  • entity Book

此结果的代码:

@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) }
    }

现在我的问题: 我想创建另一个大纲视图。

My Book实体看起来像这样(属性):

  • 名称
  • creationDate

我的新概要视图应该有这样的结构:

+ Year
++ Month
+++ Bookname

但我不知道如何才能实现这种结构。 它与我的第一个大纲视图不同。

有人能帮助我吗?

=======

我想我已经创建了年份和月份的数组,没有重复。 为此,我尝试使用此函数来获取数据:

 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) }
    }

1 个答案:

答案 0 :(得分:0)

当您的基础数据结构是分层结构(即树结构)时,更易于管理多级概述。

以下是您如何创建&#34;树&#34;的示例。您的图书的节点类:

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) 
   }
}

您的数据将存储在BookNodes层次结构中,您可以从获取请求中加载这些数据 (您可以按照我的方式对其进行预先排序,或将其保留到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)
       }
     }
}

有了这个,使用BookNodes作为大纲项目很容易回应你的大纲协议:

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        
}

如果您的程序需要允许添加/更改/删除单个书籍,则BookNode类可用于反映更改的个人(例如,删除书籍子项或添加新书籍)。然后,您只需要在大纲上调用reloadData(),而无需从数据库中取回所有内容。