关于在演示中以MVC模式呈现Apple PDFKit框架的疑问
Great question! Let's clear this up: PDFKit is fully compatible with MVC, and you don't need to create a dedicated controller for every PDFKit component like PDFView or PDFDocument. Here's how to map PDFKit's parts to MVC roles, and why you don't need extra controllers:
1. PDFKit's Components Already Align with MVC Roles
Apple designed PDFKit to fit naturally into iOS's MVC pattern:
PDFView= View Layer: It handles rendering PDF content, responding to user interactions (zooming, panning, page turns), and managing on-screen presentation. This is exactly what a View should do—focus on display and direct user input handling.PDFDocument= Model Layer: It encapsulates the PDF's data, structure (pages, bookmarks, annotations), and core operations (loading from a URL/file, saving changes). This is the Model's job: managing data and business logic related to the document itself.
2. You Don't Need PDFViewController or PDFDocumentController
Instead of creating a controller for each PDFKit class, you'll use a standard UIViewController (e.g., PDFViewerViewController) as your MVC Controller layer. Its job is to:
- Coordinate the
PDFView(View) andPDFDocument(Model) - Handle custom business logic (like adding annotations, exporting the PDF, or responding to page changes)
- Bridge user actions (e.g., a "Add Bookmark" button) to Model/View updates
A PDFDocumentController is unnecessary because PDFDocument already acts as your Model. The ViewController will hold a reference to it, and interact with it to fetch or modify document data.
3. What About PDFView's "Hybrid" Behavior?
You mentioned that PDFView has properties that blur the line between View and other layers—and that's intentional! Apple built basic interaction logic (like zooming) directly into PDFView to save developers time. This doesn't break MVC:
- View layers can handle UI-specific interactions (e.g., pinch-to-zoom) that are directly tied to display.
- Your ViewController only needs to handle higher-level logic (e.g., disabling zoom for certain documents, updating a navigation bar title when the page changes).
Example: A Simple MVC-Based PDF Viewer
Here's a quick snippet to illustrate how this fits together:
class PDFViewerViewController: UIViewController { // View Layer: PDFView private let pdfView = PDFView() // Model Layer: PDFDocument private var pdfDocument: PDFDocument? override func viewDidLoad() { super.viewDidLoad() setupPDFView() loadSamplePDF() setupNavigationBar() } private func setupPDFView() { // Configure view layout and default interactions pdfView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(pdfView) NSLayoutConstraint.activate([ pdfView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), pdfView.leadingAnchor.constraint(equalTo: view.leadingAnchor), pdfView.trailingAnchor.constraint(equalTo: view.trailingAnchor), pdfView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) pdfView.autoScales = true pdfView.displayMode = .singlePageContinuous } private func loadSamplePDF() { // Load Model (PDFDocument) and connect to View guard let pdfURL = Bundle.main.url(forResource: "sample", withExtension: "pdf") else { showErrorAlert(message: "Failed to load PDF") return } pdfDocument = PDFDocument(url: pdfURL) pdfView.document = pdfDocument } private func setupNavigationBar() { // Controller handles business-level user actions navigationItem.rightBarButtonItem = UIBarButtonItem( title: "Add Bookmark", style: .plain, target: self, action: #selector(addBookmarkTapped) ) } @objc private func addBookmarkTapped() { // Controller coordinates Model and View updates guard let currentPage = pdfView.currentPage else { return } pdfDocument?.insertBookmark(at: currentPage.index, withTitle: "Page \(currentPage.index + 1)") showSuccessAlert(message: "Bookmark added!") } }
Final Takeaway
PDFKit's design complements MVC perfectly. You don't need to force artificial controller classes for each PDFKit component—just use a standard UIViewController to mediate between the PDFView (View) and PDFDocument (Model), and keep your logic focused on clear separation of concerns.
内容的提问来源于stack exchange,提问作者Gianni

