如何使用递归遍历轮廓中的所有子级?

时间:2019-07-10 14:12:44

标签: ios swift pdfview

我想通过递归重写代码,这样可以无限制地遍历大纲中的所有子代。

我当前的代码最多可以遍历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 个答案:

答案 0 :(得分:2)

您可以通过添加一个不断调用自身的额外函数来使代码真正地递归。我将第一级保持独立,因为它与其他级别略有不同。在您的原始功能中:

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时),它才会在某个路径上停止。