Article List View Controller Swift Program

Article List View Controller Swift Program


//
//  ArticleListViewController.swift
//  TUM Blog
//

import UIKit
import Alamofire
import SwiftyJSON

/**
    Controller object that manages the presentation of and interaction with TUM Blog Articles in form of a list.
*/
class ArticleListViewController: UITableViewController {
    
    /// The Articles retrieved from the server.
    var articles: [Article] = []
    
    /// Instance to parse ISO date strings into `NSDate` objects.
    let dateParser: NSDateFormatter = {
        let formatter = NSDateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
        return formatter
    }()
    
    /// Instance to format `NSDate`s for display.
    let dateFormatter: NSDateFormatter = {
        let formatter = NSDateFormatter()
        formatter.doesRelativeDateFormatting = true
        formatter.dateStyle = NSDateFormatterStyle.ShortStyle
        formatter.timeStyle = NSDateFormatterStyle.ShortStyle
        formatter.timeZone = NSTimeZone.localTimeZone()
        return formatter
    }()

    // Called after the controller'€™s view is loaded into memory.
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Size table view cells via Auto Layout.
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 60
        // Load initial data.
        loadData()
    }
    
    // MARK: - Exercise 3.1 & Exercise 3.2
    
    /// Called when data needs to be loaded from the server.
    func loadData() {
        // Exercise 3.1 & Exercise 3.2
        
        request(.GET, "\(Shared.Server)/articles")
            .validate()
            .backgroundResponseJSON { request,response,rawJSONResult in
                print("Finally received response")
                
                // Parse raw JSON if a valid result was received.
                let parsedArticles = rawJSONResult.value
                    .flatMap({ self.parseJSON($0) })
                
                dispatch_async(dispatch_get_main_queue()) {
                
                    // If retrieving and parsing of the Articles was successful, update UI.
                    if let articles = parsedArticles {
                        self.articles = articles
                        self.tableView.reloadData()
                    }
                
                    // Notify UI that the pull-to-refresh was processed.
                    self.refreshControl?.endRefreshing()
                }
            }
        print("Scheduled request from server")
    }
    
    // MARK: - Final Exercise
    
    /** Called when an Article needs to be saved to the server.
    - parameter article: the Article to be saved
        * article.id is nil for new Comments
        * article.id is set to a specific id for existing Comments
    */
    func saveArticle(article: Article) {
        let params:[String:AnyObject]
        params = [
            "email" : article.email,
            "title": article.title,
            "text": article.text
        ]
        
        if let id = article.id {
            request(.PUT, "\(Shared.Server)/articles/\(id)", parameters: params)
                .validate()
                .response { request, response, data, error in
                    self.loadData()
            }
            
        } else {
            request(.POST, "\(Shared.Server)/articles/", parameters: params)
                .validate()
                .response { request, response, data, error in
                    self.loadData()
            }

        }
    
    }
    
    /// Called when an Article needs to be deleted from the server.
    func deleteArticle(id: Int, indexPath: NSIndexPath) {
        
        articles.removeAtIndex(indexPath.row)
        
        request(.DELETE, "\(Shared.Server)/articles/\(id)")
            .validate()
            .response { request, response, data, error in
                self.loadData()
        }
    }
    
    // MARK: - Parse Response
    
    /// Parses the raw json into an Article object.
    func parseJSON(rawJSON: AnyObject) -> [Article]? {
        // Return `nil` if the JSON is not an array.
        guard let jsonArray = JSON(rawJSON).array else { return nil }
        
        // Iterate through the JSON array, parse each element, and store results in an array.
        var parsedArticles = [Article]()
        for json in jsonArray {
            // Skip element if it does not match expected schema.
            guard let id = json["id"].int,
                let title = json["title"].string,
                let email = json["email"].string,
                let text = json["text"].string,
                let updatedString = json["updated"].string
            else { continue }
                
            parsedArticles.append(Article(
                    id: id,
                    title: title,
                    updated: dateParser.dateFromString(updatedString),
                    email: email,
                    text: text))
        }
        return parsedArticles
    }
    
    // MARK: - Table view data source
    
    // Tells the data source to return the number of rows in a given section of a table view.
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return articles.count
    }
    
    // Asks the data source for a cell to insert in a particular location of the table view.
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let article = articles[indexPath.row]
        
        let cell = tableView.dequeueReusableCellWithIdentifier("blogEntry", forIndexPath: indexPath) as! ArticleListViewCell
        cell.headingLabel.text = article.title
        cell.dateLabel.text = article.updated.flatMap({ dateFormatter.stringFromDate($0) })
        if article.email == Shared.YourEmail {
            cell.accessoryType = .DetailDisclosureButton
        }
        
        if let image = article.profileImage {
            cell.profileView.image = image
        } else {
            Gravatar.getImageForEmail(article.email, forImageView: cell.profileView) { image in
                if let image = image {
                    dispatch_async(dispatch_get_main_queue()) {
                        article.profileImage = image
                        tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
                    }
                }
            }
        }
        
        return cell
    }
    
    // Asks the data source to verify that the given row is editable.
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return articles[indexPath.row].email == Shared.YourEmail
    }
    
    // Asks the data source to commit the insertion or deletion of a specified row in the receiver.
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        
        guard let id = articles[indexPath.row].id
            where editingStyle == .Delete
        else {
            self.loadData()
            return
        }
        
        deleteArticle(id, indexPath: indexPath)
    }
    
    // MARK: - UI Actions
    
    /// Called when the user "pulls to refresh".
    @IBAction func refreshTriggered(sender: AnyObject) {
        loadData()
    }
    
    // Called when the user wants to cancel the edit and the storyboard is unwound to the Article list.
    @IBAction func cancelEditArticle(sender: UIStoryboardSegue) {
        print("Canceled Edit")
    }

    // Called when the user wants to save the edit and the storyboard is unwound to the Article list.
    @IBAction func saveEditArticle(sender: UIStoryboardSegue) {
        print("Saving Edit")
        let newArticleViewController = sender.sourceViewController as! ArticleEditViewController
        let article = newArticleViewController.articleDetailsViewController.article
        
        saveArticle(article)
    }
    
    // Notifies the view controller that a segue is about to be performed.
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        super.prepareForSegue(segue, sender: sender)
        
        guard let cell = sender as? ArticleListViewCell,
            let indexPath = tableView.indexPathForCell(cell) else { return }
        
        if let detailsViewController = segue.destinationViewController as? ArticleDetailsViewController {
            detailsViewController.article = articles[indexPath.row]
        } else if segue.identifier == "editBlogEntry",
            let navController = segue.destinationViewController as? UINavigationController,
            let editViewController = navController.viewControllers.first as? ArticleEditViewController {
                editViewController.article = articles[indexPath.row]
        }
    }
}


Learn More :