SnapShot: How to Create a Digital Scrapbook in iOS - Part 1

Caroline Baillie

When you're standing before the Great Wall of China, going out to lunch with friends, or even wandering through the middle of nowhere, don’t you want to snap a picture and easily keep track of all your adventures and experiences? Sure, you can take hundreds of photos on your phone, but there are always so many to go through. Wouldn’t it be nice to have a digital map filled with specific pictures for specific locations?

As a traveler and wanderer, I definitely wanted an app like this, and as a coder, I wanted to learn more about the iOS map feature. Inspired, I set out to create a sort of digital scrapbook that I call SnapShot. Today I want to share my newly gained experience through a tutorial, but first, here is a demo of the final product:

In this tutorial, I will be going over how to set up and use the amazing backend platform SashiDo (also used in my prior tutorial: Fish Classification iOS App with SashiDo and Teachable Machine) as well as going over the basic components of my app. Also, all my code is available on my GitHub. Before continuing, I recommend you have a Xcode installed and basic knowledge of swift.

Table of Contents

Podfile

As mentioned before, I used SashiDo’s backend platform to store user information. Because SashiDo uses Parse open-source technology to communicate with your app, you first must install the podfile:
     1. Create your Xcode project (I called mine snapShot)
     2. Go to terminal and enter your project’s folder
     3. Type sudo install cocoapods
     4. Then type pod init
     5. If you type ls you should see the following:
terminal1
     6. Type open -a TextEdit Podfile so that you can edit the file
     7. Modify the file to look like this:
podfile
     8. Save the file and return to terminal
     9. Type pod update
     10. Now if you type ls you should see all these files:
terminal2
     11. Type open snapShot.xcworkspace to open in Xcode
From now on you must open .xcworkspace, NOT .xcodeproj

SashiDo

Now we will actually set up the connection with SashiDo:
     1. Create an account with SashiDo
     2. Go to your dashboard
     3. Click Create New App and follow the instructions
     4. Once your app has been created, you should see a page saying Connect Applications With SashiDo
     5. Making sure swift is selected, copy the 6 lines at the bottom:
         a. If you are not shown this page or accidentally move past it, you can find it again by clicking Getting Started at the top of the menu on the left
sashiDo
If you had any trouble with this section, refer to the Getting Started Guide
     6. Next, go back to Xcode and open AppDelegate.swift
     7. Inside func application, paste the code you copied
     8. At the top of this file, add import Parse
     9. It should look like this (note: the line about the local datastore is not required):

application

To communicate with SashiDo, we will use Parse documentation. I will be going over some of the functions and calls I used, but it is also beneficial to refer to the Parse iOS Documentation. Additionally, to gain a more in-depth understanding, I found this video playlist on using parse for iOS development very useful.

Outline

Once you have the connection to SashiDo set up, it’s important to create an outline of your app. This diagram should contain all your controllers and the connections between them. It is also a good practice to color different types of controllers (in my case viewController=black, TableViewController=blue, and CollectionViewController=red).

outline
This is just the initial outline so your actual controllers might look or act differently.

Controller Setup

With this outline, you can now begin working on Xcode and adding the controllers:
     1. Inside the project folder, create a folder called viewControllers
     2. Go to Main.Storyboard
     3. Add the necessary (types of) controllers
     4. For each added controller create a swift file in the viewControllers folder with an appropriate name
     5. In the file, paste and modify this template code:

import Foundation
import UIKit
import MapKit
import Parse
import CoreLocation

class fileName: viewControllerType /*other types might be necessary depending on your usage of this class*/ {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

All these imports are not necessary for every controller, but it can’t hurt to have all of them.
     6. Under the corresponding controller, go to identity inspector and under class, select the swift file
     7. Copy the swift files name and paste it in Storyboard ID
namingFiles
     8. Add the necessary buttons, labels, images, etc.
         a. If your controller contains text inputs (e.g. login, signup, or newMemory), then I recommend adding a scrollView so the user can see all the input boxes
         b. Don’t add anything to the controller for the map (ViewController)
Now you should set up a navigationController to make movements between controllers smooth:
     1. Drag a navigationController onto the storyboard
     2. Under Attributes Inspector, check Is Initial View Controller
     3. Hover over the navigation controller, click control and drag your mouse to your first controller (e.g. login/signup screen)
     4. Release your mouse and select root view controller
     5. In settings.swift viewDidLoad, add the following code to keep the controller with navigation:

var objVC: UIViewController? = storyboard!.instantiateViewController(withIdentifier: "settings")
var aObjNavi = UINavigationController(rootViewController: objVC!)

From here you can create segues between view controllers (login/signup screen -> login controller) or wait to create these segues through code (login -> settings).
This is my final storyboard:

storyboard

Session Manager

The complexity of this app requires us to store information in a database (taken care of by SashiDo). However, we still need to request and send information from and to the database. To do this we will create a file called sessionManager (also used in my previous tutorial). sessionManager is a class that contains all the query functions that can then be accessed from any other file. The basic setup for this file is as follows:
     1. In snapShot, create a new folder called Classes
     2. In the this folder, create a new swift file called sessionManager
     3. Add this template code to sessionManager.swift:

import Foundation
import Parse
class sessionManager: NSObject {
    static let shared = sessionManager()
    override init() {
       super.init()
    }
}

     4. In this class we will:
         a. Create query functions
         b. Store global variables on the user and location
         c. Store a global array with all information from the database so we only need to send one request
This file will be used throughout the app so it is important to have a basic understanding of and to create this file at the beginning.

Registration

In most apps, you will need the user to create and use an account. SashiDo makes this process super easy!

Current User

In order to show individual information, I created a variable that kept track of the current user:
     1. In the Classes folder, create a new file called currentUser.swift
     2. Write this code:

import Foundation
import UIKit
import Parse

class currentUser : NSObject {
    var username:String
    var id:String
    
    init(username:String, id:String) {
        self.username = username
        self.id = id
    }
}

     3. In sessionManager.swift, add var user : currentUser! at the top
     4. This variable will be used in other functions in sessionManager

Signup

     1. You should have all the necessary text inputs (preferably in a scrollView)
     2. Connect these inputs (as an outlet) and the button (as an action) to its file (signup.swift)
     3. Add the function to dismiss the keyboard
     4. Inside the button action function (signupToggled):
         a. Display waiting spinner
         b. Create and save the user (Parse)
         c. Go to the next controller (settings)

import Foundation
import UIKit
import Parse

class signup: UIViewController {
    
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //get rid of keyboard when touch screen
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        usernameTextField.resignFirstResponder()
        passwordTextField.resignFirstResponder()
        emailTextField.resignFirstResponder()
    }

    @IBAction func signupToggled(_ sender: Any) {
        // loading icon
        self.showSpinner()
        // create new user
        let user = PFUser()
        user.username = usernameTextField.text!
        user.password = passwordTextField.text!
        user.email = emailTextField.text!
        // save user
        user.signUpInBackground { (result, error) in
            if error == nil && result == true {
                //successfully signed up
                // store current user
                let cUser = currentUser(username: user["username"] as! String, id: user.objectId!)
                sessionManager.shared.user = cUser
                //next screen
                let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "settings") as! settings
                self.navigationController?.pushViewController(secondViewController, animated: true)
            }
        }
    }
}

Login

     1. Same as sign up code but login rather than signup:

import Foundation
import UIKit
import Parse

class login: UIViewController {
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //get rid of keyboard when touch screen
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        usernameTextField.resignFirstResponder()
        passwordTextField.resignFirstResponder()
    }

    @IBAction func loginToggled(_ sender: Any) {
        // loading icon
        self.showSpinner()
        // login user
        PFUser.logInWithUsername(inBackground:usernameTextField.text!, password:passwordTextField.text!) {
          (user, error) -> Void in
          if user != nil {
            // successful
            // store current User
            var cUser = currentUser(username: user?["username"] as! String, id: user?.objectId as! String)
            sessionManager.shared.user = cUser
            // next controller
            let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "settings") as! settings
            self.navigationController?.pushViewController(secondViewController, animated: true)
          } else {
            // The login failed.
            print("incorrect username or password")
          }
        }
    }
}

Logout

To logout you can override the navigation back function on a chosen controller (settings.swift):
     1. In viewDidLoad:

//change back button name for navigation controller
let newBackButton = UIBarButtonItem(title: "Logout", style: UIBarButtonItem.Style.plain, target: self, action: #selector(settings.back(sender:)))
self.navigationItem.leftBarButtonItem = newBackButton

     2. In Class:

@objc func back(sender: UIBarButtonItem) {
    // logout
    PFUser.logOut()
    // go back to first viewController
    self.navigationController?.popToRootViewController(animated: true)
}

Part 2

This is only the beginning of a larger project. This mainly included the setup and basics, and in Part 2 we're getting more into the specifics of this project and all the maps functions.

Happy coding!

Resources

An Xcode Collection of Useful Functions and Tips
SnapShot: How to Create a Digital Scrapbook in iOS - Part 2
Video Demo
SnapShot GitHub Repo
SashiDo
Parse Documentation
Parse Video Playlist
Install Cocoapods

Caroline Baillie

A high school junior with a strong passion for computer science and engineering. Currently interning with SashiDo and creating tutorials using their incredible platform!

Find answers to all your questions

Our Frequently Asked Questions section is here to help.