Я хочу переписать код с помощью рекурсии, которая может обойти всех дочерних элементов в общих чертах без ограничений.
Мой текущий код может проходить до 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)
}
}
}