簡體   English   中英

作為后台任務運行時,Swiftui FileManager/URLSession 未寫入 documentDirectory

[英]Swiftui FileManager/URLSession not writing to documentDirectory when running as background task

希望你做得很好! 我已經構建了一個應用程序,該應用程序可以從我在我的網站上托管的 .csv 文件生成視圖。 我以前設法讓一切按預期工作,我從網站調用 csv 並將內容直接寫入變量,然后從那里處理它。 顯然這不是一個好的做法,因為當無法訪問互聯網時應用程序開始出現異常行為(盡管寫入了連接檢查)。

我現在已經構建了應用程序來調用 URL,使用 Filemanager 保存 csv,然后當應用程序刷新時,如果有互聯網連接,它將使用FileManager.default.replaceItemAt替換以前的版本,如果沒有,應用程序是從之前存儲的 .csv

當應用程序運行時,這一切都很好,但是我遇到了后台處理任務的問題。 從后台任務執行時,該應用似乎沒有使用 FileManager 寫入的權限。 在后台任務中使用它時,我還缺少一個額外的步驟嗎? 我嘗試使用FileManager.default.removeItem后跟FileManager.default.copyItem而不是 replaceItemAt 但它似乎沒有像預期的那樣產生影響。

更新 22/06 - 仍在互聯網上搜索類似的問題或示例,我想我可能在這里走錯了兔子洞。 這可能是新后台任務配置為從我的網站檢索數據的方式的問題,盡管在此方法作為后台任務工作似乎需要更多的工作之前,后台任務運行良好。

    func handleAppRefresh(task: BGProcessingTask) {
    //Schedules another refresh
    scheduleAppRefresh()
    DispatchQueue.global(qos: .background).async {
       pullData()
       print("BG Background Task fired")
    }

pullData() 將調用 loadCSV() 然后進行一些數據處理。 目前我只是在調用 loadCSV() 后直接使用打印來驗證下載等是否成功。

// Function to pass the string above into variables set in the csvevent struct
func loadCSV(from csvName: String) -> [CSVEvent] {
var csvToStruct = [CSVEvent]()

// Creates destination filepath & filename
let documentsUrl:URL =  (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?)!
let destinationFileUrl = documentsUrl.appendingPathComponent("testcsv.csv")

//Create URL to the source file to be downloaded
let fileURL = URL(string: "https://example.com/testcsv.csv")!

let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)

let request = URLRequest(url:fileURL)

let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
    if let tempLocalUrl = tempLocalUrl, error == nil {
        if let statusCode = (response as? HTTPURLResponse)?.statusCode {
            print("File downloaded Successfully. Response: \(statusCode)")
        }
        
        do {
            let _ = try FileManager.default.replaceItemAt(destinationFileUrl, withItemAt: tempLocalUrl)
        } catch (let writeError) {
            print("Error creating a file \(destinationFileUrl) : \(writeError)")
        }
    } else {
        print("Error" )
    }
}
task.resume()

let data = readCSV(inputFile: "testcsv.csv")

var rows = data.components(separatedBy: "\n")

rows.removeFirst()

// Iterates through each row and sets values
for row in rows {
    let csvColumns = row.components(separatedBy: ",")
    let csveventStruct = CSVEvent.init(raw: csvColumns)
    csvToStruct.append(csveventStruct)
}
print("LoadCSV has run and created testcsv.csv")
return csvToStruct
}

任何有關為什么這些文件沒有在后台任務中更新但在應用程序中運行良好的幫助或指示將不勝感激!

提前致謝。

編輯:添加新的 BGProcessingTask

func handleAppRefresh(task: BGProcessingTask) {
    //Schedules another refresh
    print("BG Background Task fired")
    scheduleAppRefresh()
    Task.detached {
        do {
            let events = try await loadCSV(from: "Eventtest").filter { !dateInPast(value: $0.date) }
            print(events)
            pullData(events: events)
        } catch {
            print(error)
        }
    }
}

問題不在於后台任務本身,而在於downloadTask的異步行為。 readCSV在下載數據之前執行。

在 Swift 5.5 及更高版本中, async/await提供異步行為,但代碼可以連續編寫。

func loadCSV(from csvName: String) async throws -> [CSVEvent] {
    var csvToStruct = [CSVEvent]()
    
    // Creates destination filepath & filename
    let documentsUrl:URL =  (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?)!
    let destinationFileUrl = documentsUrl.appendingPathComponent("testcsv.csv")
    
    //Create URL to the source file to be downloaded
    let fileURL = URL(string: "https://example.com/testcsv.csv")!
    
    let sessionConfig = URLSessionConfiguration.default
    let session = URLSession(configuration: sessionConfig)
    
    let request = URLRequest(url:fileURL)
    
    let (url, response) = try await session.download(for: request)
    
    if let statusCode = (response as? HTTPURLResponse)?.statusCode {
        print("File downloaded Successfully. Response: \(statusCode)")
    }
    let _ = try FileManager.default.replaceItemAt(destinationFileUrl, withItemAt: url)        
    let data = readCSV(inputFile: "testcsv.csv")
    
    var rows = data.components(separatedBy: "\n")
    
    rows.removeFirst()
    
    // Iterates through each row and sets values
    for row in rows {
        let csvColumns = row.components(separatedBy: ",")
        let csveventStruct = CSVEvent.init(raw: csvColumns)
        csvToStruct.append(csveventStruct)
    }
    print("LoadCSV has run and created testcsv.csv")
    return csvToStruct
}

要調用該函數,您必須將其包裝在替換 GCD 隊列的分離任務中

Task.detached {
    do {
        let events = try await loadCSV(csvName: "Foo")
        print("BG Background Task fired")
    } catch {
        print(error)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM