在带有 Swift 的 iOS 中使用 PDFKIT 进行 PDF 比较时应用程序崩溃

问题描述 投票:0回答:1

我是一名 React Native 开发者,正在学习 Swift。我为我的应用程序开发了一个NativeModule,它可以比较两个 PDF 并总结更改结果,然后将其发送回 React Native Bridge。以下是我正在使用的代码,如果 PDF 包含的页面少于 100 页,这些代码可以工作,但是,当页面增加时,应用程序会因内存问题而崩溃。

本机模块(PDF 管理器):

import Foundation
import PDFKit
import SwiftDiff

@objc(PDFManager)
class PDFManager: NSObject {
  
  private var currentPageIndex: Int = 0
  private var lastProcessedIndex: Int = 0
  
  @objc
  func compareAndMerge(_ pdfPath1: String, pdfPath2: String, documentName: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
    do {
      guard let firstPdfURL = URL(string: pdfPath1),
            let secondPdfURL = URL(string: pdfPath2) else {
        reject("pdfInvalidPath", "Invalid PDF path", nil)
        return
      }
      
      guard let pdf1 = PDFDocument(url: firstPdfURL),
            let pdf2 = PDFDocument(url: secondPdfURL) else {
        reject("PDFLoadError", "Failed to load PDFs", nil)
        return
      }
      
      let summary = try compareAndSummarize(doc1: pdf1, doc2: pdf2)
      let json = summarizeToJSON(summary: summary)
      resolve(json)
    } catch {
      print("Error merging PDFs:", error)
      reject("pdfMergeError", "Error merging PDFs", nil)
    }
  }
  
  @objc
  static func requiresMainQueueSetup() -> Bool {
    return true
  }
  
  private func compareAndSummarize(doc1: PDFDocument, doc2: PDFDocument) throws -> (String, Int) {
    var changesSummary = ""
    var pagesChanged = 0
    // Iterate over pages of doc1 and doc2 simultaneously
    let pageCount = min(doc1.pageCount, doc2.pageCount)
    for pageIndex in 0..<pageCount {
      autoreleasepool {
        guard let page1 = doc1.page(at: pageIndex),
              let page2 = doc2.page(at: pageIndex) else { return }
        let page1Text = page1.string ?? ""
        let page2Text = page2.string ?? ""
        changesSummary += "Page \(pageIndex + 1):\n"
        
        // Calculate differences between the text of the two pages
        let diff = diff(text1: page1Text, text2: page2Text)
        var pageChanged = false
        // Process each change in the differences
        for change in diff {
          switch change {
          case .delete(let value):
            pageChanged = true
            changesSummary += "- Deleted: \(value)\n"
          case .insert(let value):
            pageChanged = true
            changesSummary += "+ Inserted: \(value)\n"
          case .equal( _):
            break
          }
        }
        if pageChanged {
          pagesChanged += 1
        }
      }
    }
    return (changesSummary, pagesChanged)
  }

  func summarizeToJSON(summary: (String, Int)) -> String {
    let dictionary: [String: Any] = ["changes": summary.0, "pagesChanged": summary.0]
    let data = try? JSONSerialization.data(withJSONObject: dictionary, options: [.prettyPrinted])
    return String(data: data!, encoding: .utf8) ?? ""
  }

}

React 本机代码:

import React, {useState} from 'react';
import {ActivityIndicator, NativeModules, View, useWindowDimensions} from 'react-native';
import Text from '../../Components/Text';
import s from '../../assets/styles';
import {Button} from '../../Components/Buttons';
import DocumentPicker from 'react-native-document-picker';
import {useSafeAreaInsets} from 'react-native-safe-area-context';

function HomeScreen() {
  const [pdf1, setPDF1] = useState(null);
  const [pdf2, setPDF2] = useState(null);
  const [merging, setMerging] = useState(false);
  const {PDFManager} = NativeModules;
  const insets = useSafeAreaInsets();
  const {width} = useWindowDimensions();
  const buttonWidth = width / 2 - 25;

  const selectFirstPDF = async () => {
    try {
      const result = await DocumentPicker.pickSingle({
        type: DocumentPicker.types.pdf,
        copyTo: 'cachesDirectory',
      });
      if (!result?.fileCopyUri) {
        return;
      }
      setPDF1(result);
    } catch (error) {}
  };

  const selectSecondPDF = async () => {
    try {
      const result = await DocumentPicker.pickSingle({
        type: DocumentPicker.types.pdf,
        copyTo: 'cachesDirectory',
      });
      if (!result?.fileCopyUri) {
        return;
      }
      setPDF2(result);
    } catch (error) {}
  };

  const updateManuals = async () => {
    setMerging(true);
    try {
      const result = await PDFManager.compareAndMerge(
        pdf1?.fileCopyUri,
        pdf2?.fileCopyUri,
        `${pdf2?.name}_Autopilot3.pdf`,
      );
      setMerging(false);
      if (result) {
        const json = JSON.parse(result);
        console.log('json -> ', json);
      }
    } catch (error) {
      console.log('Error -> ', error);
    } finally {
      setMerging(false);
    }
  };

  return (
    <View style={[s.flex1, {paddingTop: insets.top}, s.jcac]}>
      <View style={[s.mHor10]}>
        <Text style={[s.f30, s.ls2, s.fontBlack, s.textCenter, s.as]}>
          Keep Highlights
        </Text>
        <Text style={[s.fontSemiBold, s.mVer10]}>
          Effortlessly compare your PDF manuals and keep your highlights
          updated. Files are compared locally and your data always remain
          confidential.
        </Text>
        <View style={[s.flexRow, s.aic, s.jsb, s.mVer10]}>
          <Button
            title={pdf1?.name ? pdf1?.name : 'Highlighted PDF'}
            style={[s.bgPurple, s.br30, {width: buttonWidth}, s.me10]}
            textStyle={[s.fontMedium, s.f14, s.textWhite]}
            onPress={selectFirstPDF}
          />
          <Button
            title={pdf2?.name ? pdf2?.name : 'Updated manual'}
            onPress={selectSecondPDF}
            textStyle={[s.fontMedium, s.f14, s.textWhite]}
            style={[s.br30, {width: buttonWidth}]}
          />
        </View>
        <Button
          title={'Get updated manual'}
          isDisabled={!pdf1?.fileCopyUri || !pdf2?.fileCopyUri}
          onPress={updateManuals}
        />
        {merging && <ActivityIndicator size={'large'} color={'white'}/>}
      </View>
    </View>
  );
}

export default HomeScreen;

我尝试了不同的技巧和方法,例如:autorelease

ios swift react-native pdfkit ios-pdfkit
1个回答
0
投票

没错,你应该使用Linux,而不是iOS

© www.soinside.com 2019 - 2024. All rights reserved.