SnapShot: How to Create a Digital Scrapbook in iOS - Part 1
Tags: swift, ios, tutorial, github
Published: 2021-04-22 14:45:14

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:

{% youtube wTXN-c1tPHs %}
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*](https://dev.to/carolinebaillie/fish-classification-ios-app-with-sashido-and-teachable-machine-417i)) as well as going over the basic components of my app. Also, all my code is available on my [GitHub](https://github.com/CarolineBaillie/snapShot). Before continuing, I recommend you have a [Xcode](https://developer.apple.com/xcode/) installed and basic knowledge of [swift](https://developer.apple.com/swift/).

## Table of Contents
* [Podfile](#podfile)
* [SashiDo](#sashido)
* [Outline](#outline)
* [Controller Setup](#controller-setup)
* [Session Manager](#session-manager)
* [Registration](#registration)
   * [Current User](#current-user)
   * [Signup](#signup)
   * [Login](#login)
   * [Logout](#logout)
* [Part 2](#part-2)
* [Resources](#resources)

## 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](https://www.youtube.com/watch?v=BSYLs0wl5ME):
&nbsp;&nbsp;&nbsp;&nbsp; 1\. [Create](https://developer.apple.com/documentation/xcode/creating_an_xcode_project_for_an_app) your Xcode project (I called mine snapShot)
&nbsp;&nbsp;&nbsp;&nbsp; 2\. Go to terminal and enter your project’s folder
&nbsp;&nbsp;&nbsp;&nbsp; 3\. Type *sudo install cocoapods*
&nbsp;&nbsp;&nbsp;&nbsp; 4\. Then type *pod init*
&nbsp;&nbsp;&nbsp;&nbsp; 5\. If you type *ls* you should see the following:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6ucr9shk7gxjy9z5vtm.png)
&nbsp;&nbsp;&nbsp;&nbsp; 6\. Type *open -a TextEdit Podfile* so that you can edit the file
&nbsp;&nbsp;&nbsp;&nbsp; 7\. Modify the file to look like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1y6h0epvsiw3wzhbxrv.png)
&nbsp;&nbsp;&nbsp;&nbsp; 8\. Save the file and return to terminal
&nbsp;&nbsp;&nbsp;&nbsp; 9\. Type *pod update*
&nbsp;&nbsp;&nbsp;&nbsp; 10\. Now if you type ls you should see all these files:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjcc0ji5u0ljbajro0sx.png)
&nbsp;&nbsp;&nbsp;&nbsp; 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:
&nbsp;&nbsp;&nbsp;&nbsp; 1\. Create an account with [SashiDo](https://dashboard.sashido.io/register)
&nbsp;&nbsp;&nbsp;&nbsp; 2\. Go to your dashboard
&nbsp;&nbsp;&nbsp;&nbsp; 3\. Click <u>Create New App</u> and follow the instructions
&nbsp;&nbsp;&nbsp;&nbsp; 4\. Once your app has been created, you should see a page saying <u>Connect Applications With SashiDo</u>
&nbsp;&nbsp;&nbsp;&nbsp; 5\. Making sure swift is selected, copy the 6 lines at the bottom:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a\. If you are not shown this page or accidentally move past it, you can find it again by clicking <u>Getting Started</u> at the top of the menu on the left

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a04xokwthzrdo76if2ll.png)
If you had any trouble with this section, refer to the [Getting Started Guide](https://blog.sashido.io/sashidos-getting-started-guide/)
&nbsp;&nbsp;&nbsp;&nbsp; 6\. Next, go back to Xcode and open **AppDelegate.swift**
&nbsp;&nbsp;&nbsp;&nbsp; 7\. Inside <u>func application</u>, paste the code you copied
&nbsp;&nbsp;&nbsp;&nbsp; 8\. At the top of this file, add *import Parse*
&nbsp;&nbsp;&nbsp;&nbsp; 9\. It should look like this (note: the line about the local datastore is not required):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67m5qo6vqt575a3poe2i.png)

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](https://docs.parseplatform.org/ios/guide/). Additionally, to gain a more in-depth understanding, I found this [video playlist](https://www.youtube.com/playlist?list=PLMRqhzcHGw1ZFjFyHGJTTPuvcLbwVCuG4) 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).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdeaftocgdfbcwuw4ieg.png)
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:
&nbsp;&nbsp;&nbsp;&nbsp; 1\. Inside the project folder, create a folder called *viewControllers*
&nbsp;&nbsp;&nbsp;&nbsp; 2\. Go to **Main.Storyboard**
&nbsp;&nbsp;&nbsp;&nbsp; 3\. Add the necessary (types of) controllers
&nbsp;&nbsp;&nbsp;&nbsp; 4\. For each added controller create a swift file in the *viewControllers* folder with an appropriate name
&nbsp;&nbsp;&nbsp;&nbsp; 5\. In the file, paste and modify this template code:
```swift
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.
&nbsp;&nbsp;&nbsp;&nbsp; 6\. Under the corresponding controller, go to <u>identity inspector</u> and under <u>class</u>, select the swift file
&nbsp;&nbsp;&nbsp;&nbsp; 7\. Copy the swift files name and paste it in <u>Storyboard ID</u>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8fmcxpy4czsgyzaq1ltz.png)
&nbsp;&nbsp;&nbsp;&nbsp; 8\. Add the necessary buttons, labels, images, etc.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a\. If your controller contains text inputs (e.g. login, signup, or newMemory), then I recommend adding a [scrollView](https://blog.sashido.io/xcode-collection-of-useful-functions-and-tips/) so the user can see all the input boxes
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b\. Don’t add anything to the controller for the map (ViewController)
Now you should set up a [navigationController](https://developer.apple.com/documentation/uikit/uinavigationcontroller) to make movements between controllers smooth:
&nbsp;&nbsp;&nbsp;&nbsp; 1\. Drag a navigationController onto the **storyboard**
&nbsp;&nbsp;&nbsp;&nbsp; 2\. Under <u>Attributes Inspector</u>, check <u>Is Initial View Controller</u>
&nbsp;&nbsp;&nbsp;&nbsp; 3\. Hover over the navigation controller, click <u>control</u> and drag your mouse to your first controller (e.g. login/signup screen)
&nbsp;&nbsp;&nbsp;&nbsp; 4\. Release your mouse and select <u>root view controller</u>
&nbsp;&nbsp;&nbsp;&nbsp; 5\. In **settings.swift** viewDidLoad, add the following code to keep the controller with navigation:
```swift
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:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13rdkx4i024a73vhor7d.png)

## Session Manager
The complexity of this app requires us to store information in a [database](https://blog.sashido.io/sashidos-getting-started-guide/#manageyourdatabaselikeapro) (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](https://dev.to/carolinebaillie/fish-classification-ios-app-with-sashido-and-teachable-machine-417i#session-manager)). 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:
&nbsp;&nbsp;&nbsp;&nbsp; 1\. In snapShot, create a new folder called <u>Classes</u>
&nbsp;&nbsp;&nbsp;&nbsp; 2\. In the this folder, create a new swift file called <u>sessionManager</u>
&nbsp;&nbsp;&nbsp;&nbsp; 3\. Add this template code to **sessionManager.swift**:
```swift
import Foundation
import Parse
class sessionManager: NSObject {
    static let shared = sessionManager()
    override init() {
       super.init()
    }
}
```
&nbsp;&nbsp;&nbsp;&nbsp; 4\. In this class we will:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a\. Create query functions
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b\. Store global variables on the user and location
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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:
&nbsp;&nbsp;&nbsp;&nbsp; 1\. In the <u>Classes</u> folder, create a new file called **currentUser.swift**
&nbsp;&nbsp;&nbsp;&nbsp; 2\. Write this code:
```swift
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
    }
}
```
&nbsp;&nbsp;&nbsp;&nbsp; 3\. In **sessionManager.swift**, add *var user : currentUser!* at the top
&nbsp;&nbsp;&nbsp;&nbsp; 4\. This variable will be used in other functions in sessionManager

### Signup
&nbsp;&nbsp;&nbsp;&nbsp; 1\. You should have all the necessary text inputs (preferably in a [scrollView](https://blog.sashido.io/xcode-collection-of-useful-functions-and-tips/))
&nbsp;&nbsp;&nbsp;&nbsp; 2\. [Connect](https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ConnectTheUIToCode.html) these inputs (as an outlet) and the button (as an action) to its file (**signup.swift**)
&nbsp;&nbsp;&nbsp;&nbsp; 3\. Add the function to [dismiss the keyboard](https://blog.sashido.io/xcode-collection-of-useful-functions-and-tips/)
&nbsp;&nbsp;&nbsp;&nbsp; 4\. Inside the button action function (signupToggled):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a\. Display [waiting spinner](https://blog.sashido.io/xcode-collection-of-useful-functions-and-tips/)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b\. Create and save the user ([Parse](https://docs.parseplatform.org/ios/guide/#users))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c\. Go to the next controller (settings)
```swift
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
&nbsp;&nbsp;&nbsp;&nbsp; 1\. Same as sign up code but login rather than signup:
```swift
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**):
&nbsp;&nbsp;&nbsp;&nbsp; 1\. In viewDidLoad:
```swift
//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
```
&nbsp;&nbsp;&nbsp;&nbsp; 2\. In Class:
```swift
@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 part 2 will go more into the specifics of this project and all the map functions. Check out Part 2 [here](https://blog.sashido.io/snapshot-how-to-create-a-digital-scrapbook-in-ios-part-2/)!

## Resources
An Xcode Collection of Useful Functions and Tips: https://blog.sashido.io/xcode-collection-of-useful-functions-and-tips/
Part 2: https://blog.sashido.io/snapshot-how-to-create-a-digital-scrapbook-in-ios-part-2/
SashiDo: https://www.sashido.io/en/
Parse Documentation: https://docs.parseplatform.org/ios/guide/
Parse Video Playlist: https://www.youtube.com/playlist?list=PLMRqhzcHGw1ZFjFyHGJTTPuvcLbwVCuG4
Install Cocoapods: https://www.youtube.com/watch?v=BSYLs0wl5ME
GitHub: https://github.com/CarolineBaillie/snapShot