【问题标题】:Save data to .plist file in Swift 3在 Swift 3 中将数据保存到 .plist 文件
【发布时间】:2017-05-30 19:20:54
【问题描述】:

我已成功地将我的 plist 文件中的数据读取到表视图中。现在,我只想知道如何添加另一个带有字符串“名称”和“位置”的“项目”。

我正在寻找的是一种发送字符串以保存为新“项目”的“名称”或“位置”的方法。例如,如果我单击一个按钮,输入的信息将存储在新“项目”下的 plist 文件中。

有人可以帮助我朝着正确的方向前进吗?如果是你,你会怎么做?

我正在使用 Swift 3 和 Xcode 8.2.1

这是我的 .plist 文件: enter image description here

这是我用于获取“项目”的“名称”和“位置”的代码,以便我可以将其插入到表格视图中:

struct SavedTracks {

    let name: String
    let location: String
}

extension SavedTracks {
    enum ErrorType: Error {
        case noPlistFile
        case cannotReadFile
    }

    /// Load all the elements from the plist file
    static func loadFromPlist() throws -> [SavedTracks] {
        // First we need to find the plist
        guard let file = Bundle.main.path(forResource: "SkiTracks", ofType: "plist") else {
            throw ErrorType.noPlistFile
        }

        // Then we read it as an array of dict
        guard let array = NSArray(contentsOfFile: file) as? [[String: AnyObject]] else {
            throw ErrorType.cannotReadFile
        }

        // Initialize the array
        var elements: [SavedTracks] = []

        // For each dictionary
        for dict in array {
            // We implement the element
            let element = SavedTracks.from(dict: dict)
            // And add it to the array
            elements.append(element)
        }

        // Return all elements
        return elements
    }

    /// Create an element corresponding to the given dict
    static func from(dict: [String: AnyObject]) -> SavedTracks {
        let name = dict["name"] as! String
        let location = dict["location"] as! String


        return SavedTracks(name: name,
                           location: location)
    }
}

【问题讨论】:

    标签: ios arrays swift xcode swift3


    【解决方案1】:

    你可以试试这个代码:

    class SavedTracks: NSObject,NSCoding {
    var name: String
    var location: String
    
    required init(name:String="", location:String="") {
        self.name = name
        self.location = location
    }
    
    required init(coder decoder: NSCoder) {
        self.name = decoder.decodeObject(forKey: "Name") as? String ?? ""
        self.location = decoder.decodeObject(forKey: "location") as? String ?? ""
    }
    
    func encode(with coder: NSCoder) {
        coder.encode(name, forKey:"Name")
        coder.encode(location, forKey:"location")
    }
    }
    class DataModel: NSObject {
    
    var saveTrack = [SavedTracks]()
    
    override init(){
        super.init()
        print("document file path:\(documentsDirectory())")
        print("Data file path:\(dataFilePath())")
    }
    
    //save data
    func saveData() {
        let data = NSMutableData()
        let archiver = NSKeyedArchiver(forWritingWith: data)
        archiver.encode(saveTrack, forKey: "userList")
        archiver.finishEncoding()
        data.write(toFile: dataFilePath(), atomically: true)
    }
    
    //read data
    func loadData() {
        let path = self.dataFilePath()
        let defaultManager = FileManager()
        if defaultManager.fileExists(atPath: path) {
            let url = URL(fileURLWithPath: path)
            let data = try! Data(contentsOf: url)
            let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
            saveTrack = unarchiver.decodeObject(forKey: "userList") as! Array
            unarchiver.finishDecoding()
        }
    }
    
    func documentsDirectory()->String {
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory,
                                                        .userDomainMask, true)
        let documentsDirectory = paths.first!
        return documentsDirectory
    }
    
    func dataFilePath ()->String{
        return self.documentsDirectory().appendingFormat("/userList.plist")
    }
    }
    class ViewController: UIViewController {
    var dataModel = DataModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        onCreateData()
    }
    
    //create data
    func onCreateData(){
        dataModel.saveTrack.append(SavedTracks(name: "jack", location: "xxx"))
        dataModel.saveTrack.append(SavedTracks(name: "tom", location: "yyyy"))
        dataModel.saveTrack.append(SavedTracks(name: "rose", location: "zzz"))
    }
    
    @IBAction func saveData(_ sender: UIButton) {
        dataModel.saveData()
        print("succeed")
    }
    
    @IBAction func printData(_ sender: UIButton) {
        dataModel.loadData()
        print("succeed!", dataModel.saveTrack)
    }
    }
    

    【讨论】:

    • 嗯...我做了一个 .swift 类,把所有的代码,除了视图控制器的部分,我把它放在视图控制器的场景中。在那个场景中,我放置了两个按钮,并将它们连接到视图控制器中的动作。然后,当我单击 saveData 和 printData 按钮时,控制台会输出此信息:成功成功! [, , ] 但是,这显然不是“name: name, location: location”。我做错了吗?
    • print("succeed!", dataModel.saveTrack) 打印("succeed!", dataModel.saveTrack.name) ,然后打印名称,位置替换名称将打印位置
    • print("succeed!", dataModel.saveTrack),这段代码的意思是打印这个对象,所以你的日志就像
    【解决方案2】:

    这是用于读写 plist 的辅助结构:

    用法:

    //Reading :
    let rootArray = PlistFile(named: "PlistFilename")?.array
    let rootDictionary = PlistFile(named: "PlistFilename")?.dictionary
    
    //Writing :
    
    if let plistFile = PlistFile(named : "UserData") {
      plistFile.array = yourArray
    }
    
    //or :
    
    try? PlistFile(named : "UserData")?.write(yourArray)
    

    代码:

    struct PlistFile {
    
        enum PlistError: Error {
            case failedToWrite
            case fileDoesNotExist
        }
    
        let name:String
    
        var sourcePath:String? {
            return Bundle.main.path(forResource: name, ofType: "plist")
        }
    
        var destPath:String? {
            if let _ = sourcePath {
                let dir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
                return (dir as NSString).appendingPathComponent("\(name).plist")
            } else {
                return nil
            }
        }
    
        var dictionary : [String:Any]? {
            get{
                return getDictionary()
            }
            set{
                if let newDict = newValue {
                    try? write(dictionary: newDict)
                }
            }
        }
    
        var array : [Any]? {
            get{
                return getArray()
            }
            set{
                if let newArray = newValue {
                    try? write(array: newArray)
                }
            }
        }
    
        private let fileManager = FileManager.default
    
        init?(named :String) {
            self.name = named
    
            guard let source = sourcePath, let destination = destPath, fileManager.fileExists(atPath: source)  else {
                return nil
            }
    
            if !fileManager.fileExists(atPath: destination) {
                do {
                    try fileManager.copyItem(atPath: source, toPath: destination)
                } catch let error {
                    print("Unable to copy file. ERROR: \(error.localizedDescription)")
                    return nil
                }
            }
        }
    
    
        private func getDictionary() -> [String:Any]? {
            guard let destPath = self.destPath, fileManager.fileExists(atPath: destPath) else {
                return nil
            }
            return NSDictionary(contentsOfFile: destPath) as? [String:Any]
        }
    
        private func getArray() -> [Any]? {
            guard let destPath = self.destPath, fileManager.fileExists(atPath: destPath) else {
                return nil
            }
            return NSArray(contentsOfFile: destPath) as? [Any]
        }
    
        func write(dictionary : [String:Any]) throws{
            guard let destPath = self.destPath, fileManager.fileExists(atPath: destPath) else {
                throw PlistError.fileDoesNotExist
            }
    
            if !NSDictionary(dictionary: dictionary).write(toFile: destPath, atomically: false) {
                print("Failed to write the file")
                throw PlistError.failedToWrite
            }
        }
    
        func write(array : [Any] ) throws {
            guard let destPath = self.destPath, fileManager.fileExists(atPath: destPath) else {
                throw PlistError.fileDoesNotExist
            }
    
            if !NSArray(array: array).write(toFile: destPath, atomically: false) {
                print("Failed to write the file")
                throw PlistError.failedToWrite
            }
        }
    
    
    }
    

    【讨论】:

      【解决方案3】:

      使用 PropertyListSerialization 保存重复动态字典的简单方法

      let plistDict: [String: Any] = ["Key": "Value"]
      
      //Write Data Into Plist
      func writePlist(dictContent: [String: Any]) {
      
          let url = URL(fileURLWithPath: PlistManager.path)
          do {
              let data = try Data(contentsOf: url)
              var array = try PropertyListSerialization.propertyList(from: data, format: nil) as! [[String:Any]]
              array.append(dictContent)
              let writeData = try PropertyListSerialization.data(fromPropertyList: array, format: .xml, options:0)
              try writeData.write(to: url)
          } catch {
              print(error)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-31
        • 2013-12-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多