No errors are showing because you're catching the error and not doing anything. Add print(error)
in the catch
block:
do {
try cardRow.writeToURL(NSURL(fileURLWithPath: path!), atomically: false, encoding: NSUTF8StringEncoding)
}
catch {
print(error)
}
The issue is that you're trying to write to a file in the bundle, but the bundle is read-only. You should try writing to the Documents folder:
let fileURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
.URLByAppendingPathComponent("cardsFile.csv")
By the way, writeToFile
will replace the output file. If you want to write data to a file, appending data as you go along, you might want to use NSOutputStream
:
let fileURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false).URLByAppendingPathComponent("cardsFile.csv")
guard let stream = NSOutputStream(URL: fileURL, append: false) else {
print("unable to open file")
return
}
stream.open()
for card in cards {
let data = "\(card.front),\(card.back)\n".dataUsingEncoding(NSUTF8StringEncoding)!
guard stream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length) > 0 else {
print("unable to write to file")
break
}
}
stream.close()
If the goal is to just save this locally, I wouldn't use a CSV format. I'd use a native format, such as a NSKeyedArchiver
instead. So, first making Card
conform to the NSCoding
protocol by implementing init?(coder:)
and encodeWithCoder()
:
class Card: NSObject, NSCoding {
let front: String
let back: String
init(front: String, back: String) {
self.front = front
self.back = back
super.init()
}
required convenience init?(coder aDecoder: NSCoder) {
guard let front = aDecoder.decodeObjectForKey("front") as? String else { return nil }
guard let back = aDecoder.decodeObjectForKey("back") as? String else { return nil }
self.init(front: front, back: back)
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(front, forKey: "front")
aCoder.encodeObject(back, forKey: "back")
}
override var description: String { get { return "<Card front=\(front); back=\(back)>" } }
}
Then, when you want to save:
let fileURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
.URLByAppendingPathComponent("cardsFile.bplist")
if !NSKeyedArchiver.archiveRootObject(cards, toFile: fileURL.path!) {
print("error saving archive")
}
And when you want to read it from the file:
guard let cards2 = NSKeyedUnarchiver.unarchiveObjectWithFile(fileURL.path!) as? [Card] else {
print("problem reading archive")
return
}
print(cards2)