如何使用递归遍历大纲中的所有孩子?
Posted
技术标签:
【中文标题】如何使用递归遍历大纲中的所有孩子?【英文标题】:How to traverse all children in outline using recursion? 【发布时间】:2019-07-10 14:12:44 【问题描述】:我想通过递归重写代码,它可以不受限制地遍历大纲中的所有子级。
我当前的代码最多可以遍历 3 个级别(并且我知道我可以添加更多循环并增加遍历的最大级别数),但我认为可以更有效地重写。我想知道重写 traverseOutline (outline: PDFOutline?) 方法更好。
import UIKit
import PDFKit
protocol OutlineDelegate: class
func goTo(page: PDFPage)
class OutlineViewController
@IBOutlet weak var tableView: UITableView!
weak var delegate: OutlineDelegate?
var outline: PDFOutline?
var bookmarks = [Bookmark]()
override func viewDidLoad()
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
override func viewDidAppear(_ animated: Bool)
traverseOutline(outline: outline)
tableView.reloadData()
func traverseOutline (outline: PDFOutline?)
// 1st level
guard let outline = outline else return
for i in 0...outlineCycleItems(outline)
if let bookmark = Bookmark(outline: outline, index: i)
bookmarks.append(bookmark)
let subOutline = outline.child(at: i)
// 2nd level
for j in 0...outlineCycleItems(subOutline!)
if let bookmark = Bookmark(outline: subOutline, index: j)
bookmark.name = "- " + bookmark.name!
bookmarks.append(bookmark)
let subSubOutline = subOutline?.child(at: j)
// 3rd level
for k in 0...outlineCycleItems(subSubOutline!)
if let bookmark = Bookmark(outline: subSubOutline, index: k)
bookmark.name = "-- " + bookmark.name!
bookmarks.append(bookmark)
func outlineCycleItems(_ outline: PDFOutline) -> Int
let amount = outline.numberOfChildren
if amount == 0
return amount
else
return amount - 1
extension OutlineViewController: UITableViewDelegate, UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return bookmarks.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "ChapterCell", for: indexPath) as! ItemOutlineCell
cell.configureCell(name: bookmarks[indexPath.row].name!)
return cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
delegate?.goTo(page: bookmarks[indexPath.row].link!)
class ItemOutlineCell: UITableViewCell
@IBOutlet weak var chapterName: UILabel!
func configureCell (name: String)
chapterName.text = name
class Bookmark
var link: PDFPage?
var name: String?
init(link: PDFPage, name: String)
self.link = link
self.name = name
init?(outline: PDFOutline?, index: Int)
guard let child = outline?.child(at: index) else
return nil
link = child.destination?.page
name = child.label
感谢@Erik 的主要思想,我用一个函数重写了:
override func viewDidAppear(_ animated: Bool)
if let outline = outline
traverseOutline(outline: outline, currentLevel: 0)
tableView.reloadData()
func traverseOutline (outline: PDFOutline, currentLevel: Int)
for i in 0...outlineCycleItems(outline)
if let bookmark = Bookmark(outline: outline, index: i)
let dashes = String(repeating: "-", count: currentLevel)
bookmark.name = dashes + bookmark.name!
bookmarks.append(bookmark)
let subOutline = outline.child(at: i)
traverseOutline(outline: subOutline!, currentLevel: currentLevel + 1)
【问题讨论】:
【参考方案1】:您可以通过添加一个不断调用自身的额外函数来使您的代码真正递归。我将第一层分开,因为它与其他层有些不同。在你原来的功能:
func traverseOutline (outline: PDFOutline?)
guard let outline = outline else return
for i in 0...outlineCycleItems(outline)
if let bookmark = Bookmark(outline: outline, index: i)
bookmarks.append(bookmark)
let subOutline = outline.child(at: i)
recursiveTraverse(outline: subOutline)
然后定义一个名为recursiveTraverse
的新函数:
func recursiveTraverse(outline:PDFOutline)
for j in 0...outlineCycleItems(subOutline!)
if let bookmark = Bookmark(outline: outline, index: j)
bookmark.name = "- " + bookmark.name!
bookmarks.append(bookmark)
recursiveTraverse(outline: outline.child(at: j))
这将通过在 for 循环中为每个单独的大纲调用自身来继续降低一个级别。只有当它不能从路径端点上的任何轮廓中创建书签时(当循环中所有轮廓的 if 语句为 false 时),它才会在某个路径上停止。
【讨论】:
以上是关于如何使用递归遍历大纲中的所有孩子?的主要内容,如果未能解决你的问题,请参考以下文章