Creating A Photo Gallery in Swift Using Firebase & INSPhotoGallery

Written by Josiassejod1 | Published 2019/04/11
Tech Story Tags: firebase | swift-photo-gallery | swift | create-a-photo-gallery | programming

TLDRvia the TL;DR App

I am currently building a travel app called i-Travel Journal and one of the functionalities that I wanted to add was the ability to allow users to upload and delete photos from a gallery. I was searching the internet for a blog post that not only used Firebase on the back-end, but also used the awesome INSPhotoGallery Pods Framework to get the job done, but to my dismay I could not find one that showed all the intricate details. Therefore, to help my fellow coder, I decided to put out a post to help someone get their photo gallery up and running.

To keep this blog post short, I will provide links to the Firebase Documentation to help you get started, if you do not have it already integrated into your application.

Firebase SDK iOS get started

Firebase Realtime Database get started

1. First Initialize A New View Controller & Initialize Delegates for UICollectionView

import UIKit
import Firebase
import FirebaseDatabase
import FirebaseFirestore

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UIImagePickerControllerDelegate{
var ref: DatabaseReference!
@IBOutlet weak var collectionView: UICollectionView?
 var URLs = []()
 lazy var gallery: [INSPhotoViewable] = []

    override func viewDidLoad() {
       collectionView!.delegate = self
       collectionView!.dataSource = self
    }
}

When you first initialize the class ViewController you will get a blank UIViewController class, we want to use a UICollectionView in order to display our gallery so we use the appropriate delegate method UICollectionViewDelegate along with the UICollectionViewDataSource for it in our view controller to override certain functionalities. We will also be using the UIImagePicker to select an image from the users gallery, so we use the UIImagePickerControllerDelegate.

There are also some variables that I initialized that we will be using later on.

The methods below are what we will using to implement the gallery along with some helper methods that I will be creating as well:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return gallery.count + 1

//Add the additional 1 to use it as the placeholder for the gallery selector image

}

func numberOfSections(in collectionView: UICollectionView) -> Int {

return 1
//We are only using one section of collections views for this example
//If you want to add filters to your gallery you could increase the section count

}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

}

func collectionView(_ collectionView: UICollectionView,

layout collectionViewLayout: UICollectionViewLayout,

sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize.init(width: 150, height: 150)
//This is the default size, you can change it to fit your needs

}

2. Hop Into Main.StoryBoard and Initialize Our UIViewController with our Components

Now that we have our methods stubbed out, we will now hop into the Main.Storyboard and setup our components. First we go and drag a ViewController from the list of components on the blank storyboard. On the side menu, we use the custom class tab and select the name of the custom view controller we just created, you can name it whatever you want, but make sure it is consistent across the app.

Next, we drag a UICollectionView on that ViewController, which will automatically create a UICollectionViewCell component underneath it, that we will use to display what we need for each individual row of the CollectionView.

For one cell in the UICollectionView, we want a UIImageView to display an image along with a delete button to remove the image. Therefore, in the cell that appeared I drag a UIImageView and a button component. I utilized auto layout constraints to position the button, you can place the button on any corner of the image, you can use your discretion. For the icon for the delete button, I got the icon from here, and dragged it in the Assets.xcassets file. I also used a placeholder thumbnail image for the cell used for the gallery image, you can use any image of your choice by tapping the UIImageView and selecting it on the side menu to the right, just make sure it is in the Assets folder.

3. Create A Custom UICollectionViewCell

import UIKit

class CustomUICollectionViewCell: UICollectionViewCell {

@IBOutlet weak var image: UIImageView!

@IBOutlet weak var delete: UIButton!

}

Now that we have the structure of what we want one UICollectionViewCell to look like, we need to create a custom class to mimic its structure. So what we do is create our own.

Now that we have created the class, we hop back in our Main.Storyboard class and begin to connect the custom class we just created to the UICollectionViewCell components we had just drag and drop by going to the side panel on the right and selecting it.

Next, we begin to connect the UIImage and Buttons that we just created in the Custom Class. We also want to give the UICollectionViewCell a unique name so that we can use it in the code later, so set it in the following menu as so.

4. We Return To Our Helper Methods & Delegate Methods

Now that we have done all the work connecting that we needed to do on the Storyboard and in code through custom classes, we can now begin to manipulate the methods we created earlier.

First and foremost, take a glance at the following documentation and install the Cocoa Pod for INSPhotoGallery. This is what we will be using to actually display the gallery when clicked.

Helper Methods (A Whole Heap of Them)

<a href="https://medium.com/media/1558d64e7e9e21fdbffdc1a72a1bc52d/href">https://medium.com/media/1558d64e7e9e21fdbffdc1a72a1bc52d/href</a>

These three helper method are the meat 🍖 and potatoes 🥔 of the application. Firebase is dope application and allows us to define the structure of the records that we would like to save to manipulate and retrieve it easily and freely. In order not to override all the images every time we add a new one, we have to try and structure it in a way that we can easily retrieve it like so:

-Gallery
   ID -> URL

Gallery-
5C3E4F78-FC18-46C7-8545-26D229861465:"https://firebasestorage.googleapis.com/v0/b/mytravelapp-e365b.appspot.com/o/gallery%2F6CE2EAA7-14B8-4820-9737-466FD95AA11E.jpg?alt=media&token=b621d365-aaee-4666-9817-d8dee0022afc"

Each image is under the gallery child, each child then has a unique id that points to a URL location in the Firebase Storage

FetchGallery

The fetch gallery method checks to see if there are any elements in Firebase that are of the child attribute gallery. It loops through and tries and populate the Gallery Array that we created earlier, but before we complete the operation, we want to prevent the gallery from showing duplicate records, before we call the imageToURL method. You can refer to Firebase Documentation to understand the syntax of how to query data.

Thus, it scans the Gallery to see if the accessibility Reference has any duplicates in the gallery using the contains method. Though the accessibility Reference is typically used to be a descriptive text for the image, we use it in this instance to uniquely keep track of the ID used in Firebase.

imageToURL

As seen in the INSPhotoGallery Documentation, they use an INSPhoto Object to initialize their gallery. To display each element thumbnail for UICollectionCell, we have to hit the URL provided by Firebase in order download the image and display it in the application. Therefore every time an element is added to the view, we refresh the CollectionView in order to update the UI with the newest image, this is why the DispatchQueue.main.async is used so that it activates on the main thread.

uploadImageToFirebase

This method is what actually handles the data that gets uploaded to Firebase. The goal is when a user selects an image from the UIImagePicker, they are instantly able to upload the data to Firebase. The data in the Realtime Database relies heavily on image being successfully uploaded to Firebase Storage. When an image is successfully uploaded, the completion handler will return a download url with the link to the actual image, which is appended to the existing Gallery Array. If there is any issues with the upload process, an alert will fire notifying the user using the following code:

func displayAlert( title: String, message: String){

let alert = UIAlertController.init(title: title , message: message

, preferredStyle: .alert)

let dismiss = UIAlertAction.init(title: "dismiss", style: .default, handler: nil)

alert.addAction(dismiss)

present(alert, animated: true, completion: nil)

}

CellForRowAt

<a href="https://medium.com/media/2cf22c54a9fbc6986557f676b309d29c/href">https://medium.com/media/2cf22c54a9fbc6986557f676b309d29c/href</a>

In this method, we are setting the view up for each cell that we see. IndexPath is what keeps track of the index number used to go through the array of cells that we have. Remember that custom cell name we created earlier? We use that to identify the structure of the cell custom components that we created.

Therefore, for the first cell row, I want the gallery image to be displayed, allow user to interact with the cell, and hide the delete button.

For all the other cells, I want the delete button to be displayed. I add a method called handle click, which I will talk in detail about later, which actually handles the deletion of the record if clicked.

handleClick

<a href="https://medium.com/media/f8dac202e5ef6e370be78e83fce6449c/href">https://medium.com/media/f8dac202e5ef6e370be78e83fce6449c/href</a>

This method is applied for each button that has a delete button attached to it. To prevent users from easily deleting element, I use a UIAlertController as a safe guard for users. If ‘Yes’ is selected, using the sender.tag applied using the IndexPath.row in the CellForItemAt method, the element is identified using the unique id passed through the accessibility Identifier, it finds the record in Firebase and set it to Nil. When an element is deleted from Firebase, a call to FetchGallery is made which updates the UI to remove the element. Fetch Gallery uses an observation handler, which once set, listens for any updates made to the records such as deleting, adding, or updating existing records.

DidSelectItemAt

<a href="https://medium.com/media/c1c3a7eac4ad22fba7441368db76a927/href">https://medium.com/media/c1c3a7eac4ad22fba7441368db76a927/href</a>

didSelectItemAt handles what happens when the user clicks on the image. If the index is 0, the image picker will display. I will talk more detail about that below. The magic of the INSPhotoGallery has not really been revealed, but this is where it shines now. Since I created a placeholder for the Gallery Image, the indexPath is offset by a value of 1, so in order to accurately show what the actual size of the array is I subtract the array’s total count by 1.

This is literally a copy and paste from the INSPhotoGallery documentation. In a nut shell, what their code is doing is looping through the index of the gallery array and checking if there are actually images in it. If there are images present, it displays it in full-size using a special View Controller that they have set up.

ImagePickerController

<a href="https://medium.com/media/66fc684f4357d9321fc17001885ef98f/href">https://medium.com/media/66fc684f4357d9321fc17001885ef98f/href</a>

This is the last and final part where it comes full circle, in order for there to be images upload, you need an image! In order to get that image, we use the UIImagePicker and allow the user the opportunity to pick an image from a gallery of there choice.

If the user successfully selects an image, we do two things simultaneously, we add the image to the Gallery array, then we use the storage reference to make a call to the uploadImageToFirebase method define above. After, we reload the collection view so that the new change can take place.

Conclusion

Today we created an image gallery using Firebase Realtime Database along with the Firebase Storage and a popular image gallery framework INSPhotoGallery. Though this may look complicated, you can get an appreciation for how quickly Firebase can be integrated into an application along with seeing a simple application of this uses.

I also invite you to try out the beta for my application I-Travel Journal. If you would like to help, test it out, and leave feedback at the following link. Thank you for reading my post check out my previous post for helpful information.


Published by HackerNoon on 2019/04/11