[Swift 1] Day 15 - Code Exercise Solution


#21

The code from this tutorial works so might use it instead. https://github.com/tejas123/User-Interaction-with-Camera-using-UIImagePickerController-in-Swift-


#22

I have a version for show. I couldn’t get the image to load if you save different versions. If you just have a photo.jpg and it saves over it then it works. I did get it to save as csv file though and load too.
I implemented the camera app part so it works with either a camera or a UIImagepicker.

Things I didn’t get to do (due to time as I spent a lot of time on this already). File manager to delete files, format numbers to currency, format output of documents folder to a list which is easier to read and have some error correction for format of entry of price.

So overall bit disappointed but will come back to it after some more classes to see if I can fix other problems when I learn more. I am really excited for the next larger app challenge (don’t know how long that will take if this one took a week).

Image of save file and Xcode console
https://www.evernote.com/shard/s4/sh/070b3ada-cc8c-4484-af11-b4e96dac2e2b/ee5bea614abaa42f395794fc573bc259

gist code file


#23

Hi Paul,

I am really happy that I again seem to have succeeded in the code exercise. I created an application where you can load a photo from the saved photos library. It also allows you to add an item (holiday) and a cost. When you click on the save button it will save the photo into the documents folder as photo.jpg and create a text file named information.txt which contains: “Item,cost,photo filename”.

When the application launches it will look for the files in the document directory, when it finds them it will preload all items into the text fields and the image view. If the files are not there (or one of the two is missing) it will show empty text fields and an empty image view.

The things I had to find myself were:

  • getting only the file name of the image, I did this by using “imagePath.lastPathComponent”.
  • retrieving the individual text items from the CSV file, I did this with the “let textArr = split(loadedText!) {$0 == “,”}”

I also achieved to allow the user to tap the image view by using the code:

var tap = UITapGestureRecognizer(target: self, action: “imageTapped”)
imageView.addGestureRecognizer(tap)
imageView.userInteractionEnabled = true

In the function itself I do the same actions as I added to the save button pressed action.

Finally I also added an reset button which will make the text and image view values to “nil” and retrieves all the files from the document folder and then deletes those by using the function code:

   *var error: NSError? = nil*

    *let result = NSFileManager.defaultManager().contentsOfDirectoryAtPath(path, error: &error)*
    *var fullPath: String*
    *for name in result! {*
        *var fullPath = path + "/"+(name as! String)*
        *var result = NSFileManager.defaultManager().removeItemAtPath(fullPath, error: &error)*
    *}*

I will put the code I used below.

//
// ViewController.swift
// Inventory Tracker
//
// Created by Nico van der Linden on 19/06/15.
// Copyright © 2015 Noki-Online. All rights reserved.
//

import UIKit

func documentsDirectory() -> String {
let documentsFolderPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
return documentsFolderPath
}

func fileInDocumentsDirectory (filename: String) -> String {
return documentsDirectory().stringByAppendingPathComponent(filename)
}

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var itemTextField: UITextField!
@IBOutlet weak var costTextField: UITextField!

let imagePath = fileInDocumentsDirectory("photo.jpg")
let textPath = fileInDocumentsDirectory("information.txt")

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    
    // Load text if it is available
    let loadedText = loadTextFromPath(textPath)
    let loadedImage = loadImageFromPath(imagePath)
    var tap = UITapGestureRecognizer(target: self, action: "imageTapped")
    imageView.addGestureRecognizer(tap)
    imageView.userInteractionEnabled = true
    
    if loadedText != nil && loadedImage != nil {
        let textArr = split(loadedText!) {$0 == ","}

// println(“Loaded text: (loadedText!)”)
itemTextField.text = textArr[0]
costTextField.text = textArr[1]
imageView.image = loadedImage
}
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

@IBAction func selectImagePressed(sender: AnyObject) {
    
    var imagePicker = UIImagePickerController()
    var sourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum
    
    if UIImagePickerController.isSourceTypeAvailable(sourceType) {
        imagePicker.sourceType = sourceType
        imagePicker.delegate = self
        
        presentViewController(imagePicker, animated: true, completion: nil)
    }
    
}

@IBAction func saveButtonPressed(sender: AnyObject) {
    
    // Check if image is selected in the UI
    if imageView.image != nil {
        let result = saveImage(imageView.image!, path: imagePath)
    }
    
    let status = saveText("\(itemTextField.text),\(costTextField.text),\(imagePath.lastPathComponent)", path: textPath)

}

@IBAction func resetButtonPressed(sender: AnyObject) {
    removeFilesFromPath(documentsDirectory())
    itemTextField.text = nil
    costTextField.text = nil
    imageView.image = nil
}

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
    var image = info[UIImagePickerControllerOriginalImage] as! UIImage
    imageView.image = image
    dismissViewControllerAnimated(true, completion: nil)
}

func imagePickerControllerDidCancel(picker: UIImagePickerController) {
    dismissViewControllerAnimated(true, completion: nil)
}

func saveImage (image: UIImage, path: String) -> Bool {
    let jpgImageData = UIImageJPEGRepresentation(image, 1.0)
    let result = jpgImageData.writeToFile(path, atomically: true)
    return result
}

func loadTextFromPath (path: String) -> String? {
    var error: NSError? = nil
    let text = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: &error)

// if text == nil {
// println(“Error loading text from path (path) with error (error?.localizedDescription)”)
// }

    return text
}

func loadImageFromPath (path: String) -> UIImage? {
    let image = UIImage(contentsOfFile: path)

// if image == nil {
// println(“Missing image at path: (path)”)
// }
return image
}

func saveText (text: String, path: String) -> Bool {
    var error: NSError? = nil
    let status = text.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error: &error)
    
    if !status {
        println("Error saving file at path: \(path) with error \(error?.localizedDescription)")
    }
    
    return status
}

func removeFilesFromPath (path: String) {
    var error: NSError? = nil

    let result = NSFileManager.defaultManager().contentsOfDirectoryAtPath(path, error: &error)
    var fullPath: String
    for name in result! {
        var fullPath = path + "/"+(name as! String)
        var result = NSFileManager.defaultManager().removeItemAtPath(fullPath, error: &error)
    }

// println(“result: (result)”)

}

func imageTapped() {

    var imagePicker = UIImagePickerController()
    var sourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum
    
    if UIImagePickerController.isSourceTypeAvailable(sourceType) {
        imagePicker.sourceType = sourceType
        imagePicker.delegate = self
        
        presentViewController(imagePicker, animated: true, completion: nil)
    }
    
}

}


#24

The case is, that this isn’t a new folder :slight_smile: - XCode running the app changes the name of the directory, so finder just refreshes the folder name. All files inside Documents, created by the app are still there from run to run (at least for XCode 7.3)


#25

Yes that makes sense. It’s just confusing that the name keeps changing … even if it’s just a rename.