Swift教程_CoreData实例(四)_构建控制层(查询、更新数据)

Swift教程_CoreData实例(一)_构建storyboard

Swift教程_CoreData实例(二)_构建数据层

Swift教程_CoreData实例(三)_构建控制层(列表数据加载、删除数据)

Swift教程_CoreData实例(四)_构建控制层(查询、更新数据)

Swift教程_CoreData实例(五)_构建控制层(添加数据)

2.查询数据

我们自定义一个列表控制器PKOBookDetailTableViewController,并应用到storyboard的明细显示view中,用来显示所选中的book的明细。通过PKOBooksTableViewController传的Book对象来为列表赋值。
其中用到了监听系统语言变更通知的触发发放,以及coredata自带的undo、redo功能(撤销操作、取消撤销),当然不加这些功能也不影响最终效果,详细见代码与注释。
代码如下,注释非常详细,其中包含更新数据的部分代码,请结合下一小节的代码阅读:

import UIKit

class PKOBookDetailTableViewController: UITableViewController {
    
    var book: Book!
    
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var authorLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    
    //加载view时调用
    override func viewDidLoad() {
        super.viewDidLoad()
        NSLog("==viewDidLoad==")
        
        self.navigationItem.rightBarButtonItem = self.editButtonItem()
        
        //编辑的时候允许选择
        self.tableView.allowsSelectionDuringEditing = true
        
        //监听到NSCurrentLocaleDidChangeNotification时,即系统语言变化时触发的方法,与removeObserver是一对
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "localeChanged:", name: NSCurrentLocaleDidChangeNotification, object: nil)
    }
    
    //析构方法
    deinit{
        NSLog("==deinit==")
        NSNotificationCenter.defaultCenter().removeObserver(self, name: NSCurrentLocaleDidChangeNotification, object: nil)
    }
    
    
    /*
    The view controller must be first responder in order to be able to receive shake events for undo. It should resign first responder status when it disappears.指定是否可以时第一响应者,通俗来讲就是焦点
    */
    override func canBecomeFirstResponder() -> Bool {
        return true
    }
    
    //view显示时设置焦点
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.becomeFirstResponder()
    }
    
    //view销毁前取消焦点
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        self.resignFirstResponder()
    }
    
    //视图即将可见时调用,每次显示view就会调用
    override func viewWillAppear(animated: Bool) {
        NSLog("==viewWillAppear==")
        super.viewWillAppear(animated)
        
        //重载数据
        self.updateInterface()
        //改变右侧按钮状态
        self.updateRightBarButtonItemState()
    }
    
    //设置为编辑模式时调用
    override func setEditing(editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: animated)
        NSLog("==setEditing==\(editing)")
        
        self.navigationItem.setHidesBackButton(editing, animated: animated)
        
        //编辑状态时设置撤销管理器
        if(editing){
            self.setUpundoManager()
        }else
        //非编辑状态时取消撤销管理器并保存数据
        {
            self.cleanUpUndoManager()
            var error: NSError? = nil
            if (self.book.managedObjectContext?.save(&error) == nil) {
                NSLog("Unresolved error \(error), \(error?.userInfo)")
                abort()
            }
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //更新数据
    func updateInterface() {
        self.authorLabel.text = self.book.author
        self.titleLabel.text = self.book.title
        self.dateLabel.text = self.dateFormatter().stringFromDate(self.book.theDate)
    }
    
    func updateRightBarButtonItemState() {
        NSLog("==updateRightBarButtonItemState==")
        // 如果实体对象在保存状态,则允许右侧按钮
        var error: NSError? = nil
        self.navigationItem.rightBarButtonItem?.enabled = self.book.validateForUpdate(&error)
    }
    
    
    // MARK: - Table view data source
    
    //点击编辑按钮时的row编辑样式,默认delete,row前有一个删除标记,这里用none,没有任何标记
    override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
        return UITableViewCellEditingStyle.None
    }
    
    //点击编辑按钮时row是否需要缩进,这里不需要
    override func tableView(tableView: UITableView, shouldIndentWhileEditingRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return false
    }
    
    //在行将要选择的时候执行。通常,你可以使用这个方法来阻止选定特定的行。返回结果是选择的行
    override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
        if(self.editing){
            return indexPath
        }
        return nil
    }
    
    //在选择行后执行,这里是编辑状态选中一行时创建一个编辑页面
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        if(self.editing){
            self.performSegueWithIdentifier("DetailToEdit", sender: self)
        }
    }
    
    // MARK: - Undo support
    
    //设置撤回管理器
    func setUpundoManager() {
        if self.book.managedObjectContext?.undoManager == nil {
            self.book.managedObjectContext?.undoManager =  NSUndoManager()
            self.book.managedObjectContext?.undoManager?.levelsOfUndo = 3//撤销最大数
        }
        
        var bookUndoManager = self.book.managedObjectContext?.undoManager
        
        //监听撤回和取消撤回
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "undoManagerDidUndo:", name: NSUndoManagerDidUndoChangeNotification, object: bookUndoManager)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "undoManagerDidRedo:", name: NSUndoManagerDidRedoChangeNotification, object: bookUndoManager)
    }
    
    //取消撤回管理器
    func cleanUpUndoManager() {
        var bookUndoManager = self.book.managedObjectContext?.undoManager
        
        //移除撤回和取消撤回监听
        NSNotificationCenter.defaultCenter().removeObserver(self, name: NSUndoManagerWillUndoChangeNotification, object: bookUndoManager)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: NSUndoManagerWillRedoChangeNotification, object: bookUndoManager)
        
        //置空context的撤回管理器
        self.book.managedObjectContext?.undoManager = nil
    }
    
    //监听到撤回触发,重载数据和导航右侧按钮状态
    func undoManagerDidUndo(notification : NSNotification){
        NSLog("==undoManagerDidUndo==")
        //重载数据
        self.updateInterface()
        //改变右侧按钮状态
        self.updateRightBarButtonItemState()
    }
    
    //监听到取消撤回触发,重载数据和导航右侧按钮状态
    func undoManagerDidRedo(notification : NSNotification){
        NSLog("==undoManagerDidRedo==")
        //重载数据
        self.updateInterface()
        //改变右侧按钮状态
        self.updateRightBarButtonItemState()
    }
    
    // MARK: - Date Formatter
    
    //日期格式化
    func dateFormatter() -> NSDateFormatter{
        var dateFormatter = NSDateFormatter()
        dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
        dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle
        return dateFormatter
    }
    
    // MARK: - Navigation
    
    //通过segue跳转前所做的工作
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if(segue.identifier == "DetailToEdit"){
            var bookEditViewController = segue.destinationViewController as PKOBookEditViewController
            
            bookEditViewController.editedObject = self.book
            //根据选择的不同行为编辑view赋不同的值
            switch(self.tableView.indexPathForSelectedRow()!.row) {
            case 0:
                bookEditViewController.editedFieldKey = "title"
                bookEditViewController.editedFieldName = "title"
            case 1:
                bookEditViewController.editedFieldKey = "author"
                bookEditViewController.editedFieldName = "author"
            case 2:
                bookEditViewController.editedFieldKey = "theDate"
                bookEditViewController.editedFieldName = "theDate"
            default:
                break
            }
        }
    }
    
    // MARK: - Locale changes
    
    //监听到语言变化时,重载数据
    func localeChanged(notification : NSNotification) {
        NSLog("==localeChanged==")
        //重载数据
        self.updateInterface()
    }
    
}

3.更新数据

我们自定义一个基本的view控制器PKOBookEditViewController,并应用到storyboard的编辑view中,用来编辑所选中的字段。通过PKOBookDetailTableViewController中所选择的字段为编辑view的字段赋值。
其中用到了日期选择控件,需要根据PKOBookDetailTableViewController选择的字段来判断显示哪种控件。
代码如下,注释非常详细:

import UIKit

class PKOBookEditViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var datePicker: UIDatePicker!
    var editedObject: Book!
    var editedFieldKey: String!
    var editedFieldName: String!
    var editingDate: Bool!{
        get{
            //判断是否是日期字段
            var attributeClassName = self.editedObject.entity.attributesByName[self.editedFieldKey]?.attributeValueClassName?
            if attributeClassName == "NSDate" {
                return true
            }
            else {
                return false
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //为标题赋值
        self.title = self.editedFieldName
        //如果选中日期,则显示日期控件
        if self.editingDate! {
            self.textField.hidden = true
            self.datePicker.hidden = false
            
            var date = self.editedObject.valueForKey(self.editedFieldKey) as? NSDate
            if date == nil {
                date = NSDate()
            }
            self.datePicker.date = date!
        }
        else {
            self.textField.hidden = false
            self.datePicker.hidden = true
            self.textField.text = self.editedObject.valueForKey(self.editedFieldKey) as String
            self.textField.placeholder = self.title//空的时候显示值
            self.textField.becomeFirstResponder()
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //点击保存
    @IBAction func saveAction(sender: AnyObject) {
        // Set the action name for the undo operation.给撤回操作设置name
        NSLog("==saveAction==\(self.editedFieldName)")
        var undoManager = self.editedObject.managedObjectContext?.undoManager
        undoManager?.setActionName(self.editedFieldName)
        
        //更新该对象,然后抛出
        if self.editingDate! {
            self.editedObject.setValue(self.datePicker.date, forKey:self.editedFieldKey)
        }
        else {
            self.editedObject.setValue(self.textField.text, forKey:self.editedFieldKey)
        }
        
        self.navigationController?.popViewControllerAnimated(true)
    }

}
点击进入ooppookid的博客

你可能感兴趣的:(技术,sqlite,xcode,swift,coredata)