The Basic Meeting List Toolbox

Our First Search

NOTE: In this page, we will introduce The DemoSimpleBMLTiOSLibClient project. This is an extremely simple “straight out of the box” project that has no purpose on this Earth other than to demonstrate the BMLTiOSLib in its most simplistic form. The app has very little character, minimal error checking, and no “eye candy” at all. The code is deliberately spartan and ugly, as it will be explained in these pages. It will not have a repo; but will be provided as inline zip files as the discussion progresses.
ALSO NOTE: This will not use the CocoaPods version. This is an older version, but will be completely fine for demonstrating the issues we’re dealing with.

The BMLTiOSLib Class

In this page, we’ll explore the BMLTiOSLib class a bit further. It’s the principal interface to the system, and the “gateway” to the Root Server. Everything you do to access the Root Server will be done via an instance of this class.

In the Beginning…

As mentioned in an earlier page, everything starts with an instance of

BMLTiOSLib

. The process begins by a simple instantiation, like so:

import UIKit
import BMLTiOSLib

class ViewController : UIViewController, BMLTiOSLibDelegate {
    var _libraryInstance: BMLTiOSLib! = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // This is a string that points to a VALID Root Server instance
        // (>=10.2.8.1 running HTTPS, and with most of its data fields unmodified from default).
        let rootServerURI = "https://tkddevel.com/bmltwork/bmlt/main_server/"
        
        // Create an instance of the class. This immediately begins a communication process with the Root Server,
        // and the callbacks will be the next course of action.
        self._libraryInstance = BMLTiOSLib(inRootServerURI: rootServerURI, inDelegate: self)
    }
    
    // These are the required callback functions for the BMLTiOSLibDelegate class.
    
    // This is called upon successful connection and querying of the Root Server (or unsuccessful)
    func bmltLibInstance(_ inLibInstance: BMLTiOSLib, serverIsValid: Bool) {
        let alertController = UIAlertController(title: (serverIsValid ? "EXCELLENT!" : "BOGUS!"), message: "The initialization has completed.", preferredStyle: .alert)
        
        let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
        
        alertController.addAction(okAction)
        
        self.present(alertController, animated: true, completion: nil)
    }
    
    // This is called if the BMLTiOSLib suffers an error of some sort.
    func bmltLibInstance(_ inLibInstance: BMLTiOSLib, errorOccurred error: Error) {
        let alertController = UIAlertController(title: "ERROR!", message: "\(error)", preferredStyle: .alert)
        
        let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
        
        alertController.addAction(okAction)
        
        self.present(alertController, animated: true, completion: nil)
    }
}

The above code was copied verbatim from an extremely simple app that demonstrates ONLY this bit of code (Downloads a zip file with an Xcode project in it).

Build it and run it. After a few seconds of churning, you should get a display that looks like this:

The only thing that the app did, was create an instance of BMLTiOSLib, giving it a valid Root Server URI. It then displayed a success alert upon receiving a delegate callback, informing the app of a successful server connection.

The Root Server we provided was for our testing server, which will always be a valid server for the purposes of this library.

Now, let’s make it an invalid Root Server URI. That’s real easy to do. All we need to do, is remove an “s” from the URI, like so:

        let rootServerURI = "https://tkddevel.com/bmltwork/bmlt/main_server/"

becomes

        let rootServerURI = "http://tkddevel.com/bmltwork/bmlt/main_server/"

Now, build and run the app. You’ll get a sweet little alert that looks like this:

Useful and informative, huh? The strings are meant to be replaced by your app into ones more easily digested.

That First Alert Was A Really Big Deal

Don’t let the tiny amount of code that you had to write, or the simplicity of the alert fool you. A great deal went on behind the scenes, as we pointed out in our technical overview.

By the time that callback was made, a lot of information had been exchanged with the Root Server, and we now have an open channel to it. We can immediately start exercising this connection.

Let’s Find Some Meetings

Let’s do a simple meeting search for every meeting on the server:

import UIKit
import BMLTiOSLib

class ViewController : UIViewController, BMLTiOSLibDelegate {
    var _libraryInstance: BMLTiOSLib! = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // This is a string that points to a VALID Root Server instance
        // (>=10.2.8.1 running HTTPS, and with most of its data fields unmodified from default).
        let rootServerURI = "https://tkddevel.com/bmltwork/bmlt/main_server/"
        
        // Create an instance of the class. This immediately begins a communication process with the Root Server,
        // and the callbacks will be the next course of action.
        self._libraryInstance = BMLTiOSLib(inRootServerURI: rootServerURI, inDelegate: self)
    }
    
    // These are the required callback functions for the BMLTiOSLibDelegate class.
    
    // This is called upon successful connection and querying of the Root Server (or unsuccessful)
    func bmltLibInstance(_ inLibInstance: BMLTiOSLib, serverIsValid: Bool) {
        let alertController = UIAlertController(title: (serverIsValid ? "EXCELLENT!" : "BOGUS!"), message: "We're in! Wanna find some meetings?", preferredStyle: .alert)
        
        let cancelAction = UIAlertAction(title: "NO", style: UIAlertActionStyle.cancel, handler: nil)
        
        alertController.addAction(cancelAction)
        
        let findAction = UIAlertAction(title: "YES", style: UIAlertActionStyle.default, handler: {(_:UIAlertAction) in self._libraryInstance.searchCriteria.performMeetingSearch()})
        
        alertController.addAction(findAction)
        
        self.present(alertController, animated: true, completion: nil)
    }
    
    // This is called if the BMLTiOSLib suffers an error of some sort.
    func bmltLibInstance(_ inLibInstance: BMLTiOSLib, errorOccurred error: Error) {
        let alertController = UIAlertController(title: "ERROR!", message: "\(error)", preferredStyle: .alert)
        
        let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
        
        alertController.addAction(okAction)
        
        self.present(alertController, animated: true, completion: nil)
    }
    
    // This is called with the results of a meeting search.
    func bmltLibInstance(_ inLibInstance: BMLTiOSLib, meetingSearchResults: [BMLTiOSLibMeetingNode]) {
        let alertController = UIAlertController(title: "w00t!", message: "\(meetingSearchResults.count) meetings were found!", preferredStyle: .alert)
        
        let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
        
        alertController.addAction(okAction)
        
        self.present(alertController, animated: true, completion: nil)
    }
}

Let’s look at what we did, here:

We Modified the serverIsValid Callback

It went from:

func bmltLibInstance(_ inLibInstance: BMLTiOSLib, serverIsValid: Bool) {
    let alertController = UIAlertController(title: (serverIsValid ? "EXCELLENT!" : "BOGUS!"), message: "The initialization has completed.", preferredStyle: .alert)
    
    let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
    
    alertController.addAction(okAction)
    
    self.present(alertController, animated: true, completion: nil)
}

to:

func bmltLibInstance(_ inLibInstance: BMLTiOSLib, serverIsValid: Bool) {
    let alertController = UIAlertController(title: (serverIsValid ? "EXCELLENT!" : "BOGUS!"), message: "We're in! Wanna find some meetings?", preferredStyle: .alert)
    
    let cancelAction = UIAlertAction(title: "NO", style: UIAlertActionStyle.cancel, handler: nil)
    
    alertController.addAction(cancelAction)
    
    let findAction = UIAlertAction(title: "YES", style: UIAlertActionStyle.default, handler: {(_:UIAlertAction) in self._libraryInstance.searchCriteria.performMeetingSearch()})
    
    alertController.addAction(findAction)
    
    self.present(alertController, animated: true, completion: nil)
}

The red parts are the parts that substantially changed. Basically, we replaced the report with a simple choice of whether or not to proceed with a basic meeting search. If you tap “NO”, then the app basically just goes quiescent.

However, if you hit “YES”, then this bit of code gets exercised:

self._libraryInstance.searchCriteria.performMeetingSearch()

This tells the BMLTiOSLib.searchCriteria object to perform an “open” search (no criteria specified, so the whole database is returned).

We Added a New Delegate Callback

We added the following Delegate handler:

func bmltLibInstance(_ inLibInstance: BMLTiOSLib, meetingSearchResults: [BMLTiOSLibMeetingNode]) {
    let alertController = UIAlertController(title: "w00t!", message: "\(meetingSearchResults.count) meetings were found!", preferredStyle: .alert)
    
    let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
    
    alertController.addAction(okAction)
    
    self.present(alertController, animated: true, completion: nil)
}

This is called with the results of the meeting search in an array.

In there, we simply take a count of the number of meetings returned, and report how many.

That means that the app now looks like this:


(Let’s Press “YES”)

(Your Mileage May Vary)

You just did your first BMLT meeting search with an iOS app. If you hadn’t stopped to read these pages, it probably would have taken you ten minutes to implement; from the project creation, through the first meeting search result. That’s the magic of the BMLTiOSLib. It literally just saved you several days (at least) of writing (and testing) a lot of complex communication code.

Here’s the next version of the demo app with the new search (Downloads a zip file with an Xcode project).

Exercising Our Options

What you may not know at this time, is that we have already made use of optional BMLTiOSLibDelegate methods.

When the meeting search responded, it did so with both a list of the meetings it found, AND a list of the format codes used in those meetings. This is a capability that was added to the JSON/XML semantic response to make it easy for Satellites to display format codes for its meeting searches without displaying ones not necessary for the listed meetings.

Now, if we add this method:

func bmltLibInstance(_ inLibInstance: BMLTiOSLib, formatSearchResults: [BMLTiOSLibFormatNode], isAllUsedFormats: Bool) {
    let alertController = UIAlertController(title: "Double-w00t!", message: "\(formatSearchResults.count) formats were found!", preferredStyle: .alert)
    
    let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
    
    alertController.addAction(okAction)
    
    self.present(alertController, animated: true, completion: nil)
}

We will see a third alert show up:

However, the meetings found alert won’t show up. There’s a reason for this.

This happens because only one alert can be shown at a time, and the meetings alert came up second (that callback gets called after the formats one), but the first alert gets dibs.

Here’s the third installment of the app with the new callback (Downloads a zip file with the Xcode project).

In the next page, let’s see if we can address the “missing data” issue.