• Skip to main content
  • Skip to primary sidebar

Ravi Shankar

Tweaking Apps

  • About
  • Portfolio
  • Privacy Policy

UICollectionView

Search photos on Flickr – Web Service

August 11, 2015 By Ravi Shankar 1 Comment

In this tutorial we will see the steps required to write a demo app that retrieves photos from Flickr based on search text and display them in a UICollectionView. This also covers how to integrate 3rd party libaries using CocoaPods.

Flickr API

Register your app in Flickr and get the API key details. You will need the API key to access the Flickr Photo Search API.

Project Setup

Create a new project by selecting Single View Application template and selecting language as Swift.

Install 3rd Party Libraries

We will be using CocoaPods to install third party libraries. First make sure to install CocoaPods on your Mac. Launch terminal window, navigate to the newly created project folder and create a file with name as Podfile. Edit the Podfile and add the following content

use_frameworks!
pod ‘Alamofire’
pod ‘SwiftyJSON’
pod ‘Haneke’

Alamorfire, SwiftyJSON and Haneke are the thirdparty libraries that will be used in this project. Alamofire for WebSerice call, SwiftJSON for parsing JSON data and Haneke for caching images.

After adiding the required libraries, type pod install on the terminal window. This should install the required libraries and create the necessary workspace. Now open <Project Name>.xcworkspace to add the functionality to the project.

Model Class

Add a new file (Photo.swift) to act as a place holder for storing photo details. Photo struct has properties for id, title, farm, secret, server and computed property which constructs the URL of the photo.

[code language=”swift”]
import UIKit

struct Photo {
var id: String
var title: String
var farm: String
var secret: String
var server: String
var imageURL: NSURL {
get {
let url = NSURL(string: "http://farm\(farm).staticflickr.com/\(server)/\(id)_\(secret)_m.jpg")!
return url
}
}
}
[/code]

 

Web Service Integration

Add new Swift file to the project and provide a name as Services.swift. Add the following code snippet to Services.swift

[code language=”swift”]import Alamofire
import SwiftyJSON

protocol FlickrPhotoDownloadDelegate {
func finishedDownloading(photos:[Photo])
}

class Services {

let API_KEY = “"
let URL = "https://api.flickr.com/services/rest/"
let METHOD = "flickr.photos.search"
let FORMAT_TYPE:String = "json"
let JSON_CALLBACK:Int = 1
let PRIVACY_FILTER:Int = 1

var delegate:FlickrPhotoDownloadDelegate?

// MARK:- Service Call

func makeServiceCall(searchText: String) {

Alamofire.request(.GET, URL, parameters: ["method": METHOD, "api_key": API_KEY, "tags":searchText,"privacy_filter":PRIVACY_FILTER, "format":FORMAT_TYPE, "nojsoncallback": JSON_CALLBACK])
.responseJSON { (request, response, data, error) in
if data != nil {
let jsonData:JSON = JSON(data!)
let photosDict = jsonData["photos"]
let photoArray = photosDict["photo"]
var photos = [Photo]()

for item in photoArray {
let id = item.1["id"].stringValue
let farm = item.1["farm"].stringValue
let server = item.1["server"].stringValue
let secret = item.1["secret"].stringValue
let title = item.1["title"].stringValue
let photo = Photo(id:id, title:title, farm:farm, secret: secret, server: server)
photos.append(photo)
}
self.delegate?.finishedDownloading(photos)
} else {
println(error)
}
}

}
}
[/code]

The above code does the following

  • Makes a web service call to the flickr photo search API using Alamofire third party library.
  • Web Service results are parsed using SwiftyJSON library. 
  • The delegates are notified about the completion of the download by pasisng the photos array.

Design User Intrerfaces

Navigate to Main.storyboard, add a UICollectionView and UISearchBar to the ViewController as shown in the below screenshot.

Make sure add Auto Layout constriants so that the UI looks good for both iPad and iPhone. If you need help with Auto Layout then check out this tutorial.

As shown in the above screenshot, you need to add UIImageView to the CollectionViewCell. Now embed this ViewController inside Navigation Controller using the Editor -> Embed In -> Navigation Controller menu option.

Add another second View Controller to the Storyboard which would act as the Detail View Controller for displaying selected Photo.

Add Custom Cell

Create a new file (PhotoCell.swift) by selecting CocoaTouch class and keeping the base class as UICollectionViewCell. Set this class as the Custom Class for UICollectionViewCell in the Interface builder. Then create IBOutlet for the imageView in PhotoCell.

[code language=”swift”]
import UIKit

class PhotoCell: UICollectionViewCell {

@IBOutlet weak var imageView: UIImageView!

}
[/code]

 

Add PhotosViewController

 

You can rename the existing ViewController.swift to PhotosViewController.swift file. In the storyboard, select the ViewController with CollectionView and set the custom class name to PhotosViewController.

Create IBOutlets for UISearchBar and UICollectionView in PhotosViewController.

[code language=”swift”]@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var collectionView: UICollectionView!
[/code]

Implement the SearchBar delegate method and service call for searching photos based on the entered Search Text.

[code language=”swift”]// MARK:- SearchButton

func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchForPhotos()
searchBar .resignFirstResponder()
}

// MARK:- SearchPhotos

func searchForPhotos() {
service.makeServiceCall(searchBar.text)
}
[/code]

Also add the following code snippet that processes the downloaded photos returned from the web service call. All UI calls needs to be done in the main thread hence setting the photos instance variable and update CollectionView are done within dispatch_async(dispatch_get_main_queue()).

[code language=”swift”]// MARK:- Flickr Photo Download
func finishedDownloading(photos: [Photo]) {
dispatch_async(dispatch_get_main_queue(), { () -&gt; Void in
self.photos = photos
self.collectionView?.reloadData()
})
}[/code]

Set the all the delegates and default value for the search bar in viewDidLoad method.

[code language=”swift”]override func viewDidLoad() {
super.viewDidLoad()

collectionView.dataSource = self
searchBar.delegate = self
collectionView.delegate = self
service.delegate = self

// default
searchBar.text = "famous quotes"
searchForPhotos()
}[/code]

Add CollectionViewDataSource methods

In the PhotosViewController add the CollecitonViewDataSource methods for displaying the photos. This can be done by adding an extension to the PhotosViewController class.

[code language=”swift”]extension PhotosViewController: UICollectionViewDataSource {
// MARK:- UICollectionViewDataSource methods

func numberOfSectionsInCollectionView(collectionView: UICollectionView) -&gt; Int {
return 1
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
return photos.count
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! PhotoCell
let photo = photos[indexPath.row]
cell.imageView.frame.size = cell.frame.size
cell.imageView.hnk_setImageFromURL(photo.imageURL)
return cell
}

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let photo:Photo? = photos[indexPath.row]
if let photo = photo {
let detailViewController = storyboard?.instantiateViewControllerWithIdentifier("DetailViewController") as! DetailViewController
detailViewController.photo = photo
presentViewController(detailViewController, animated: true, completion: nil)
}
}
}[/code]

The cellForItemAtIndexPath uses the custom cell (PhotoCell) for displaying the Photo. Also uses the thirdparty library Haneke to load the imageView. And in the didSelectItemAtIndexPath method add the code for calling the DetailViewController by passwing the selecting photo.

Finally in the PhotosViewController add the code that calcuates the Cell Size to be displayed on the CollecitonView. This is done by implementing the UICollectionViewDelegateFlowLayout method.

[code language=”swift”]extension PhotosViewController: UICollectionViewDelegateFlowLayout {
// MARK:- UICollectioViewDelegateFlowLayout methods

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -&gt; CGSize
{
let length = (UIScreen.mainScreen().bounds.width-15)/4
return CGSizeMake(length,length);
}
}
[/code]

Check out this article in stackoverflow for calculating the size of the CollectionViewCell.

Add DetailViewController

Add a new CocoaTouch class of Subclass as UIViewController with name as DetailViewController. Then add the following code to the class file.

[code language=”swift”]
import UIKit
import Haneke

class DetailViewController: UIViewController {

var photo:Photo?
var imageView:UIImageView?

override func viewDidLoad() {
super.viewDidLoad()

if let photo = photo {

imageView = UIImageView(frame: CGRectMake(0, 0, 320, 320))
imageView?.hnk_setImageFromURL(photo.imageURL)
view.addSubview(imageView!)

let tapGestureRecogonizer = UITapGestureRecognizer(target: self, action: Selector("close"))
view.addGestureRecognizer(tapGestureRecogonizer)
}
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

// MARK:- viewDidLayoutSubviews

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

let size = view.bounds.size
let imageSize = CGSizeMake(size.width,size.width)
imageView?.frame = CGRectMake(0.0, (size.height – imageSize.height)/2.0, imageSize.width, imageSize.height)

}
// MARK:- close
func close() {
dismissViewControllerAnimated(true, completion: nil)
}
}[/code]

The above code does the following

  • Calculates the size of the imageview and aligns it to the centre of the ViewController.
  • Loads the image using the third party library Haneke.
  • Adds a gesture recogonizer that dismisses the ViewContorller on tap gesture.

Dowload the source code from here.

Filed Under: Swift, UICollectionView, WebService, Xcode Tagged With: CocoaPods, Flickr, Photo

UICollectionView Demo in Swift

July 31, 2015 By Ravi Shankar

UICollectionView can be used for displaying set of data in rows and columns The main difference between UICollectionView and UITableView is that CollectionView can be display more than one column. The following topics are covered in this article

  • Simple collection view demo
  • Displaying data in Collection View
  • Implementiing Custom Cell 
  • Adding Section Headers
  • Highlighting Cell
  • Insert Cell
  • Delete Cells

Project Setup

Create a new project by selecting Single View Application template.

Provide the necessary details in the Project options screen and select the language as Swift.

Adding CollectionView

Let us first try out simple collection view to get a better understanding of how various components works. Then let us move on to a demo that displays various fruits grouped in different section. And you will be able insert and delete cells from the Collection View.

Navigate to Main.storyboard, disable Auto Layout and size classes using File Inspector option.

Then drag and drop CollectionView from object library to ViewController. The ViewController with CollectionView should look as shown below.

The square box inside collection view is UICollectionViewCell. Using Attributes Inspector, change the background colour of CollectionView to white. Then select UICollecitonViewCell and enter value for identifier as “CellIdentifier”

Using Assistant Editor, add an IBOutlet to CollectionView in ViewController.swlft file.

[code language=”swift”]@IBOutlet weak var collectionView: UICollectionView![/code]

Implement UICollectionViewDataSource methods

When the CollectionView loads, we need to specify the data for the cells. This can be done by implementing
UICollectionViewDataSource related methods. UICollectionViewDataSource protocols defines the following mandatory and optional methods.

[code language=”swift”]protocol UICollectionViewDataSource : NSObjectProtocol {

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int

// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell

optional func numberOfSectionsInCollectionView(collectionView: UICollectionView) -&gt; Int

// The view that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:
optional func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -&gt; UICollectionReusableView
}[/code]

First make sure to set the delegate property of collectionView to self in viewDidLoad function. Then add instance level property for storing Cell Identifier.

[code language=”swift”]let identifier = "CellIdentifier"

override func viewDidLoad() {
super.viewDidLoad()

collectionView.dataSource = self
}[/code]

Now add the implementation for mandatory methods numberOfItemsInSection and cellForItemAtIndexOath in ViewController.swlft. We can do this by adding an extension to ViewController class. Add this extension after the closing parenthesis of View Controller class.

[code language=”swift”]// MARK:- UICollectionViewDataSource Delegate
extension ViewController: UICollectionViewDataSource {

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
return 12
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier, forIndexPath: indexPath) as! UICollectionViewCell
cell.backgroundColor = UIColor.redColor()

return cell
}
}
[/code]

We have temporarily hard coded the number of items to be shown as 12. Using dequeReusableCellWithReuseIdentifier funciton, create cells based on index path. Then change the background color of cell to red. Now when you build and run the project, you should see collection view showing some cells as shown below.

If you want to have 3 rows and 4 columns then use the Collection View’s Size Inspector to make the appropriate changes to Cell Size and Minimum Spacing attributes.

If you Build and Run the project you should notice the changes.

Collection View DataSource

Now for the actual demo project, let us create a seperate class which will act as DataSource. Before creating a datasource, let us create a model class with file name as Fruit.swift. The implementation of the Fruit class should look as shown below

[code language=”swift”]class Fruit {
var name:String?
var group:String?

init(name: String, group: String) {
self.name = name
self.group = group
}
}
[/code]

 

Fruit struct is just a place holder for storing fruit related information. Now create another class for DataSource and name it as DataSource.swift. This class will provide the data related methods to the CollectionView. Durining the initialisation of the class, the data is read from plist and populated to fruits and groups array. Then using the respective helper methods the details will be retrieved by CollectionView.

[code language=”swift”]import Foundation

class DataSource {

init() {
populateData()
}

var fruits:[Fruit] = []
var groups:[String] = []

func numbeOfRowsInEachGroup(index: Int) -&gt; Int {
return fruitsInGroup(index).count
}

func numberOfGroups() -&gt; Int {
return groups.count
}

func gettGroupLabelAtIndex(index: Int) -&gt; String {
return groups[index]
}

// MARK:- Populate Data from plist

func populateData() {
if let path = NSBundle.mainBundle().pathForResource("fruits", ofType: "plist") {
if let dictArray = NSArray(contentsOfFile: path) {
for item in dictArray {
if let dict = item as? NSDictionary {
let name = dict["name"] as! String
let group = dict["group"] as! String

let fruit = Fruit(name: name, group: group)
if !contains(groups, group){
groups.append(group)
}
fruits.append(fruit)
}
}
}
}
}

// MARK:- FruitsForEachGroup

func fruitsInGroup(index: Int) -&gt; [Fruit] {
let item = groups[index]
let filteredFruits = fruits.filter { (fruit: Fruit) -&gt; Bool in
return fruit.group == item
}
return filteredFruits
}
}[/code]

Then add the required images to Images.xcassets, you can download the images for this project from GitHub.

Also add/create a new plist file which contains the information about the fruits and the group they belong to (download it from here).

Add Custom CollectionViewCell

For displaying image and caption in Collection View Cell, create a Custom Cell subclass of UICollectionViewCell. Provide name for the new file as Fruit Cell.

Navigate to Main.storyboard, select CollectionViewCell and using identity inspector set the class as FruitCell.

Drag and drop UIImageView and Label on to CollectionViewCell and add corresponding IBOutlets to FruitCell class.

[code language=”swift”]
import UIKit

class FruitCell: UICollectionViewCell {

@IBOutlet weak var caption: UILabel!
@IBOutlet weak var imageView: UIImageView!
}
[/code]

Display Data

We need to make changes to the ViewController extension for displaying the data form the DataSource with CustomCell. First Create an instance variable for DataSource in ViewController class

[code language=”swift”]let dataSource = DataSource()
[/code]

Then make the following changes to UICollectionViewDataSource extension to reflect the DataSource and FruitCell classes.

[code language=”swift”]
extension ViewController : UICollectionViewDataSource {

func numberOfSectionsInCollectionView(collectionView: UICollectionView) -&gt; Int {
return dataSource.groups.count
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
return dataSource.numbeOfRowsInEachGroup(section)
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier,forIndexPath:indexPath) as! FruitCell

let fruits: [Fruit] = dataSource.fruitsInGroup(indexPath.section)
let fruit = fruits[indexPath.row]

let name = fruit.name!

cell.imageView.image = UIImage(named: name.lowercaseString)
cell.caption.text = name.capitalizedString

return cell
}
}[/code]

Now if you build and run the project, you should see the colleciton view displaying fruits along with the caption.

The rows and columns are not properly aligned, we can fix this calculate the size of the cell based on height and width of collection view. Let us make the Collection View to display 2 cells per row. Navigate to Main,storyboard, update the Cell Size property to 182 as shown below.

Make sure to adjust the UIImageView and Label to fit the changed Collection View cell size. Now if you compile and run the project, the simulator should look as shown below.

Add Section Header

Headers for each can be added by implementing the viewForSupplementaryElementOfKind method defined as part of UICollectionViewDataSource protocol. We already have function in DataSource class that returns caption for each section. Let us add new Custom class for CollectionView section header and map this class to the header view in Interface builder.

Create FruitsHeaderView with subclass as UICollectionResuableView. Then navigate to Main.storyboard, select Collection View -> Attributes Inspector and enable Section Header under Accessories.

Now select the Section Header in the Collection View and set the class as FruitsHeaderView using Identity Inspector. In the Attributes Inspector enter the Identifier as HeaderView

Add UILabel to the header view to display the seciton title and corresponding IBOutlet to FruitsHeaderView class. You can also provide some background colour for the HeaderView,

[code language=”swift”]
import UIKit

class FruitsHeaderView: UICollectionReusableView {
@IBOutlet weak var sectionLabel: UILabel!
}
[/code]

Now add the following viewForSupplementaryElementOfKind implementation to the UICollectionViewDataSource extension in ViewController class.

[code language=”swift”] func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -&gt; UICollectionReusableView {

let headerView: FruitsHeaderView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: headerViewIdentifier, forIndexPath: indexPath) as! FruitsHeaderView

headerView.sectionLabel.text = dataSource.gettGroupLabelAtIndex(indexPath.section)
return headerView
}
[/code]

 

Make sure to add an instance variable let headerViewIdentifier = “HeaderView” in ViewController.class. In viewForSupplementaryElementOfKind function, we are creating an instance of FruitsHeaderView class using dequeueReusableSupplementaryViewOfKind function. Then set the section label by retrieving the caption from DataSource class. Build and run the app on iPhone simulator should show the following

Add Detail View

Now to add a detail View, let us first embed the ViewController in Navigation Controller. Then add another ViewController for using it as Detail View. Create a segue by Control + drag from CollectionView Cell to the new View Controller and select the Segue as Push.

Add UIImageView to the DetailViewController and centre align it to the View. Then add a new class (sub class of UIViewController) and name the file as DetailViewController

Map this class to the Second View Controller in the Interface builder. Then add the IBOutlet for the UIImageView in DetailViewController class.

@IBOutlet weak var imageView: UIImageView!

From the main View Controller, the selected Fruit needs to be passed to the DetailViewController class. Add a new property which is of type Fruit

[code language=”swift”]var fruit: Fruit?[/code]

In viewDidLoad method, add code to populate the title and image.

[code language=”swift”]if let fruit = fruit {
navigationItem.title = fruit.name?.capitalizedString
imageView.image = UIImage(named: fruit.name!.lowercaseString)
}[/code]

Navigate to ViewController.class and implement the prepareForSegue and getIndexPathForSelectedCell function.

[code language=”swift”]// MARK:- prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// retrieve selected cell &amp; fruit
if let indexPath = getIndexPathForSelectedCell() {

let fruit = dataSource.fruitsInGroup(indexPath.section)[indexPath.row]

let detailViewController = segue.destinationViewController as! DetailViewController
detailViewController.fruit = fruit
}
}

func getIndexPathForSelectedCell() -&gt; NSIndexPath? {

var indexPath:NSIndexPath?

if collectionView.indexPathsForSelectedItems().count &gt; 0 {
indexPath = collectionView.indexPathsForSelectedItems()[0] as? NSIndexPath
}
return indexPath
}
[/code]

In the above function using the selected Item indexPath the corresponding fruit is retrieved from DataSource class. Then this information is passed to the DetailViewController.

Highlight Selection

When the user taps any cell, it would nice to see the cell getting highlighted. This can be done by implementing following function as extension.

[code language=”swift”]// MARK:- UICollectionViewDelegate Methods

extension ViewController : UICollectionViewDelegate {
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
highlightCell(indexPath, flag: true)
}
}

func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
highlightCell(indexPath, flag: false)
}
}[/code]

Also make sure to add the collectionView.delegate = self to viewDidLoad function. Then add the following highlight function inside ViewController class.

[code language=”swift”]// MARK:- Highlight
func highlightCell(indexPath : NSIndexPath, flag: Bool) {

let cell = collectionView.cellForItemAtIndexPath(indexPath)

if flag {
cell?.contentView.backgroundColor = UIColor.magentaColor()
} else {
cell?.contentView.backgroundColor = nil
}
}
[/code]

 

Since we want to dehighlight the cell when the user returns from the DetailViewController. implement the viewDidAppear function with de-hightlight functionality.

[code language=”swift”]override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)

if let indexPath = getIndexPathForSelectedCell() {
highlightCell(indexPath, flag: false)
}
}
[/code]

Insert Cell

CollectionView provides insertItemsAtIndexPath method for adding new cell to CollectionView. Navigate to Main.storyboard, add new BarButtonItem to ViewController and set the Identifier as Add.

Add an IBAction to ViewController class and map it to the Add button. In the DataSource class add the following function which inserts new item to fruit model and returns the index.

[code language=”swift”]
// MARK:- Add Dummy Data
func addAndGetIndexForNewItem() -&gt; Int {

let fruit = Fruit(name: "SugarApple", group: "Morning")

let count = fruitsInGroup(0).count
let index = count &gt; 0 ? count – 1 : count
fruits.insert(fruit, atIndex: index)

return index
}
[/code]

Then modify the addNewItem IBAction method with the following piece of code.

[code language=”swift”] // MARK:- Add Cell
@IBAction func addNewItem(sender: AnyObject) {
let index = dataSource.addAndGetIndexForNewItem()
let indexPath = NSIndexPath(forItem: index, inSection: 0)
collectionView.insertItemsAtIndexPaths([indexPath])
}
[/code]

Delete Cell

Add Edit button to the navigation bar to allow users to perform delete operation. This can be done by adding the following line in viewDidLoad method.

[code language=”plain”]navigationItem.leftBarButtonItem = editButtonItem()[/code]

Then add a toolbar with button to delete the selected cell. Navigate to Main.storyboard, drag and drop toolbar on to View Controller. Add a BarButtonItem to the toolbar and select the identifier as Trash.

This toolbar should be displayed when the user taps on Edit button. Create an IBOutlet for the toolbar and add the following line to the viewDidLoad method.

[code language=”swift”]toolBar.hidden = true[/code]

Implement the setEditing function to enable or disable editing operation. In the below function, when editing is enabled, users will be allowed to select and delete multiple cells. The toolbar will be displayed or hidden based on editing flag.

[code language=”swift”]
// MARK:- Editing
override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
collectionView?.allowsMultipleSelection = editing
toolBar.hidden = !editing
}
[/code]

Now hook up Trash button in the Interface builder to IBAction for performing the delete operation. Add the following code snippet to deleteCells IBAction method. This first retrieves the indexpath for all the selected items. Then iterates through the indexpaths and to get the list of fruits to be deleted from model.

[code language=”swift”]
@IBAction func deleteCells(sender: AnyObject) {

var deletedFruits:[Fruit] = []

let indexpaths = collectionView?.indexPathsForSelectedItems()

if let indexpaths = indexpaths {

for item in indexpaths {
let cell = collectionView!.cellForItemAtIndexPath(item as! NSIndexPath)

collectionView?.deselectItemAtIndexPath(item as? NSIndexPath, animated: true)
// fruits for section
let sectionfruits = dataSource.fruitsInGroup(item.section)
deletedFruits.append(sectionfruits[item.row])
}

dataSource.deleteItems(deletedFruits)

collectionView?.deleteItemsAtIndexPaths(indexpaths)
}
}
[/code]

 

And in the DataSource class, add a function to delete fruits from the model. Also add an extension to array to get the index of the object based on the selected item (This will not be needed in Swift 2.0).

[code language=”swift”]
// MARK:- Delete Items
func deleteItems(items: [Fruit]) {

for item in items {
// remove item
let index = fruits.indexOfObject(item)
if index != -1 {
fruits.removeAtIndex(index)
}
}
}
[/code]

We need to cancel the segue operation when the edit operation is enabled, you can do this by implementing the following method in ViewController class.

[code language=”swift”]
// MARK:- Should Perform Segue
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -&gt; Bool {
return !editing
}[/code]

Download the source code from here

Filed Under: Swift, UICollectionView, Xcode Tagged With: Delete Cell, Insert Cell

Primary Sidebar

TwitterLinkedin

Recent Posts

  • How to know the size of the folders in iCloud
  • Errors were encountered while preparing your device
  • We have blocked all requests from this device – Firebase Phone Authentication
  • iPhone is not available error message in Xcode
  • Clear CocoaPods cache, re-download and reinstall all pods

Copyright 2021 © rshankar.com