2017-12-12 160 views
9

Pytałem już o to wcześniej, ale musiałem przeformułować wszystko, aby stało się bardziej zrozumiałe.Menedżer plików czasami nie znajduje podfolderów w katalogu dokumentów

W moim projekcie, Stworzyłem podfolder wewnątrz documents directory zwanego HTML z następującego kodu:

fileprivate func createFolderOnDocumentsDirectoryIfNotExists() { 
    let folderName = "HTML" 
    let fileManager = FileManager.default 
    if let tDocumentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first { 
     let filePath = tDocumentDirectory.appendingPathComponent("\(folderName)") 
     if !fileManager.fileExists(atPath: filePath.path) { 
      do { 
       try fileManager.createDirectory(atPath: filePath.path, withIntermediateDirectories: true, attributes: nil) 
      } catch { 
       print("Couldn't create document directory") 
      } 
     } 
     print("Document directory is \(filePath)") 
    } 
} 

Instrukcja print drukuje następujące:

Document directory is file:///var/mobile/Containers/Data/Application/103869C9-9D46-4595-A370-A93BCD75D495/Documents/HTML

w mojej aplikacji Bundle mam plik .css do użycia w ciągu HTML do zaprezentowania w postaci WKWebView.

Jako plik .css musi być w tym samym folderze co HTML baseURL, kopiować że .css plik z Bundle do katalogu utworzonego z powyższej funkcji, z następującym kodem:

fileprivate func copyCSSFileToHTMLFolder() { 
    guard let cssURL = Bundle.main.url(forResource: "swiss", withExtension: "css") else { return } 
    let fileManager = FileManager.default 
    if let tDocumentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first { 
     let fp = tDocumentDirectory.appendingPathComponent("HTML") 
     if fileManager.fileExists(atPath: fp.path) { 
      let fp2 = fp.appendingPathComponent(cssURL.lastPathComponent) 
      do { 
       try fileManager.copyItem(atPath: cssURL.path, toPath: fp2.path) 
      } catch { 
       print("\nFailed to copy css to HTML folder with error:", error) 
      } 
     } 
    } 
} 

wiem Mogę użyć obu w aplikacji: Bundle, ustawiając HTML baseURL na main.Bundle, ale ponieważ muszę wyświetlać lokalne obrazy wewnątrz obrazów HTML, a nie sieciowych, musiałem przenieść je do podfolderu, aby móc później skopiować pożądane obrazy do tego podfolderu od main.Bundle jest tylko do odczytu i nie jest zapisywalny (nie możemy zapisać tam obrazów).

Teraz mam ViewController, który zostanie przepchnięty przez UINavigationController; wewnątrz tego pchnął ViewController Mam WKWebView, który przedstawi HTML.

Mam też var markdownString: String? {} właściwość, że raz instancję przekonwertować go do HTML ciąg stosując następującą funkcję:

func getHTML(str: String) -> String { 
    /* 
     the cssImport here points to the previously copied css file as they are on the same folder 
    */ 

    let cssImport = "<head><link rel=\"stylesheet\" type=\"text/css\" href=\"swiss.css\"></head>" 
    let htmlString = try? Down(markdownString: str).toHTML()  
    return cssImport + htmlString! 
} 

My WKWebView jest zadeklarowana z następującego kodu:

private lazy var webView: WKWebView = { 
    // script to fit the content with the screen 
    var scriptContent = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);" 

    let wkuscript = WKUserScript(source: scriptContent, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true) 
    let wkucontroller = WKUserContentController() 
    wkucontroller.addUserScript(wkuscript) 

    let wkwebconfig = WKWebViewConfiguration() 
    wkwebconfig.userContentController = wkucontroller 

    let wv = WKWebView(frame: .zero, configuration: wkwebconfig) 
    wv.frame.size.height = 1 
    return wv 
}() 

Ilekroć mój markdown String jest ustawiony, przekonwertowałem go na ciąg znaków HTML, a następnie utworzono instancję HTML baseURL, a następnie załadowałem ją do mojego webView z następcą g code:

public var markdownString: String? { 
    didSet { 
     guard let kPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("HTML", isDirectory: true) else { return } 

     guard let str = markdownString else { return } 
     let html = getHTML(str: str) 

     print("base url:", kPath) 

     let fm = FileManager.default 

     do { 
      let items = try fm.contentsOfDirectory(atPath: kPath.path) 
      print("items:", items) 
     } catch { 
      print("Error:", error) 
     } 
     webView.loadHTMLString(html, baseURL: kPath) 
    } 
} 

Oto, gdzie zaczyna się mój problem.

Plik swiss.css znajduje się w następującym katalogu:

file:///var/mobile/Containers/Data/Application/103869C9-9D46-4595-A370-A93BCD75D495/Documents/HTML/

W HTML baseURL punkty do następującej ścieżki:

file:///var/mobile/Containers/Data/Application/103869C9-9D46-4595-A370-A93BCD75D495/Documents/HTML/

Jak widać, są one zarówno wskazując na tej samej ścieżce.

Czasami mój HTML znajdzie plik swiss.css, gdyż drukuje items w bloku do{}catch{}, ale innym razem nie znajdzie folderu, try fm.contentsOfDirectory(atPath: kPath.path) pożary błąd przechwycony w bloku catch{} drukowania następujący:

Error: Error Domain=NSCocoaErrorDomain Code=260 "The folder “HTML” doesn’t exist." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/103869C9-9D46-4595-A370-A93BCD75D495/Documents/HTML, NSUserStringVariant=( Folder ), NSUnderlyingError=0x1c044e5e0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

To dzieje się w symulatorze i na prawdziwym urządzeniu.

Co powoduje ten problem? Dlaczego czasami znajduje folder, a czasem nie, nawet bez ponownego uruchamiania aplikacji, co może zresetować ścieżkę documents directory, nawet jeśli nie wymuszam ścieżki, ale zamiast tego ją ściągam, jak widać powyżej .

Nie rozumiem tego zachowania.

UPDATE

więc myślałem, że czytanie ciąg html bezpośrednio może być przyczyną pewnych problemów więc zmieniłem deklarację markdown: String?.

W nim zapisuję przekonwertowany ciąg znaków (nie ciąg html) do pliku w tej samej ścieżce o nazwie index.html.

Teraz myślę, że stało się inaczej - kiedy wypycham ten widok po raz pierwszy, znajduje on teraz mój plik swiss.css, a plik html wykrywa go i używa go zgodnie z oczekiwaniami; jak na razie dobrze.

ale kiedy odrzucić ten kontroler widoku, poping do kontrolera widoku rodzica (naciskając przycisk Wstecz), a następnie starają się wcisnąć go ponownie, ten sam błąd (opisane wcześniej) podpowiada:

Failed to write html to file with error: Error Domain=NSCocoaErrorDomain Code=4 "The folder “index.html” doesn’t exist." UserInfo={NSURL=file:///var/mobile/Containers/Data/Application/C0639153-6BA7-40E7-82CF-25BA4CB4A943/Documents/HTML/index.html, NSUserStringVariant=Folder, NSUnderlyingError=0x1c045d850 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

Zauważ, że niektóre ścieżki tutaj są inne niż poprzednie, ponieważ jest to inne uruchomienie i się zmienia, ale to nie jest problem, ponieważ nigdy nie przechowuję ścieżki i nie piszę jej, zawsze pobieraję adresy URL z domyślnym menedżerem plików pobierz,

Zaktualizowany markdown deklaracja jest następująca:

public var markdownString: String? { 
    didSet { 
     guard let kPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("HTML", isDirectory: true) else { return } 

     guard let str = markdownString else { return } 
     let html = getHTML(str: str) 

     do { 
      let writePath = kPath.appendingPathComponent("index.html") 
      try html.write(to: writePath, atomically: true, encoding: .utf8) 
      webView.loadFileURL(writePath, allowingReadAccessTo: kPath) 
     } catch { 
      print("Failed to write html to file with error:", error) 
      return 
     } 

     let fm = FileManager.default 
     do { 
      let items = try fm.contentsOfDirectory(atPath: kPath.path) 
      print("items:", items) 
     } catch { 
      print("Error:", error) 
     } 
    } 
} 

Jakoś to zdezorientowało mnie jeszcze bardziej.

Dlaczego działa na pierwszej prezentacji, a następnie nie?

+0

Czy mogę zapytać, dlaczego oznakowałeś to 'css'?Jak dokładnie może pomóc ekspert CSS w tym pytaniu? –

+0

@AndreiGheorghiu Masz rację; to był błąd. Naprawiono –

+0

spróbuj zastąpić "guard let str = markdownString else {return}" Jest to jedyna część twojego kodu, która wydaje mi się wątpliwa. – Mozahler

Odpowiedz

0

W sekcji UPDATE wspomnieć następujący błąd:
Failed to write html to file with error: Error Domain=NSCocoaErrorDomain Code=4 "The folder “index.html” doesn’t exist."
O ile zrozumiałem swój problem, index.html nie powinien być folder ale plik.

nie mam pojęcia, dlaczego to traktuje jako index.html folderu, ale może zastępując
let writePath = kPath.appendingPathComponent("index.html")
z
let writePath = kPath.appendingPathComponent("index.html", isDirectory: false)
pomaga lub przynajmniej prowadzi do bardziej konkretnym komunikatem o błędzie.

+1

To jest ta dziwna część; nawet zastępując kod, rejestruje błąd. Nie wiem, dlaczego to się dzieje. Myślę, że zrobię krok naprzód i przerobię tę część kodu i zastosuję inne podejście, a następnie osobno przejdę głębiej, aby to rozgryźć. –