Shrikar Archak

It does not matter how slow you go so long as you do not stop. ~Confucius

Swift iOS Tutorial: UISearchBar and UISearchBarDelegate

One of the important feature in an iOS application would be searching functionality, today we will be learning how to add search to our tableview application in Swift.

UISearchBar

The UISearchBar class implements a text field control for text-based searches. The control provides a text field for entering text, a search button, a bookmark button, and a cancel button. The UISearchBar object does not actually perform any searches. You use a delegate, an object conforming to the UISearchBarDelegate protocol, to implement the actions when text is entered and buttons are clicked. You can hide and show the cancel button by setting showsCancelButton to false or true.

UISearchBarDelegate

The UISearchBarDelegate protocol defines the optional methods you implement to make a UISearchBar control functional. A UISearchBar object provides the user interface for a search field on a bar, but it’s the application’s responsibility to implement the actions when buttons are tapped. At a minimum, the delegate needs to perform the actual search when text is entered in the text field.

The main function which we will be implementing are

delegate
1
2
optional func searchBar(_ searchBar: UISearchBar,
          textDidChange searchText: String)

We will maintain a boolean variable searchActive to decide if the search is in progress.

Steps to implement search

  • Create a single view application. images

  • Disable Size classes for now. images

  • Select the tableview and set the autolayout constraints to 0. images

Core Data Stack: Save and Fetch Entities

In the previous post we saw how to build a simple Core Data application. Also if you haven’t completed the previous post I would suggest you to look at them before continuing.

In this post we will provide users to add inventory and display all the existing inventory. Also the user will be able to scan the barcode and get necessary detail about that product.

The datamodel for the product will look like below.

images

Most of the data in the CoreDataStack is boilerplate code and is automatically generated. The most important function in our case is insertInventory which creates an entity in the managed object context and store it in the core data stack.

CoreDataStack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//
//  CoreDataStack.swift
//  SimplyBarcode
//
//  Created by Shrikar Archak on 2/8/15.
//  Copyright (c) 2015 Shrikar Archak. All rights reserved.
//

import Foundation
import CoreData

class CoreDataStack {
    lazy var applicationDocumentsDirectory: NSURL = {
        // The directory the application uses to store the Core Data store file. This code uses a directory named "com.shrikar.SimplyBarcode" in the application's documents Application Support directory.
        let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
        return urls[urls.count-1] as NSURL
        }()

    lazy var managedObjectModel: NSManagedObjectModel = {
        // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
        let modelURL = NSBundle.mainBundle().URLForResource("SimplyBarcode", withExtension: "momd")!
        return NSManagedObjectModel(contentsOfURL: modelURL)!
        }()

    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
        // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
        // Create the coordinator and store
        var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SimplyBarcode.sqlite")
        var error: NSError? = nil
        var failureReason = "There was an error creating or loading the application's saved data."
        if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
            coordinator = nil
            // Report any error we got.
            let dict = NSMutableDictionary()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
            dict[NSLocalizedFailureReasonErrorKey] = failureReason
            dict[NSUnderlyingErrorKey] = error
            error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
            // Replace this with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog("Unresolved error \(error), \(error!.userInfo)")
            abort()
        }

        return coordinator
        }()


    func insertInventory(productName : String, supplierName : String, quantity: Int, cost: Double, barcodeString: String,
        barcode: NSData) {
            let record = NSEntityDescription.insertNewObjectForEntityForName("Product", inManagedObjectContext: self.managedObjectContext!) as Product
            record.productName = productName
            record.supplierName = supplierName
            record.quantity = quantity
            record.cost = cost
            record.barcodeString = barcodeString
            record.barcode = barcode
            saveContext()
    }

    lazy var managedObjectContext: NSManagedObjectContext? = {
        // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
        let coordinator = self.persistentStoreCoordinator
        if coordinator == nil {
            return nil
        }
        var managedObjectContext = NSManagedObjectContext()
        managedObjectContext.persistentStoreCoordinator = coordinator
        return managedObjectContext
        }()

    // MARK: - Core Data Saving support

    func saveContext () {
        if let moc = self.managedObjectContext {
            var error: NSError? = nil
            if moc.hasChanges && !moc.save(&error) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                NSLog("Unresolved error \(error), \(error!.userInfo)")
                abort()
            }
        }
    }

}

Core Data Swift Tutorial

Core Data Features

Core Data framework provides a simple way of maintaining the life cycle of the objects and object graph management including persistence. Here are some of the main features of Core Data

  • Relationship maintenance
  • Core Data manage change propagation and maintain consistency of relationships among objects
  • Provides mechanism for schema migration.
  • Automatic support for storing objects in external data repositories
  • Sophisticated merge policies and conflict resolution

Core Data Terminologies

Managed Object Context

We can think of managed object context as a staging area for all the objects where modifications to the objects happen. The data store in the managed object context is not persisted in the persistent store.

We need to explicitly call the save on the context to persist the data.

Managed Objects

Model objects that tie into in the Core Data framework are known as managed objects. All managed objects must be registered with a managed object context. You add objects to the graph and remove objects from the graph using the context.

Fetch Requests

To retrieve data using a managed object context, you create a fetch request. A fetch request has three parts. * It should what type of entity data it should fetch * It may also contain a predicate object that specifies conditions that objects must match * An array of sort descriptor objects that specifies the order in which the objects should appear. Like you can specify that you want the latest created objects to appear first or sort by a name parameter withing the model

Persistent Stores

A given persistent object store is associated with a single file or other external data store and is ultimately responsible for mapping between data in that store and corresponding objects in a managed object context.

NSFetchedResultsController

If you are using core data with UITableView then this is the most useful class for that purpose. You use a fetched results controller to efficiently manage the results returned from a Core Data fetch request to provide data for a UITableView object.

You configure a fetch results controller using a fetch request that specifies the entity, an array containing at least one sort ordering, and optionally a filter predicate. The fetched results controller efficiently analyzes the result of the fetch request and computes all the information about sections in the result set. It also computes all the information for the index based on the result set.

In addition, fetched results controllers provide the following features:

Optionally monitor changes to objects in the associated managed object context and report changes in the results set to its delegate. We need to implement NSFetchedResultsControllerDelegate if we want to be notified when there are changes to the managed object context.

Troubleshooting

If you get an error like this: Unable to load class named ‘Menu’ for the entity ‘Menu’. Class not found, using default NSManagedObject instead.

Solution:

Swift classes are namespaced—they’re scoped to the module (typically, the project) they are compiled in. To use a Swift subclass of the NSManagedObject class with your Core Data model, prefix the class name in the Class field in the model entity inspector with the name of your module.

images

Xcode 6 Tutorial: Designing the iOS App Layout for Barcode Inventory App

SimpleBarcode : An app for inventory management

In January we learned how to build a Yik Yak Clone. This month we will be learning on how to build a simple barcode inventory app, and in doing so we will be learning about AVFoundation and Core Data which are some of the most important frameworks in iOS ecosystem. I have already put out the the first part of the tutorial which will help in implementing the barcode scanning functionality AVFoundation : Implementing barcode scanning in iOS8 with Swift if you haven’t completed that section I suggest you to complete it before going further.

Lets take a look at a few of the barcode scanning applications people are looking for and willing to pay you for that. So if you are planning to make some money building apps or just want to learn about iOS you are in the right place.

I am not saying that we will be building those apps. But we will be learning concepts which are necessary to build those applications. You might even ask why I am not building them myself. Its a valid question and at this point my focus is on different stuff.

So lets get started in building the app layout using Xcode 6 and interface builder. So if you have completed the first part there is only one blank view controller and nothing else. For this app we will build a simple tab bar application with two tabs . One tab for barcode scanning and the other one is for listing the inventory.

This would be the initial state

images

Select the view controller and embed in a tabbar controller also select the view controller and embed in navigation bar controller

images

AVFoundation : Implementing Barcode Scanning in iOS8 With Swift

In iOS 7 apple introduced support for reading MachineReadable Code(Barcodes). As of today it supports these machine formats for reading. Frameworks also provide core images filters to generate these barcodes. In this post we will implement the same for iOS 8 and Swift.

  • UPCE
  • Code39
  • Code39Mod43
  • EAN13
  • EAN8
  • Code93
  • Code128
  • PDF417
  • QR
  • Aztec
  • Interleaved2of5
  • ITF14
  • DataMatrix

This is how the final example will work.

To implement barcode scanning in our app we need to have some idea about how AVFoundation works.

AVCaptureSession

AVCaptureSession is one of the key object that will help in managing the data flow from the capture stage through our input devices like camera/mic to output like a movie file. We can also provide custom presets which will control the quality/bitrate of the output.

AVCaptureDevice

An AVCaptureDevice object represents a physical capture device and the properties associated with that device. You use a capture device to configure the properties of the underlying hardware. A capture device also provides input data (such as audio or video) to an AVCaptureSession object. We also have the flexibility to set the properties on the input device like (focus, exposure etc) but the should be done while having a lock on that particular device object

AVCaptureInputDevice

AVCaptureInputDevice is useful for capturing the data from the input device.

AVCaptureVideoPreviewLayer

AVCaptureVideoPreviewLayer is special CGlayer which will help us display the data as captured from our input device

Here is the flow on how the start capturing input from the device.