如何在 SwiftUI 中使用 .fileimporter 保存音频文件并检索文件并在 SwiftUI 列表中显示它们的文件名?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中使用 .fileimporter 保存音频文件并检索文件并在 SwiftUI 列表中显示它们的文件名?【英文标题】:Onecbowcibecbow Fhe Fhhecohwfhfwhqfohoh f 【发布时间】:2021-12-28 15:10:20 【问题描述】:

我非常努力地在这里找到了类似的问题,但没有找到。那么,如何保存已使用 .fileimporter 导入的音频文件并将其保存在文档目录的文件夹中。另外如何检索它们并在 SwiftUI 的列表中显示它们的文件名?我希望我的问题足够清楚。这是我尝试过的代码。

import SwiftUI

extension FileManager 
    static func getDocumentsDirectory() -> URL 
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    
    
    static let customFolderURL = FileManager.getDocumentsDirectory().appendingPathComponent("Music Files")


class Manager: ObservableObject 
    @Published var musicFiles: [URL] = []
    
    init() 
        do 
            try FileManager.default.createDirectory(at: FileManager.customFolderURL, withIntermediateDirectories: true, attributes: nil)
         catch 
            print("Failed to create folder")
        
    
    
    func save(url: URL) 
        if url.startAccessingSecurityScopedResource() 
            do 
                let musicFile = try Data(contentsOf: url)
                try musicFile.write(to: FileManager.customFolderURL, options: .atomic)
                print("Success")
                print(FileManager.customFolderURL)
             catch 
                print("Failed to save the music file")
            
            url.stopAccessingSecurityScopedResource()
         else 
            print("Permission failed!")
        
    
    
    func getMusicFiles() 
        do 
            let musicFiles = try FileManager.default.contentsOfDirectory(atPath: FileManager.customFolderURL.path)
            print(musicFiles)
         catch 
            print("Failed to retrieve items.")
        
    


struct MainView: View 
    @State private var isFileImporterShown = false
    @State private var isMusicPlayerShown = false
    
    @EnvironmentObject var manager: Manager
    
    var body: some View 
        TabView 
            VStack 
                Button("Import Song") 
                    isFileImporterShown.toggle()
                
                .padding()
                .fileImporter(isPresented: $isFileImporterShown, allowedContentTypes: [.audio], allowsMultipleSelection: true)  result in
                    do 
                        let url = try result.get().first!
                        if url.startAccessingSecurityScopedResource() 
                            manager.save(url: url)
                        
                     catch 
                        
                    
                
                
                Button("Show Player") 
                    isMusicPlayerShown.toggle()
                
                .padding()
                .sheet(isPresented: $isMusicPlayerShown) 
                    MusicPlayerView()
                
            
            .tabItem 
                Image(systemName: "externaldrive")
                Text("Load")
            
            
            AllSongsListView()
                .tabItem 
                    Image(systemName: "music.note.list")
                    Text("Songs")
                
        
    


struct AllSongsListView: View 
    @EnvironmentObject var manager: Manager
    var body: some View 
        NavigationView 
            List 
                
            
            .navigationTitle("Your Songs")
            .onAppear 
                manager.getMusicFiles()
            
        
    

【问题讨论】:

【参考方案1】:

保存的问题是您试图将文件保存为目录。

try musicFile.write(to: FileManager.customFolderURL, options: .atomic)

所以to 参数是文件夹路径而不是文件路径。

你需要像这样改变它:

let savePath = FileManager.customFolderURL.appendingPathComponent(url.lastPathComponent)
                
try musicFile.write(to: savePath, options: .atomic)

为了显示导入文件的列表,您可以执行以下操作:

List 
        ForEach(manager.musicFiles, id: \.self)  file in
            Text(file.lastPathComponent)
        

这是完整的例子:

import SwiftUI

extension FileManager 
    static func getDocumentsDirectory() -> URL 
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    
    
    static let customFolderURL = FileManager.getDocumentsDirectory().appendingPathComponent("Music Files")


class Manager: ObservableObject 
    @Published var musicFiles: [URL] = []
    
    static var shared = Manager()
    
    init() 
        do 
            try FileManager.default.createDirectory(at: FileManager.customFolderURL, withIntermediateDirectories: true, attributes: nil)
         catch 
            print("Failed to create folder:")
            print(error)
        
    
    
    func save(url: URL) 
        if url.startAccessingSecurityScopedResource() 
            do 
                let musicFile = try Data(contentsOf: url)
                let savePath = FileManager.customFolderURL.appendingPathComponent(url.lastPathComponent)
                
                try musicFile.write(to: savePath, options: .atomic)
                print("Success")
                musicFiles.append(savePath)
             catch 
                print("Failed to save the music file:")
                print(error)
            
            url.stopAccessingSecurityScopedResource()
         else 
            print("Permission failed!")
        
    
    
    func getMusicFiles() 
        do 
            let musicFiles = try FileManager.default.contentsOfDirectory(atPath: FileManager.customFolderURL.path)
            print(musicFiles)
         catch 
            print("Failed to retrieve items.")
        
    


struct MainView: View 
    @State private var isFileImporterShown = false
    @State private var isMusicPlayerShown = false
    
    @ObservedObject var manager = Manager.shared
    
    var body: some View 
        TabView 
            VStack 
                Button("Import Song") 
                    isFileImporterShown.toggle()
                
                .padding()
                .fileImporter(isPresented: $isFileImporterShown, allowedContentTypes: [.audio], allowsMultipleSelection: true)  result in
                    do 
                        let url = try result.get().first!
                        if url.startAccessingSecurityScopedResource() 
                            manager.save(url: url)
                        
                     catch 
                        print(error)
                    
                
                
                Button("Show Player") 
                    isMusicPlayerShown.toggle()
                
                .padding()
                .sheet(isPresented: $isMusicPlayerShown) 
                    Text("Musiker")
                
            
            .tabItem 
                Image(systemName: "externaldrive")
                Text("Load")
            
            
            AllSongsListView()
                .tabItem 
                    Image(systemName: "music.note.list")
                    Text("Songs")
                
        
    


struct AllSongsListView: View 
    @ObservedObject var manager = Manager.shared
    
    var body: some View 
        NavigationView 
            List 
                ForEach(manager.musicFiles, id: \.self)  file in
                    Text(file.lastPathComponent)
                
            
            .navigationTitle("Your Songs")
            .onAppear 
                manager.getMusicFiles()
            
        
    

【讨论】:

以上是关于如何在 SwiftUI 中使用 .fileimporter 保存音频文件并检索文件并在 SwiftUI 列表中显示它们的文件名?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UIkit 中添加 SwiftUI 对象

如何在 SwiftUI 中使用 SFSafariViewController?

如何在 swiftUI 视图中使用按钮? [关闭]

如何在 SwiftUI 中使用 .fileimporter 保存音频文件并检索文件并在 SwiftUI 列表中显示它们的文件名?

如何在 Xcode Playground 中使用 SwiftUI?

如何在 SwiftUI 中使用渐变填充形状