27_Blog Reader
这个App是用来读取 Official Google Blog 的内容,然后显示出来。
用了新建工程时用了 Master-Detail Application 这个模板。用了Core Data用来存储内容,不过每次启动App还是会删除内容,然后重新下载最新的20条。所以如果没有网络的时候打开不显示内容。
在原工程的基础上,我在Core Data中增加了date这项,为了排列时按照时间排列。获取的内容中有published和updated两个时间,用published好一些。这里只简单的转了String而不是Date类型。
// // MasterViewController.swift // Blog Reader // // Created by zcdll on 16/1/24. // Copyright © 2016年 ZC. All rights reserved. // import UIKit import CoreData class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate { var detailViewController: DetailViewController? = nil var managedObjectContext: NSManagedObjectContext? = nil override func viewDidLoad() { super.viewDidLoad() let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate let context: NSManagedObjectContext = appDel.managedObjectContext let url = NSURL(string: "https://www.googleapis.com/blogger/v3/blogs/10861780/posts?key=AIzaSyCxL3Iltcd-oLc-dFUtdDG9TTuJGWilsYw")! let session = NSURLSession.sharedSession() let task = session.dataTaskWithURL(url) { (data, response, error) -> Void in if error != nil { print(error) } else { if let data = data { //print(NSString(data: data, encoding: NSUTF8StringEncoding)) do { let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary if jsonResult.count > 0 { if let items = jsonResult["items"] as? NSArray { let request = NSFetchRequest(entityName: "BlogItems") request.returnsObjectsAsFaults = false do { let results = try context.executeFetchRequest(request) if results.count > 0 { for result in results { context.deleteObject(result as! NSManagedObject) do { try context.save() } catch {} } } } catch { print("Context fetched failed") } for item in items { if let title = item["title"] as? String { if let content = item["content"] as? String { if let date = item["published"] as? String { let updatedDate = date.componentsSeparatedByString("-08:00")[0] print(updatedDate) //print(title) //print(content) let newPost: NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName("BlogItems", inManagedObjectContext: context) newPost.setValue(title, forKey: "title") newPost.setValue(content, forKey: "content") newPost.setValue(updatedDate, forKey: "date") } } } //print(items) } } } } catch {} } } } task.resume() // Do any additional setup after loading the view, typically from a nib. if let split = self.splitViewController { let controllers = split.viewControllers self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController } } override func viewWillAppear(animated: Bool) { self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed super.viewWillAppear(animated) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Segues override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "showDetail" { if let indexPath = self.tableView.indexPathForSelectedRow { let object = self.fetchedResultsController.objectAtIndexPath(indexPath) let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController controller.detailItem = object controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem() controller.navigationItem.leftItemsSupplementBackButton = true } } } // MARK: - Table View override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let sectionInfo = self.fetchedResultsController.sections![section] return sectionInfo.numberOfObjects } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) self.configureCell(cell, atIndexPath: indexPath) return cell } override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { // Return false if you do not want the specified item to be editable. return true } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { let context = self.fetchedResultsController.managedObjectContext context.deleteObject(self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject) do { try context.save() } catch { // 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. //print("Unresolved error \(error), \(error.userInfo)") abort() } } } func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) { let object = self.fetchedResultsController.objectAtIndexPath(indexPath) cell.textLabel!.text = object.valueForKey("title")!.description } // MARK: - Fetched results controller var fetchedResultsController: NSFetchedResultsController { if _fetchedResultsController != nil { return _fetchedResultsController! } let fetchRequest = NSFetchRequest() // Edit the entity name as appropriate. let entity = NSEntityDescription.entityForName("BlogItems", inManagedObjectContext: self.managedObjectContext!) fetchRequest.entity = entity // Set the batch size to a suitable number. fetchRequest.fetchBatchSize = 20 // Edit the sort key as appropriate. let sortDescriptor = NSSortDescriptor(key: "date", ascending: false) fetchRequest.sortDescriptors = [sortDescriptor] // Edit the section name key path and cache name if appropriate. // nil for section name key path means "no sections". let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: nil, cacheName: "Master") aFetchedResultsController.delegate = self _fetchedResultsController = aFetchedResultsController do { try _fetchedResultsController!.performFetch() } catch { // 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. //print("Unresolved error \(error), \(error.userInfo)") abort() } return _fetchedResultsController! } var _fetchedResultsController: NSFetchedResultsController? = nil func controllerWillChangeContent(controller: NSFetchedResultsController) { self.tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { switch type { case .Insert: self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) case .Delete: self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) default: return } } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) case .Delete: tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) case .Update: self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!) case .Move: tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) } } func controllerDidChangeContent(controller: NSFetchedResultsController) { self.tableView.endUpdates() } /* // Implementing the above methods to update the table view in response to individual changes may have performance implications if a large number of changes are made simultaneously. If this proves to be an issue, you can instead just implement controllerDidChangeContent: which notifies the delegate that all section and object changes have been processed. func controllerDidChangeContent(controller: NSFetchedResultsController) { // In the simplest, most efficient, case, reload the table view. self.tableView.reloadData() } */ }
// // DetailViewController.swift // Blog Reader // // Created by zcdll on 16/1/24. // Copyright © 2016年 ZC. All rights reserved. // import UIKit class DetailViewController: UIViewController { @IBOutlet weak var webview: UIWebView! var detailItem: AnyObject? { didSet { // Update the view. self.configureView() } } func configureView() { // Update the user interface for the detail item. if let detail = self.detailItem { if let postWebView = self.webview { postWebView.loadHTMLString(detail.valueForKey("content")!.description, baseURL: NSURL(string: "https://googleblog.blogspot.com/")) } } } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.configureView() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }