Trying to create a simple example code block in Swift 2.0 on iOS 9.1 using Xcode 7.1. Tried this article in techotopia; which I suspect is based on swift 1.2.
Made a few tiny changes so that it would compile & run, but although it appears to work, it doesn't seem to save my string into the file. Is there capability or something subtle I have missed here.
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textBox: UITextField!
var fileMgr: NSFileManager = NSFileManager.defaultManager()
var docsDir: String?
var dataFile: String?
var string: String = ""
override func viewDidLoad() {
super.viewDidLoad()
let dirPaths = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true)
docsDir = dirPaths[0] as String
let dataFile = NSURL(fileURLWithPath: docsDir!).URLByAppendingPathComponent("datafile.dat")
string = "\(dataFile)"
print(string)
if fileMgr.fileExistsAtPath(string) {
let databuffer = fileMgr.contentsAtPath(string)
let datastring = NSString(data: databuffer!,
encoding: NSUTF8StringEncoding)
textBox.text = datastring as? String
}
}
@IBAction func saveText(sender: AnyObject) {
let databuffer = (textBox.text)
let data = databuffer?.dataUsingEncoding(NSUTF8StringEncoding)
fileMgr.createFileAtPath(string, contents: data,
attributes: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
More testing; noticed I get this error when I try and create the file... error in __connection_block_invoke_2: Connection interrupted; which explains why it isn't working, if only I could workout what it is talking about?
Continued to try to debug; added UIFileSharingEnabled but cannot see Documents directory; added more code to test its presence, and create it if missing; fails telling me it is already there... even if it is evidently invisible...
When you do this, string
ends up being a string representation of the file URL, e.g. file://...
. That file://
prefix is a URL "scheme" (like http://
or ftp://
). But including the scheme at the start of the string means that this is not a valid path. You have to remove the scheme.
The easiest way to do this is to use the path
method to get the path from a NSURL
without that scheme. I'd also use URLForDirectory
to get the URL for the documents folder nowadays.
class ViewController: UIViewController {
@IBOutlet weak var textBox: UITextField!
lazy var fileMgr = NSFileManager.defaultManager()
var path: String!
override func viewDidLoad() {
super.viewDidLoad()
let documents = try! fileMgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
path = documents.URLByAppendingPathComponent("datafile.dat").path
if fileMgr.fileExistsAtPath(path) {
if let data = fileMgr.contentsAtPath(path) {
textBox.text = String(data: data, encoding: NSUTF8StringEncoding)
}
}
}
@IBAction func saveText(sender: AnyObject) {
let data = textBox.text?.dataUsingEncoding(NSUTF8StringEncoding)
fileMgr.createFileAtPath(path, contents: data, attributes: nil)
}
}
Or I might stay entirely in the world of URLs, retiring paths altogether, also using methods that throw meaningful error messages:
class ViewController: UIViewController {
@IBOutlet weak var textBox: UITextField!
lazy var fileMgr = NSFileManager.defaultManager()
var fileURL: NSURL!
override func viewDidLoad() {
super.viewDidLoad()
do {
let documents = try fileMgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
fileURL = documents.URLByAppendingPathComponent("datafile.dat")
var reachableError: NSError?
if fileURL.checkResourceIsReachableAndReturnError(&reachableError) {
textBox.text = try String(contentsOfURL: fileURL)
}
} catch {
print(error)
}
}
@IBAction func saveText(sender: AnyObject) {
do {
try textBox.text?.writeToURL(fileURL, atomically: true, encoding: NSUTF8StringEncoding)
} catch {
print(error)
}
}
}