Failed when storing NSMutableArray into plist in swift - swift

I'm writing a swift codes for iphone. In my app I need to store some friends info. Currently I use plist to store the data. I have referred to lots of examples of reading/writing NSMutableArray from/into plist, but when I tried to store an NSMutableArray it just doesn't work.
Below is my codes, finally the result is "nil".
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let filename = path.stringByAppendingPathComponent("FriendList.plist")
var FM = NSFileManager()
if FM.createFileAtPath(filename, contents: nil, attributes: nil) {
if (arrayToBeStored?.writeToFile(filename, atomically: false) != nil) {
if NSFileManager().fileExistsAtPath(filename){
let arrayFromPlist = NSMutableArray(contentsOfFile: filename)
//everything goes well except "arrayFromPlist" is just nil.
println(arrayFromPlist)
}else{
println("Plist was not actually created!")
}
}else{
println("Failed to store the array into plist.")
}
}else{
println("Failed to create file.")
}
Anyone has ideas what's wrong in my codes?

"arrayToBeStored.writeToFile" returns a boolean, so it's not comparable with "nil".
let arrayToBeStored = NSArray(object: ["test1", "test2"])
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
let filename = path.stringByAppendingPathComponent("FriendList.plist")
var FM = NSFileManager()
if FM.createFileAtPath(filename, contents: nil, attributes: nil) {
if arrayToBeStored.writeToFile(filename, atomically: false) {
if NSFileManager().fileExistsAtPath(filename){
let arrayFromPlist = NSMutableArray(contentsOfFile: filename)
println(arrayFromPlist!) // => test1, test2
}else{
println("Plist was not actually created!")
}
} else {
println("Failed to store the array into plist.")
}
}else{
println("Failed to create file.")
}
Xcode 6.2 version:
let arrayToBeStored = NSArray(object: ["test1", "test2"])
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let filename = path.stringByAppendingPathComponent("FriendList.plist")
var FM = NSFileManager()
if FM.createFileAtPath(filename, contents: nil, attributes: nil) {
if arrayToBeStored.writeToFile(filename, atomically: false) {
if NSFileManager().fileExistsAtPath(filename) {
let arrayFromPlist = NSMutableArray(contentsOfFile: filename)
println(arrayFromPlist![0][0]) // => test1
}else{
println("Plist was not actually created!")
}
} else {
println("Failed to store the array into plist.")
}
}else{
println("Failed to create file.")
}

Related

Problem creating and writing a subdirectory in Swift 5

I'm having a problem trying to write a text file to a subdirectory of my Documents folder.
My code is as follows:
#objc func makeFileButtonTapped() {
print(#function)
let tempName = "test"
var tempRecurrance: String = ""
switch recurrentInt {
case 0:
tempRecurrance = "Never"
case 1:
tempRecurrance = "Sometimes"
case 2:
tempRecurrance = "Often"
default:
tempRecurrance = "Unknown"
}
fileName = tempName + ".txt"
let tempTitle: String = "\n\Title: " + titleString + "\n\n"
let tempDate: String = "Date: " + dateString + "\n\n"
let tempRecurring: String = "Recurs: " + tempRecurrance + "\n\n\n\n"
myDocument = ""
myDocument.append(tempTitle)
myDocument.append(tempDate)
myDocument.append(tempRecurring)
saveToDirectory()
}
func saveToDirectory(){
print(#function)
let fileManager = FileManager.default
// Create subdirectory
do {
let directoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let myAppDirectoryURL = directoryURL.appendingPathComponent("MySubDirectory")
if !fileManager.fileExists(atPath: myAppDirectoryURL.path) {
try fileManager.createDirectory(at: myAppDirectoryURL, withIntermediateDirectories: true, attributes: nil)
print("New directory created.")
//print("dictionary already exists.")
}
// Create document
let documentURL = myAppDirectoryURL.appendingPathComponent (fileName)
try myDocument.write(to: documentURL, atomically: false, encoding: .utf8)
print("documentURL =", documentURL.path)
} catch {
print(error)
}
}
I'm getting a console message that the directory {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}.
Remove the check if the file already exists, if !fileManager.fileExists(atPath: myAppDirectoryURL.path) since the createDirectory call will not generate an error if the directory already exist when you have withIntermediateDirectories set tot true.
You used some properties that wasn't part of the question so here is my test version of your function for completeness
func saveToDirectory(_ fileName: String, text: String) {
let fileManager = FileManager.default
do {
let directoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let myAppDirectoryURL = directoryURL.appendingPathComponent("MySubDirectory")
try fileManager.createDirectory(at: myAppDirectoryURL, withIntermediateDirectories: true, attributes: nil)
let documentURL = myAppDirectoryURL.appendingPathComponent (fileName)
try text.write(to: documentURL, atomically: true, encoding: .utf8)
} catch {
print(error)
}
}

How To Read From File Swift [duplicate]

I need to read and write data to/from a text file, but I haven't been able to figure out how.
I found this sample code in the Swift's iBook, but I still don't know how to write or read data.
import Cocoa
class DataImporter {
/*
DataImporter is a class to import data from an external file.
The class is assumed to take a non-trivial amount of time to initialize.
*/
var fileName = "data.txt"
// the DataImporter class would provide data importing functionality here
}
class DataManager {
#lazy var importer = DataImporter()
var data = String[]()
// the DataManager class would provide data management functionality here
}
let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"
// the DataImporter instance for the importer property has not yet been created”
println(manager.importer.fileName)
// the DataImporter instance for the importer property has now been created
// prints "data.txt”
var str = "Hello World in Swift Language."
For reading and writing you should use a location that is writeable, for example documents directory. The following code shows how to read and write a simple string. You can test it on a playground.
Swift 3.x - 5.x
let file = "file.txt" //this is the file. we will write to and read from it
let text = "some text" //just a text
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(file)
//writing
do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {/* error handling here */}
//reading
do {
let text2 = try String(contentsOf: fileURL, encoding: .utf8)
}
catch {/* error handling here */}
}
Swift 2.2
let file = "file.txt" //this is the file. we will write to and read from it
let text = "some text" //just a text
if let dir = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first {
let path = NSURL(fileURLWithPath: dir).URLByAppendingPathComponent(file)
//writing
do {
try text.writeToURL(path, atomically: false, encoding: NSUTF8StringEncoding)
}
catch {/* error handling here */}
//reading
do {
let text2 = try NSString(contentsOfURL: path, encoding: NSUTF8StringEncoding)
}
catch {/* error handling here */}
}
Swift 1.x
let file = "file.txt"
if let dirs : [String] = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String] {
let dir = dirs[0] //documents directory
let path = dir.stringByAppendingPathComponent(file);
let text = "some text"
//writing
text.writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
//reading
let text2 = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil)
}
Assuming that you have moved your text file data.txt to your Xcode-project (Use drag'n'drop and check "Copy files if necessary") you can do the following just like in Objective-C:
let bundle = NSBundle.mainBundle()
let path = bundle.pathForResource("data", ofType: "txt")
let content = NSString.stringWithContentsOfFile(path) as String
println(content) // prints the content of data.txt
Update:
For reading a file from Bundle (iOS) you can use:
let path = NSBundle.mainBundle().pathForResource("FileName", ofType: "txt")
var text = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)!
println(text)
Update for Swift 3:
let path = Bundle.main.path(forResource: "data", ofType: "txt") // file path for file "data.txt"
var text = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)!
For Swift 5
let path = Bundle.main.path(forResource: "ListAlertJson", ofType: "txt") // file path for file "data.txt"
let string = try String(contentsOfFile: path!, encoding: String.Encoding.utf8)
Xcode 8.x • Swift 3.x or later
do {
// get the documents folder url
if let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
// create the destination url for the text file to be saved
let fileURL = documentDirectory.appendingPathComponent("file.txt")
// define the string/text to be saved
let text = "Hello World !!!"
// writing to disk
// Note: if you set atomically to true it will overwrite the file if it exists without a warning
try text.write(to: fileURL, atomically: false, encoding: .utf8)
print("saving was successful")
// any posterior code goes here
// reading from disk
let savedText = try String(contentsOf: fileURL)
print("savedText:", savedText) // "Hello World !!!\n"
}
} catch {
print("error:", error)
}
New simpler and recommended method:
Apple recommends using URLs for filehandling and the other solutions here seem deprecated (see comments below).
The following is the new simple way of reading and writing with URL's:
Swift 5+, 4 and 3.1
import Foundation // Needed for those pasting into Playground
let fileName = "Test"
let dir = try? FileManager.default.url(for: .documentDirectory,
in: .userDomainMask, appropriateFor: nil, create: true)
guard let fileURL = dir?.appendingPathComponent(fileName).appendingPathExtension("txt") else {
fatalError("Not able to create URL")
}
// Writing to the file named Test
let outString = "Write this text to the file"
do {
try outString.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
assertionFailure("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
}
// Reading it back from the file
var inString = ""
do {
inString = try String(contentsOf: fileURL)
} catch {
assertionFailure("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
}
print("Read from the file: \(inString)")
Xcode 8, Swift 3 way to read file from the app bundle:
if let path = Bundle.main.path(forResource: filename, ofType: nil) {
do {
let text = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
print(text)
} catch {
printError("Failed to read text from \(filename)")
}
} else {
printError("Failed to load file from app bundle \(filename)")
}
Here's a convenient copy and paste Extension
public extension String {
func contentsOrBlank()->String {
if let path = Bundle.main.path(forResource:self , ofType: nil) {
do {
let text = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
return text
} catch { print("Failed to read text from bundle file \(self)") }
} else { print("Failed to load file from bundle \(self)") }
return ""
}
}
For example
let t = "yourFile.txt".contentsOrBlank()
You almost always want an array of lines:
let r:[String] = "yourFile.txt"
.contentsOrBlank()
.characters
.split(separator: "\n", omittingEmptySubsequences:ignore)
.map(String.init)
I want to show you only the first part, that is read. Here's how simply you can read:
Swift 3:
let s = try String(contentsOfFile: Bundle.main.path(forResource: "myFile", ofType: "txt")!)
Swift 2:
let s = try! String(contentsOfFile: NSBundle.mainBundle().pathForResource("myFile", ofType: "txt")!)
Simplest way to read a file in Swift > 4.0
let path = Bundle.main.path(forResource: "data", ofType: "txt") // file path for file "data.txt"
do {
var text = try String(contentsOfFile: path!)
}
catch(_){print("error")}
}
You may find this tool useful to not only read from file in Swift but also parse your input: https://github.com/shoumikhin/StreamScanner
Just specify the file path and data delimiters like this:
import StreamScanner
if let input = NSFileHandle(forReadingAtPath: "/file/path")
{
let scanner = StreamScanner(source: input, delimiters: NSCharacterSet(charactersInString: ":\n")) //separate data by colons and newlines
while let field: String = scanner.read()
{
//use field
}
}
Hope, this helps.
This works with Swift 3.1.1 on Linux:
import Foundation
let s = try! String(contentsOfFile: "yo", encoding: .utf8)
The current accepted answer above from Adam had some errors for me but here is how I reworked his answer and made this work for me.
let file = "file.txt"
let dirs: [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
if (dirs != nil) {
let directories:[String] = dirs!
let dirs = directories[0]; //documents directory
let path = dirs.stringByAppendingPathComponent(file);
let text = "some text"
//writing
text.writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
//reading
var error:NSError?
//reading
let text2 = String(contentsOfFile: path, encoding:NSUTF8StringEncoding, error: &error)
if let theError = error {
print("\(theError.localizedDescription)")
}
}
To avoid confusion and add ease, I have created two functions for reading and writing strings to files in the documents directory. Here are the functions:
func writeToDocumentsFile(fileName:String,value:String) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
let path = documentsPath.stringByAppendingPathComponent(fileName)
var error:NSError?
value.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error: &error)
}
func readFromDocumentsFile(fileName:String) -> String {
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
let path = documentsPath.stringByAppendingPathComponent(fileName)
var checkValidation = NSFileManager.defaultManager()
var error:NSError?
var file:String
if checkValidation.fileExistsAtPath(path) {
file = NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil) as! String
} else {
file = "*ERROR* \(fileName) does not exist."
}
return file
}
Here is an example of their use:
writeToDocumentsFile("MyText.txt","Hello world!")
let value = readFromDocumentsFile("MyText.txt")
println(value) //Would output 'Hello world!'
let otherValue = readFromDocumentsFile("SomeText.txt")
println(otherValue) //Would output '*ERROR* SomeText.txt does not exist.'
Hope this helps!
Xcode Version: 6.3.2
I had to recode like this:
let path = NSBundle.mainBundle().pathForResource("Output_5", ofType: "xml")
let text = try? NSString(contentsOfFile: path! as String, encoding: NSUTF8StringEncoding)
print(text)
In the function example, (read|write)DocumentsFromFile(...) having some function wrappers certainly seems to makes sense since everything in OSx and iOS seems to need three or four major classes instantiated and a bunch of properties, configured, linked, instantiated, and set, just to write "Hi" to a file, in 182 countries.
However, these examples aren't complete enough to use in a real program. The write function does not report any errors creating or writing to the file. On the read, I don't think it's a good idea to return an error that the file doesn't exist as the string that is supposed to contain the data that was read. You would want to know that it failed and why, through some notification mechanism, like an exception. Then, you can write some code that outputs what the problem is and allows the user to correct it, or "correctly" breaks the program at that point.
You would not want to just return a string with an "Error file does not exist" in it. Then, you would have to look for the error in the string from calling function each time and handle it there. You also possibly couldn't really tell if the error string was actually read from an actual file, or if it was produced from your code.
You can't even call the read like this in swift 2.2 and Xcode 7.3 because NSString(contentsOfFile...) throws an exception. It is a compile time error if you do not have any code to catch it and do something with it, like print it to stdout, or better, an error popup window, or stderr. I have heard that Apple is moving away from try catch and exceptions, but it's going to be a long move and it's not possible to write code without this. I don't know where the &error argument comes from, perhaps an older version, but NSString.writeTo[File|URL] does not currently have an NSError argument. They are defined like this in NSString.h :
public func writeToURL(url: NSURL, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws
public func writeToFile(path: String, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws
public convenience init(contentsOfURL url: NSURL, encoding enc: UInt) throws
public convenience init(contentsOfFile path: String, encoding enc: UInt) throws
Also, the file not existing is just one of a number of potential problems your program might have reading a file, such as a permissions problem, the file size, or numerous other issues that you would not even want to try to code a handler for each one of them. It's best to just assume it's all correct and catch and print, or handle, an exception if something goes amiss, besides, at this point, you don't really have a choice anyway.
Here are my rewrites :
func writeToDocumentsFile(fileName:String,value:String) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString!
let path = documentsPath.stringByAppendingPathComponent(fileName)
do {
try value.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding)
} catch let error as NSError {
print("ERROR : writing to file \(path) : \(error.localizedDescription)")
}
}
func readFromDocumentsFile(fileName:String) -> String {
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let path = documentsPath.stringByAppendingPathComponent(fileName)
var readText : String = ""
do {
try readText = NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding) as String
}
catch let error as NSError {
print("ERROR : reading from file \(fileName) : \(error.localizedDescription)")
}
return readText
}
For my txt file works this way:
let myFileURL = NSBundle.mainBundle().URLForResource("listacomuni", withExtension: "txt")!
let myText = try! String(contentsOfURL: myFileURL, encoding: NSISOLatin1StringEncoding)
print(String(myText))
Latest swift3 code
You can read data from text file just use bellow code
This my text file
{
"NumberOfSlices": "8",
"NrScenes": "5",
"Scenes": [{
"dataType": "label1",
"image":"http://is3.mzstatic.com/image/thumb/Purple19/v4/6e/81/31/6e8131cf-2092-3cd3-534c-28e129897ca9/mzl.syvaewyp.png/53x53bb-85.png",
"value": "Hello",
"color": "(UIColor.red)"
}, {
"dataType": "label2",
"image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",
"value": "Hi There",
"color": "(UIColor.blue)"
}, {
"dataType": "label3",
"image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",
"value": "hi how r u ",
"color": "(UIColor.green)"
}, {
"dataType": "label4",
"image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",
"value": "what are u doing ",
"color": "(UIColor.purple)"
}, {
"dataType": "label5",
"image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",
"value": "how many times ",
"color": "(UIColor.white)"
}, {
"dataType": "label6",
"image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/5a/f3/06/5af306b0-7cac-1808-f440-bab7a0d18ec0/mzl.towjvmpm.png/53x53bb-85.png",
"value": "hi how r u ",
"color": "(UIColor.blue)"
}, {
"dataType": "label7",
"image":"http://is5.mzstatic.com/image/thumb/Purple71/v4/a8/dc/eb/a8dceb29-6daf-ca0f-d037-df9f34cdc476/mzl.ukhhsxik.png/53x53bb-85.png",
"value": "hi how r u ",
"color": "(UIColor.gry)"
}, {
"dataType": "label8",
"image":"http://is2.mzstatic.com/image/thumb/Purple71/v4/15/23/e0/1523e03c-fff2-291e-80a7-73f35d45c7e5/mzl.zejcvahm.png/53x53bb-85.png",
"value": "hi how r u ",
"color": "(UIColor.brown)"
}]
}
You can use this code you get data from text json file in swift3
let filePath = Bundle.main.path(forResource: "nameoftheyourjsonTextfile", ofType: "json")
let contentData = FileManager.default.contents(atPath: filePath!)
let content = NSString(data: contentData!, encoding: String.Encoding.utf8.rawValue) as? String
print(content)
let json = try! JSONSerialization.jsonObject(with: contentData!) as! NSDictionary
print(json)
let app = json.object(forKey: "Scenes") as! NSArray!
let _ : NSDictionary
for dict in app! {
let colorNam = (dict as AnyObject).object(forKey: "color") as! String
print("colors are \(colorNam)")
// let colour = UIColor(hexString: colorNam) {
// colorsArray.append(colour.cgColor)
// colorsArray.append(colorNam as! UIColor)
let value = (dict as AnyObject).object(forKey: "value") as! String
print("the values are \(value)")
valuesArray.append(value)
let images = (dict as AnyObject).object(forKey: "image") as! String
let url = URL(string: images as String)
let data = try? Data(contentsOf: url!)
print(data)
let image1 = UIImage(data: data!)! as UIImage
imagesArray.append(image1)
print(image1)
}
It is recommended to read and write files asynchronously! and it's so easy to do in pure Swift,
here is the protocol:
protocol FileRepository {
func read(from path: String) throws -> String
func readAsync(from path: String, completion: #escaping (Result<String, Error>) -> Void)
func write(_ string: String, to path: String) throws
func writeAsync(_ string: String, to path: String, completion: #escaping (Result<Void, Error>) -> Void)
}
As you can see it allows you to read and write files synchronously or asynchronously.
Here is my implementation in Swift 5:
class DefaultFileRepository {
// MARK: Properties
let queue: DispatchQueue = .global()
let fileManager: FileManager = .default
lazy var baseURL: URL = {
try! fileManager
.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("MyFiles")
}()
// MARK: Private functions
private func doRead(from path: String) throws -> String {
let url = baseURL.appendingPathComponent(path)
var isDir: ObjCBool = false
guard fileManager.fileExists(atPath: url.path, isDirectory: &isDir) && !isDir.boolValue else {
throw ReadWriteError.doesNotExist
}
let string: String
do {
string = try String(contentsOf: url)
} catch {
throw ReadWriteError.readFailed(error)
}
return string
}
private func doWrite(_ string: String, to path: String) throws {
let url = baseURL.appendingPathComponent(path)
let folderURL = url.deletingLastPathComponent()
var isFolderDir: ObjCBool = false
if fileManager.fileExists(atPath: folderURL.path, isDirectory: &isFolderDir) {
if !isFolderDir.boolValue {
throw ReadWriteError.canNotCreateFolder
}
} else {
do {
try fileManager.createDirectory(at: folderURL, withIntermediateDirectories: true)
} catch {
throw ReadWriteError.canNotCreateFolder
}
}
var isDir: ObjCBool = false
guard !fileManager.fileExists(atPath: url.path, isDirectory: &isDir) || !isDir.boolValue else {
throw ReadWriteError.canNotCreateFile
}
guard let data = string.data(using: .utf8) else {
throw ReadWriteError.encodingFailed
}
do {
try data.write(to: url)
} catch {
throw ReadWriteError.writeFailed(error)
}
}
}
extension DefaultFileRepository: FileRepository {
func read(from path: String) throws -> String {
try queue.sync { try self.doRead(from: path) }
}
func readAsync(from path: String, completion: #escaping (Result<String, Error>) -> Void) {
queue.async {
do {
let result = try self.doRead(from: path)
completion(.success(result))
} catch {
completion(.failure(error))
}
}
}
func write(_ string: String, to path: String) throws {
try queue.sync { try self.doWrite(string, to: path) }
}
func writeAsync(_ string: String, to path: String, completion: #escaping (Result<Void, Error>) -> Void) {
queue.async {
do {
try self.doWrite(string, to: path)
completion(.success(Void()))
} catch {
completion(.failure(error))
}
}
}
}
enum ReadWriteError: LocalizedError {
// MARK: Cases
case doesNotExist
case readFailed(Error)
case canNotCreateFolder
case canNotCreateFile
case encodingFailed
case writeFailed(Error)
}
write in ViewDidLoad
var error: NSError?
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
var documentsDirectory = paths.first as String
var dataPath = documentsDirectory.stringByAppendingPathComponent("MyFolder")
if !NSFileManager.defaultManager().fileExistsAtPath(dataPath) {
NSFileManager.defaultManager().createDirectoryAtPath(dataPath, withIntermediateDirectories: false, attributes: nil, error: &error)
} else {
println("not creted or exist")
}
func listDocumentDirectoryfiles() -> [String] {
if let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as? String {
let myFilePath = documentDirectory.stringByAppendingPathComponent("MyFolder")
return NSFileManager.defaultManager().contentsOfDirectoryAtPath(myFilePath, error: nil) as [String]
}
return []
}
func writeToDocumentsFile(fileName:String,value:String) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let path = documentsPath.appendingPathComponent(fileName)
do{
try value.write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
}catch{
}
}
func readFromDocumentsFile(fileName:String) -> String {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let path = documentsPath.appendingPathComponent(fileName)
let checkValidation = FileManager.default
var file:String
if checkValidation.fileExists(atPath: path) {
do{
try file = NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String
}catch{
file = ""
}
} else {
file = ""
}
return file
}
Earlier solutions answers question, but in my case deleting old content of file while writing was a problem.
So, I created piece of code for writing to file in documents directory without deleting previous content. You probably need better error handling, but I believe it's good starting point. Swift 4.
Usuage:
let filename = "test.txt"
createOrOverwriteEmptyFileInDocuments(filename: filename)
if let handle = getHandleForFileInDocuments(filename: filename) {
writeString(string: "aaa", fileHandle: handle)
writeString(string: "bbb", fileHandle: handle)
writeString(string: "\n", fileHandle: handle)
writeString(string: "ccc", fileHandle: handle)
}
Helper methods:
func createOrOverwriteEmptyFileInDocuments(filename: String){
guard let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
debugPrint("ERROR IN createOrOverwriteEmptyFileInDocuments")
return
}
let fileURL = dir.appendingPathComponent(filename)
do {
try "".write(to: fileURL, atomically: true, encoding: .utf8)
}
catch {
debugPrint("ERROR WRITING STRING: " + error.localizedDescription)
}
debugPrint("FILE CREATED: " + fileURL.absoluteString)
}
private func writeString(string: String, fileHandle: FileHandle){
let data = string.data(using: String.Encoding.utf8)
guard let dataU = data else {
debugPrint("ERROR WRITING STRING: " + string)
return
}
fileHandle.seekToEndOfFile()
fileHandle.write(dataU)
}
private func getHandleForFileInDocuments(filename: String)->FileHandle?{
guard let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
debugPrint("ERROR OPENING FILE")
return nil
}
let fileURL = dir.appendingPathComponent(filename)
do {
let fileHandle: FileHandle? = try FileHandle(forWritingTo: fileURL)
return fileHandle
}
catch {
debugPrint("ERROR OPENING FILE: " + error.localizedDescription)
return nil
}
}
Swift 3.x - 5.x
The Best Example is to Create a Local Logfile with an Extension .txt
that can visible and show in the "Files App" with current date and Time as a File Name
just add this code in info.plist enable these two features
UIFileSharingEnabled
LSSupportsOpeningDocumentsInPlace
and this Function Below
var logfileName : String = ""
func getTodayString() -> String{
let date = Date()
let calender = Calendar.current
let components = calender.dateComponents([.year,.month,.day,.hour,.minute,.second], from: date)
let year = components.year
let month = components.month
let day = components.day
let hour = components.hour
let minute = components.minute
let second = components.second
let today_string = String(year!) + "-" + String(month!) + "-" + String(day!) + "-" + String(hour!) + "" + String(minute!) + "" + String(second!)+".txt"
return today_string
}
func LogCreator(){
logfileName = getTodayString()
print("LogCreator: Logfile Generated Named: \(logfileName)")
let file = logfileName //this is the file. we will write to and read from it
let text = "some text" //just a text
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(file)
let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)[0]
print("LogCreator: The Logs are Stored at location \(documentPath)")
//writing
do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {/* error handling here */}
//reading
do {
let text2 = try String(contentsOf: fileURL, encoding: .utf8)
print("LogCreator: The Detail log are :-\(text2)")
}
catch {/* error handling here */}
}
}
[1]: https://i.stack.imgur.com/4eg12.png
Xcode 8.3.2 Swift 3.x. Using NSKeyedArchiver and NSKeyedUnarchiver
Reading file from documents
let documentsDirectoryPathString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let documentsDirectoryPath = NSURL(string: documentsDirectoryPathString)!
let jsonFilePath = documentsDirectoryPath.appendingPathComponent("Filename.json")
let fileManager = FileManager.default
var isDirectory: ObjCBool = false
if fileManager.fileExists(atPath: (jsonFilePath?.absoluteString)!, isDirectory: &isDirectory) {
let finalDataDict = NSKeyedUnarchiver.unarchiveObject(withFile: (jsonFilePath?.absoluteString)!) as! [String: Any]
}
else{
print("File does not exists")
}
Write file to documents
NSKeyedArchiver.archiveRootObject(finalDataDict, toFile:(jsonFilePath?.absoluteString)!)

Documents folder working in Simulator but not iPad - Swift 2.1

The below code unzips a folder of images into a folder I create. and then loops through it and adds the names to an array, then loops through this array and retrieves those file names into an array of images.
It works perfectly on the simulator, but the data is empty when I do it on the iPad, it prints out nothing. I can only assume the folder isn't accessible or is being searched before the unzip has completed, but It shouldnt as I am using NSOperationQueue with a completion block.
func unzipData(objectData: NSManagedObject) {
var paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentsDir = paths[0]
let zipPath = documentsDir.stringByAppendingString("MyZipFiles")
let folderPath = documentsDir.stringByAppendingString("/docLibFiles") // My folder name in document directory
var optData = NSData(data: objectData.valueForKey("image") as! NSData)
print(objectData.valueForKey("imageUrl") as! String)
optData.writeToFile(zipPath, atomically: true)
let success = fileManager.fileExistsAtPath(zipPath) as Bool
if success == false {
do {
try! fileManager.createDirectoryAtPath(folderPath, withIntermediateDirectories: true, attributes: nil)
}
}
queue.addOperationWithBlock { () -> Void in
let operation1 = NSBlockOperation(block: {
let unZipped = SSZipArchive.unzipFileAtPath(zipPath, toDestination: folderPath)
})
operation1.completionBlock = {
dispatch_async(dispatch_get_main_queue(), {
if queue.operationCount == 0 {
self.retrieveFiles()
}
})
}
queue.addOperation(operation1)
}
}
func getDocumentsURL() -> NSURL {
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
return documentsURL
}
func fileInDocumentsDirectory(filename: String) -> String {
let fileURL = getDocumentsURL().URLByAppendingPathComponent(filename)
return fileURL.path!
}
func retrieveFiles() {
var paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentsDir = paths[0]
let zipPath = documentsDir.stringByAppendingString("MyZipFiles")
let folderPath = documentsDir.stringByAppendingString("/docLibFiles") // My folder name in document directory
do {
let filelist = try fileManager.contentsOfDirectoryAtPath(folderPath)
print(filelist)
print("filename")
for filename in filelist {
fileNameArray.append(filename)
}
} catch let error as NSError {
print("Could not save \(error)")
}
do {
for item in fileNameArray {
print("item \(item)")
let imagePath = fileInDocumentsDirectory("docLibFiles/\(item)")
imageArray.append(UIImage(contentsOfFile: imagePath)!)
}
print("filename array \(fileNameArray)")
print("image array \(imageArray)")
unzipDelegate!.unzipSet(imageArray)
}
}
In case of avoiding an error is generated by some trivial typos. Probably process paths in NSURL form
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentsDir = paths[0]
let url = NSURL(fileURLWithPath: documentsDir)
url.URLByAppendingPathComponent("MyZipFiles")
url.URLByAppendingPathComponent("docLibFiles")
Im not exactly sure why the initial problem was there, but my code was definitely overcomplicated. Ive sorted it now, hopefully it will help someone else in swift 2.1
class UnzipDocument {
let queue = NSOperationQueue() // BACKGROUND THREAD
var imageArray = [UIImage]()
var fileNameArray = [String]()
var fileManager = NSFileManager.defaultManager()
let compressedFile = NSTemporaryDirectory().stringByAppendingString("MyZipFiles")
let uncompressedFolder = NSTemporaryDirectory().stringByAppendingString("MyUnzippedFiles")
func unzipData(objectData: NSManagedObject){ // THIS IS BASICALLY NSDATA FROM CORE DATA FOR ME
let optData = NSData(data: objectData.valueForKey("image") as! NSData)
let success = fileManager.fileExistsAtPath(uncompressedFolder) as Bool // CREATES THE FOLDER IF IT DOESNT EXIST
if success == false {
do {
try! fileManager.createDirectoryAtPath(uncompressedFolder, withIntermediateDirectories: true, attributes: nil)
}
}
optData.writeToFile(compressedFile, atomically: true)
queue.addOperationWithBlock { () -> Void in
let operation1 = NSBlockOperation(block: {
SSZipArchive.unzipFileAtPath(self.compressedFile, toDestination: self.uncompressedFolder)
})
operation1.completionBlock = {
if queue.operationCount == 0 {
dispatch_async(dispatch_get_main_queue(), {
if queue.operationCount == 0 {
self.retrieveFiles()
}
})
}
}
queue.addOperation(operation1)
}
}
func retrieveFiles() {
do {
let filelist = try fileManager.contentsOfDirectoryAtPath(uncompressedFolder)
print(filelist)
print("filename")
for filename in filelist {
self.fileNameArray.append(filename)
}
} catch let error as NSError {
print("Could not save \(error)")
}
do {
for item in fileNameArray {
print("item \(item)")
let imagePath = uncompressedFolder.stringByAppendingString("/\(item)")
imageArray.append(UIImage(contentsOfFile: imagePath)!)
}
print("filename array \(fileNameArray)")
print("image array \(imageArray)")
unzipDelegate!.unzipSet(imageArray)
} catch {
}
}
}
and to delete the temp file/folder after use, so that it can be reused without any old documents remaining
var fileManager = NSFileManager.defaultManager()
let compressedFile = NSTemporaryDirectory().stringByAppendingString("MyZipFiles")
let uncompressedFolder = NSTemporaryDirectory().stringByAppendingString("MyUnzippedFiles")
do {
try fileManager.removeItemAtPath(compressedFile)
try fileManager.removeItemAtPath(uncompressedFolder)
} catch let error as NSError {
print("Could not save \(error)")
}

NSFileManager.defaultManager().removeItemAtPath removes file only once app terminates

So I am using the methods bellow to handle getting, deleting, and saving images for my app. When I call removeImage it succeeds and when I use NSFileManager.defaultManager().fileExistsAtPath it says the file does not exist. However, when I call getImage it can still grab the image even though it has been deleted. When I quite the app and start it up again getImage works as expected until I use removeImage. I have also tried wrapping the removeImage call in dispatch_async(dispatch_get_main_queue(),{}) and it still doesn't work.
My code:
class func removeImage(user:User){
let context = getManagedObjectContext()
context.performBlockAndWait({
guard let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) as [String]! where paths.count > 0 else{
return
}
do{
if let dirPath = paths[0] as String!{
let path = "\(user.id)_\(user.name).png"
let readPath = (dirPath as NSString).stringByAppendingPathComponent(path)
try NSFileManager.defaultManager().removeItemAtPath(readPath)
}
}catch{
}
})
}
class func saveImage(user:User,image:UIImage){
let path = "\(user.id)_\(user.name).png"
guard let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) as [String]! where paths.count > 0 else{
return
}
if let dirPath = paths[0] as String!{
let writePath = (dirPath as NSString).stringByAppendingPathComponent(path)
UIImagePNGRepresentation(image)!.writeToFile(writePath, atomically: true)
}
}
class func getImage(user:User)->UIImage?{
let path = "\(user.id)_\(user.name).png"
guard let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) as [String]! where paths.count > 0 else{
return nil
}
if let dirPath = paths[0] as String!{
let readPath = (dirPath as NSString).stringByAppendingPathComponent(path)
return UIImage(named: readPath)
}
return nil
}
UPDATE/FIX! Changed code to this and it worked:
class func removeImage(user:User){
let manager = NSFileManager.defaultManager()
do{
let directoryURL = try manager.URLForDirectory(.DocumentationDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
if #available(iOS 9.0, *) {
let url = NSURL(fileURLWithPath: "\(user.id)_\(user.name).png", relativeToURL: directoryURL)
try manager.removeItemAtURL(url)
} else {
let url = directoryURL.URLByAppendingPathComponent("\(user.id)_\(user.name).png")
try manager.removeItemAtURL(url)
}
}catch{
}
}
class func saveImage(user:User,image:UIImage){
let manager = NSFileManager.defaultManager()
do{
let directoryURL = try manager.URLForDirectory(.DocumentationDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
if #available(iOS 9.0, *) {
let url = NSURL(fileURLWithPath: "\(user.id)_\(user.name).png", relativeToURL: directoryURL)
UIImagePNGRepresentation(image)!.writeToURL(url, atomically: true)
} else {
let url = directoryURL.URLByAppendingPathComponent("\(user.id)_\(user.name).png")
UIImagePNGRepresentation(image)!.writeToURL(url, atomically: true)
}
}catch{
}
}
class func getImage(user:User)->UIImage?{
let manager = NSFileManager.defaultManager()
do{
let directoryURL = try manager.URLForDirectory(.DocumentationDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
if #available(iOS 9.0, *) {
let url = NSURL(fileURLWithPath: "\(user.id)_\(user.name).png", relativeToURL: directoryURL)
if let data = NSData(contentsOfURL: url){
return UIImage(data: data)
}
} else {
let url = directoryURL.URLByAppendingPathComponent("\(user.id)_\(user.name).png")
if let data = NSData(contentsOfURL: url){
return UIImage(data: data)
}
}
}catch{
}
return nil
}

Write and Read a plist in swift with simple data

i'm trying to understand how to save a simple value, an integer, in a plist.
but i'm finding on the net only solution for save dictionary and array and i don't understand what i can change to work it only for an integer.
this is the code for the moment...
var musicalChoice = 1
var musicString : String = "5"
override func viewDidLoad() {
super.viewDidLoad()
musicString = String(musicalChoice)}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func writePlist() {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as NSString
let path = documentsDirectory.stringByAppendingPathComponent("Preferences.plist")
musicString.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error:nil )
}
func readPlist() {
}
Update for Swift 4
I have created SwiftyPlistManager. Take a look at it on GiHub and follow these video instructions:
https://www.youtube.com/playlist?list=PL_csAAO9PQ8bKg79CX5PEfn886SMMDj3j
Update for Swift 3.1
let BedroomFloorKey = "BedroomFloor"
let BedroomWallKey = "BedroomWall"
var bedroomFloorID: Any = 101
var bedroomWallID: Any = 101
func loadGameData() {
// getting path to GameData.plist
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
let documentsDirectory = paths.object(at: 0) as! NSString
let path = documentsDirectory.appendingPathComponent("GameData.plist")
let fileManager = FileManager.default
//check if file exists
if !fileManager.fileExists(atPath: path) {
guard let bundlePath = Bundle.main.path(forResource: "GameData", ofType: "plist") else { return }
do {
try fileManager.copyItem(atPath: bundlePath, toPath: path)
} catch let error as NSError {
print("Unable to copy file. ERROR: \(error.localizedDescription)")
}
}
let resultDictionary = NSMutableDictionary(contentsOfFile: path)
print("Loaded GameData.plist file is --> \(resultDictionary?.description ?? "")")
let myDict = NSDictionary(contentsOfFile: path)
if let dict = myDict {
//loading values
bedroomFloorID = dict.object(forKey: BedroomFloorKey)!
bedroomWallID = dict.object(forKey: BedroomWallKey)!
//...
} else {
print("WARNING: Couldn't create dictionary from GameData.plist! Default values will be used!")
}
}
func saveGameData() {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
let documentsDirectory = paths.object(at: 0) as! NSString
let path = documentsDirectory.appendingPathComponent("GameData.plist")
let dict: NSMutableDictionary = ["XInitializerItem": "DoNotEverChangeMe"]
//saving values
dict.setObject(bedroomFloorID, forKey: BedroomFloorKey as NSCopying)
dict.setObject(bedroomWallID, forKey: BedroomWallKey as NSCopying)
//...
//writing to GameData.plist
dict.write(toFile: path, atomically: false)
let resultDictionary = NSMutableDictionary(contentsOfFile: path)
print("Saved GameData.plist file is --> \(resultDictionary?.description ?? "")")
}
Here's what I use to read/write a plist file in swift:
let BedroomFloorKey = "BedroomFloor"
let BedroomWallKey = "BedroomWall"
var bedroomFloorID: AnyObject = 101
var bedroomWallID: AnyObject = 101
func loadGameData() {
// getting path to GameData.plist
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths[0] as String
let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")
let fileManager = NSFileManager.defaultManager()
//check if file exists
if(!fileManager.fileExistsAtPath(path)) {
// If it doesn't, copy it from the default file in the Bundle
if let bundlePath = NSBundle.mainBundle().pathForResource("GameData", ofType: "plist") {
let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
println("Bundle GameData.plist file is --> \(resultDictionary?.description)")
fileManager.copyItemAtPath(bundlePath, toPath: path, error: nil)
println("copy")
} else {
println("GameData.plist not found. Please, make sure it is part of the bundle.")
}
} else {
println("GameData.plist already exits at path.")
// use this to delete file from documents directory
//fileManager.removeItemAtPath(path, error: nil)
}
let resultDictionary = NSMutableDictionary(contentsOfFile: path)
println("Loaded GameData.plist file is --> \(resultDictionary?.description)")
var myDict = NSDictionary(contentsOfFile: path)
if let dict = myDict {
//loading values
bedroomFloorID = dict.objectForKey(BedroomFloorKey)!
bedroomWallID = dict.objectForKey(BedroomWallKey)!
//...
} else {
println("WARNING: Couldn't create dictionary from GameData.plist! Default values will be used!")
}
}
func saveGameData() {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as NSString
let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")
var dict: NSMutableDictionary = ["XInitializerItem": "DoNotEverChangeMe"]
//saving values
dict.setObject(bedroomFloorID, forKey: BedroomFloorKey)
dict.setObject(bedroomWallID, forKey: BedroomWallKey)
//...
//writing to GameData.plist
dict.writeToFile(path, atomically: false)
let resultDictionary = NSMutableDictionary(contentsOfFile: path)
println("Saved GameData.plist file is --> \(resultDictionary?.description)")
}
The plist file is this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BedroomFloor</key>
<integer>101</integer>
<key>BedroomWall</key>
<integer>101</integer>
<key>XInitializerItem</key>
<string>DoNotEverChangeMe</string>
</dict>
</plist>
My variant function to read and write .plist on swift, tested on device.
Exapmle:
var dataVersion = readPlist("Options", key: "dataVersion")
writePlist("Options", key: "dataVersion", data: 1.23)
Function:
func readPlist(namePlist: String, key: String) -> AnyObject{
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as! NSString
let path = documentsDirectory.stringByAppendingPathComponent(namePlist+".plist")
var output:AnyObject = false
if let dict = NSMutableDictionary(contentsOfFile: path){
output = dict.objectForKey(key)!
}else{
if let privPath = NSBundle.mainBundle().pathForResource(namePlist, ofType: "plist"){
if let dict = NSMutableDictionary(contentsOfFile: privPath){
output = dict.objectForKey(key)!
}else{
output = false
println("error_read")
}
}else{
output = false
println("error_read")
}
}
return output
}
func writePlist(namePlist: String, key: String, data: AnyObject){
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as! NSString
let path = documentsDirectory.stringByAppendingPathComponent(namePlist+".plist")
if let dict = NSMutableDictionary(contentsOfFile: path){
dict.setObject(data, forKey: key)
if dict.writeToFile(path, atomically: true){
println("plist_write")
}else{
println("plist_write_error")
}
}else{
if let privPath = NSBundle.mainBundle().pathForResource(namePlist, ofType: "plist"){
if let dict = NSMutableDictionary(contentsOfFile: privPath){
dict.setObject(data, forKey: key)
if dict.writeToFile(path, atomically: true){
println("plist_write")
}else{
println("plist_write_error")
}
}else{
println("plist_write")
}
}else{
println("error_find_plist")
}
}
}
You can't have anything other than an array or dictionary as the root object in a plist. This is because plist files are essentially special xml files so when you are trying to read the file you ask for object at key or object at index, otherwise you have no means of obtaining your data. Also, when inserting numbers into a plist, you must wrap them in the NSNumber class. To save your objects, check out this answer.