user3069232
user3069232

Reputation: 8995

Trouble working with basic file system functionality in Swift 2.0

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...

Upvotes: 2

Views: 267

Answers (1)

Rob
Rob

Reputation: 437402

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)
        }
    }

}

Upvotes: 2

Related Questions