cs193p – Project #4 Assignment #4 Task #8

By Boby1187 (Own work) [CC BY-SA 4.0 (http://creativecommons.org/licenses/by-sa/4.0)], via Wikimedia Commons

Please note, this blog entry is from a previous course. You might want to check out the current one.

Keep track of the most recent 100 Twitter searches the user has performed in your application. Add a UITabBarController to your application with a tab for searching (i.e. your main UI) and a second tab showing these most recent search terms in a table view (uniqued with most recent first). When a user clicks on a search term in the second tab, segue (stay in that same tab) to show the most recent Tweets matching that search term. Store these most recent searches permanently in NSUserDefaults so that your application doesn’t forget them if it is restarted.

Embed the current initial view controller (which should be your navigation view controller) in a tab view controller. Add a new table view controller and embed it in a navigation view controller. Add this new navigation view controller to the tab view controller, and choose nice icons for the two new tabs of the tab view controller. Create a new class for the new table view controller and segue from its cell to the twitter table view controller. Don’t forget to provide sensible names for the cell and the segue identifiers:

cs193p - Project #4 Assignment #4 Task #8 - tab view controller
cs193p – Project #4 Assignment #4 Task #8 – tab view controller


Create an additional new class to hold the global “truth” (note, that this one does not have a parent class). It accesses the user defaults to get and set its values:

class RecentSearches {    
    private struct Const {
        static let ValuesKey = "RecentSearches.Values"
        static let NumberOfSearches = 100
    }    
    private let defaults = NSUserDefaults.standardUserDefaults()    
    var values: [String] {
        get { return defaults.objectForKey(Const.ValuesKey) as? [String] ?? [] }
        set { defaults.setObject(newValue, forKey: Const.ValuesKey) }
    }
}

Adding a new value, we don’t want doubles. If the new search value does already exist, remove it. Then insert it at the beginning of the array. If there are more than 100 entries, remove the last ones:

    private struct Const {
        ...
        static let NumberOfSearches = 100
    }    
    func add(search: String) {
        var currentSearches = values
        if let index = find(currentSearches, search) {
            currentSearches.removeAtIndex(index)
        }
        currentSearches.insert(search, atIndex: 0)
        while currentSearches.count > Const.NumberOfSearches {
            currentSearches.removeLast()
        }
        values = currentSearches
    }

The new values are added in the tweet table view controller, when we search for a new text:

    @IBAction func refresh(sender: UIRefreshControl?) {
        if searchText != nil {
            RecentSearches().add(searchText!)
            ...
    }

To fill the new table with data, the new table view controller class needs to provide the number of rows, which equals the number of entries stored in the user defaults:

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return RecentSearches().values.count
    }

The cell itself is filled with the search text:

    private struct Storyboard {
        static let CellReuseIdentifier = "History Cell"
    }    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(Storyboard.CellReuseIdentifier, forIndexPath: indexPath) as UITableViewCell
        cell.textLabel?.text = RecentSearches().values[indexPath.row]
        return cell
    }

… and preparing the segue, just set the selected text as search text for the tweet table view controller:

    private struct Storyboard {
        ...
        static let SegueIdentifier = "Show Search"
    }
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let identifier = segue.identifier {
            if identifier == Storyboard.SegueIdentifier {
                if let ttvc = segue.destinationViewController as? TweetTableViewController {
                    if let cell = sender as? UITableViewCell {
                        ttvc.searchText = cell.textLabel?.text
                    }
                }
            }
        }
    }

Because the contents of the user defaults will change only when table view is off screen, reload its data when it will appear again:

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        tableView.reloadData()
    }

The complete code for task #8 is available on GitHub.

FacebooktwitterredditpinterestlinkedintumblrmailFacebooktwitterredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published.