Writing Swift Dictionary to File

Writing swift dictionary to file

Anyway, when you want to store MyOwnType to file, MyOwnType must be a subclass of NSObject and conforms to NSCoding protocol. like this:

class MyOwnType: NSObject, NSCoding {

var name: String

init(name: String) {
self.name = name
}

required init(coder aDecoder: NSCoder) {
name = aDecoder.decodeObjectForKey("name") as? String ?? ""
}

func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(name, forKey: "name")
}
}

Then, here is the Dictionary:

var dict = [Int : [Int : MyOwnType]]()
dict[1] = [
1: MyOwnType(name: "foobar"),
2: MyOwnType(name: "bazqux")
]

So, here comes your question:

Writing swift dictionary to file

You can use NSKeyedArchiver to write, and NSKeyedUnarchiver to read:

func getFileURL(fileName: String) -> NSURL {
let manager = NSFileManager.defaultManager()
let dirURL = manager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false, error: nil)
return dirURL!.URLByAppendingPathComponent(fileName)
}

let filePath = getFileURL("data.dat").path!

// write to file
NSKeyedArchiver.archiveRootObject(dict, toFile: filePath)

// read from file
let dict2 = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as [Int : [Int : MyOwnType]]

// here `dict2` is a copy of `dict`

But in the body of your question:

how can I write/read it to/from a plist file in swift?

In fact, NSKeyedArchiver format is binary plist. But if you want that dictionary as a value of plist, you can serialize Dictionary to NSData with NSKeyedArchiver:

// archive to data
let dat:NSData = NSKeyedArchiver.archivedDataWithRootObject(dict)

// unarchive from data
let dict2 = NSKeyedUnarchiver.unarchiveObjectWithData(data) as [Int : [Int : MyOwnType]]

Write Dictionary to File in Swift

URL(string is the wrong API. It requires that the string starts with a scheme like https://.

In the file system where paths starts with a slash you must use

let url = URL(fileURLWithPath: path)

as WithPath implies.

A swiftier way is PropertyListEncoder

extension Dictionary where Key: Encodable, Value: Encodable {
func writeToURL(_ url: URL) throws {
// archive data
let data = try PropertyListEncoder().encode(self)
try data.write(to: url)
}
}

How to write Dictionary to a file?

First of all filePath?.absoluteString returns the entire – even percent escaped – string including the file:// scheme and the method expects a path without the scheme (filePath?.path - the naming is a bit confusing ;-) ).

I recommend to save a [String:String] dictionary as property list file. It's not necessary to create the file explicitly.

I changed the signatures of the methods slightly in the Swift-3-way. Further there is no need to use any optional type.

func store(dictionary: Dictionary<String, String>, in fileName: String, at directory: String) -> Bool {
let fileExtension = "plist"
let directoryURL = create(directory:directory)
do {
let data = try PropertyListSerialization.data(fromPropertyList: dictionary, format: .xml, options: 0)
try data.write(to: directoryURL.appendingPathComponent(fileName).appendingPathExtension(fileExtension))
return true
} catch {
print(error)
return false
}
}

func create(directory: String) -> URL {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let directoryURL = documentsDirectory.appendingPathComponent(directory)

do {
try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
fatalError("Error creating directory: \(error.localizedDescription)")
}
return directoryURL
}

PS: Instead of returning a Bool you could make the store method can throw and handle the error in the calling method:

func store(dictionary: Dictionary<String, String>, in fileName: String, at directory: String) throws {
let fileExtension = "plist"
let directoryURL = create(directory:directory)

let data = try PropertyListSerialization.data(fromPropertyList: dictionary, format: .xml, options: 0)
try data.write(to: directoryURL.appendingPathComponent(fileName).appendingPathExtension(fileExtension))
}

Swift 4 How do I write/read dictionaries to/from the document directory?

Dictionary has its own write method which writes a property list representation of the contents of the dictionary to a given URL. You can do it using below code:

Write

    // Get application document directory path array
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
let fileName = "users"

if let documentPath = paths.first {
let filePath = NSMutableString(string: documentPath).appendingPathComponent(fileName)

let URL = NSURL.fileURL(withPath: filePath)

let dictionary = NSMutableDictionary(capacity: 0)

dictionary.setValue("valu1", forKey: "key1")
dictionary.setValue("valu2", forKey: "key2")

let success = dictionary.write(to: URL, atomically: true)
print("write: ", success)
}

Read

    if let dictionary = NSMutableDictionary(contentsOf: URL){
print(dictionary)
}

Hope, it will work.

How to write an array of dictionaries to a .txt file in Xcode Project

If all you want to do is output your Array of Dictionaries in an "orderly / readable" format, you can use this:

if let orderedKeys = finalDictionary.first?.keys {

var outputString = ""
var i = 1

for d in finalDictionary {
outputString += "Booking \(i):\n"
for k in orderedKeys {
outputString += k + ": " + (d[k] ?? "(no value)") + "\n"
}
outputString += "\n"
i += 1
}

print(outputString)
// or, write outputString to a text file

}

Note: this is just quick code... not necessarily optimal or 100% error free, and assumes all records have the same keys. More of a "here's a direction to go" kinda thingy :)

Edit: If the dictionaries may have variable sets of keys, you can do this:

var outputString = ""
var i = 1
for d in finalDictionary {
outputString += "Booking \(i):\n"
for k in d.keys {
outputString += k + ": " + (d[k] ?? "(no value)") + "\n"
}
outputString += "\n"
i += 1
}

print(outputString)

Edit 2: probably a little "Swiftier" way of doing it:

outputString = ""
i = 1

finalDictionary.forEach {
outputString += "Booking \(i):\n"
$0.forEach { outputString += "\($0): \($1)\n" }
outputString += "\n"
i += 1
}

print(outputString)

Because Dictionaries are unordered, you may end up with:

Booking 1:
EmailAddress: johnmm@gmail.com
PhoneNumber: 94949392
FullName: John
.
Booking 2:
SomeOtherKey: Some Value
FullName: Dave
EmailAddress: dave@gmail.com
.
Booking 3:
FullName: Chris
PhoneNumber: 202583963
SomeOtherKey: Some Other Value
EmailAddress: chris@gmail.com

and so on.

Write dictionary in Bundle's json file, Swift 4, iOS

You cannot edit an embedded file. You have to first copy it from Bundle to Documents directory and then work ( edit ) on this file

How to save/retrieve dictionary from file using SwiftyJSON

I finally got this to work. The biggest problem was that I couldn't convert collaborationDictionary to JSON. I finally had to convert it to a dictionary of arrays vs dictionary of sets. Here are the 2 methods:

     // **************************************************************************
func getUploadedFileSet() {
let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)

if FileManager.default.fileExists(atPath: (jsonFileURL?.absoluteString)!) {
do {
let data = try Data(contentsOf: jsonFileURL!, options: .alwaysMapped)
let json = JSON(data: data)
if json != nil {
for (key, subJson) in json[kCollaborations] {
let stringArray:[String] = subJson.arrayValue.map { $0.string! }
let stringSet = Set(stringArray)
collaborationDictionary.updateValue(stringSet, forKey: key)
}
} else {
print("Could not get json from file, make sure that file contains valid json.")
}
} catch let error {
print(error.localizedDescription)
}
}
}

// **************************************************************************
func saveUploadedFilesSet() {
let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)
let adjustedJSONFileURL = URL(fileURLWithPath:(jsonFileURL?.absoluteString)!)

do {
let dirExists = FileManager.default.fileExists(atPath: (appURL?.absoluteString)!)
if !dirExists {
try FileManager.default.createDirectory(atPath: (appURL?.absoluteString)!, withIntermediateDirectories: false, attributes: nil)
}

// Convert set elements to arrays
var convertedCollaborationDictionary: [String:[String]] = [:]
for (sessionID, fileNameSet) in collaborationDictionary {
let array = Array(fileNameSet)
convertedCollaborationDictionary.updateValue(array, forKey: sessionID)
}
let json: JSON = JSON(convertedCollaborationDictionary)
let fullJSON: JSON = [kCollaborations:json.object]
let data = try fullJSON.rawData()
try data.write(to: adjustedJSONFileURL, options: .atomic)

} catch let error as NSError {
print(error.localizedDescription);
}
}

How to add Dictionary to Plist in SWIFT

You need to convert Dictionary to NSDictionary so that you can use writeToFile

Try to cast with this

let succeed = (favoriteGooglelocations as NSDictionary).writeToFile(path, atomically: true)

If succeed is false,check your GoogleItems class,it should conforms to NSCoding

Update,this is the code I test,you may refer to it

import UIKit
import CoreLocation

Set you GoogleItems conforms to NSCoding

class GoogleItems: NSObject,NSCoding {
override init() {}
var name:String?
var address:String?
var distance : String?
var googleLocation: CLLocation?
var isStar : Bool?
required init(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObjectForKey("name") as? String
self.address = aDecoder.decodeObjectForKey("address") as? String
self.distance = aDecoder.decodeObjectForKey("distance") as? String
self.googleLocation = aDecoder.decodeObjectForKey("googleLocation") as? CLLocation
self.isStar = aDecoder.decodeObjectForKey("isStar") as? Bool
}
func encodeWithCoder(aCoder: NSCoder) {
if name != nil{ aCoder.encodeObject(name, forKey: "name")}
if address != nil{ aCoder.encodeObject(address, forKey: "address")}
if distance != nil { aCoder.encodeObject(distance, forKey: "distance")}
if googleLocation != nil { aCoder.encodeObject(googleLocation, forKey: "googleLocation")}
if isStar != nil {aCoder.encodeBool(isStar!, forKey: "isStar")}
}
}

Then write to file

    var favoriteGooglelocations = [Int:GoogleItems]()
var item = GoogleItems()
item.isStar = true
item.name = "name"
item.address = "address"
item.googleLocation = nil
item.distance = "23"
favoriteGooglelocations[1] = item
let dic = favoriteGooglelocations as NSDictionary
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentDirectory = paths[0] as! String
let path = documentDirectory.stringByAppendingPathComponent("Favorites.plist")
let succeed = NSKeyedArchiver.archiveRootObject(dic, toFile: path)
println(succeed)

Read from file

     let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)

let documentDirectory = paths[0] as! String

let path = documentDirectory.stringByAppendingPathComponent("Favorites.plist")
let dic = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? [Int:GoogleItems]
if(dic != nil){
for (key,value) in dic!{
let item = value
println(item.name)
println(item.address)
}

}


Related Topics



Leave a reply



Submit