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?
Czy mogę zapytać, dlaczego oznakowałeś to 'css'?Jak dokładnie może pomóc ekspert CSS w tym pytaniu? –
@AndreiGheorghiu Masz rację; to był błąd. Naprawiono –
spróbuj zastąpić "guard let str = markdownString else {return}" Jest to jedyna część twojego kodu, która wydaje mi się wątpliwa. – Mozahler