(作业)采用多MVC和Core Data构造一个个人信息维护程序

这次作业要用到一个新的框架,话不多说,先上需求
这里写图片描述
然后看看博主实现的程序吧
这里写图片描述

现在我们就开始一步一步地实现这个程序吧。
首先从工程的创建开始,因为要使用Core Data,所以需要在创建工程时将Use Core Data打上勾,这样的话系统会自动帮我们生成一些代码和文件
这里写图片描述

这里写图片描述
这个homework.xcdatamodeld文件就是系统帮我们生成的,再看看AppDelegate.swift文件,会发现里面多了一些代码

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    /*
     The persistent container for the application. This implementation
     creates and returns a container, having loaded the store for the
     application to it. This property is optional since there are legitimate
     error conditions that could cause the creation of the store to fail.
    */
    let container = NSPersistentContainer(name: "homework")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() 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.

            /*
             Typical reasons for an error here include:
             * The parent directory does not exist, cannot be created, or disallows writing.
             * The persistent store is not accessible, due to permissions or data protection when the device is locked.
             * The device is out of space.
             * The store could not be migrated to the current model version.
             Check the error message to determine what the actual problem was.
             */
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

// MARK: - Core Data Saving support

func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() 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.
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}

其中persistentContainer属性和saveContext()方法会在后面用到。

然后我们就需要在数据库中添加自己的表了。因为这里使用的是Core Data,我们就不需要使用SQL语句来创建表或者插入数据了,直接在xcode里面通过编辑器就可以创建实体类了,我们这里创建一个叫Person的实体,它包含两个属性name和age,操作步骤如下:
这里写图片描述

从上面的运行图可以看出,博主这里使用了三个界面,Persons展示数据库中已经存在的界面;Add和Edit是同一个界面,负责增加或修改Person的信息;Search界面做一些特定的查询。所以出了系统自带的ViewController.swift文件之外,我们还需要再创建两个控制器文件,InsertViewController.swift文件和SearchViewController.swift文件。

我们先来实现InsertViewController.swift的功能,首先我们需要两个文本输入框,一个输入名字,一个输入年龄,所以需要声明两个属性,而且需要声明一个记录下标的属性,这个属性保存前一个界面传入的点击的cell的下标

var row: Int?
var nameTextField: UITextField!
var ageTextField: UITextField!

因为要使用Core Data,所以我们需要导入库

import CoreData

然后构建我们的界面,首先将两个文本输入框添加到视图上,然后在navigationbar上添加一个完成的按钮,最后再根据是否传入的了下标来设置视图的标题(如果没有传入下标,就是添加数据,如果传入了,就是修改数据)
所以最终的viewDidLoad方法内容如下

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    self.view.backgroundColor = UIColor.white

    nameTextField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 44))
    nameTextField.layer.borderWidth = 1
    self.view.addSubview(nameTextField)

    ageTextField = UITextField(frame: CGRect(x: 20, y: 200, width: 300, height: 44))
    ageTextField.layer.borderWidth = 1
    self.view.addSubview(ageTextField)

    let btn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(done))
    self.navigationItem.rightBarButtonItem = btn

    if row == nil {
        self.title = "Add"
    } else {
        self.title = "Edit"
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext
        let request: NSFetchRequest<Person> = Person.fetchRequest()
        if let persons = try? context.fetch(request) {
            nameTextField.placeholder = persons[row!].name
            ageTextField.placeholder = String(persons[row!].age)
        }
    }
}

在判断为修改数据时,我们需要给两个文本输入框设置占位符,这里就使用了Core Data的查询。在查询Core Data中的数据时,我们需要先获取到程序代理,也就是AppDelegate,然后获取代理中的上下文,这个就需要AppDelegate.swift中新生成的persistentContainer了。在获取到context之后,需要初始化一个查询的请求,这个请求用于指定查找哪个实体的数据,并且可以设置一些查询的条件,详细会在Search界面多讲解,在调用context的fetch后,会返回实体的数组,我们就根据传入的下标,来获取数组中的元素,并将其值设置为textfield的placeholder。

在构建完成界面之后,我们就需要实现done按钮的功能。

@objc func done() {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext

    let name = self.nameTextField.text!
    let age = Int16(self.ageTextField.text!)

    if row == nil {
        if !name.isEmpty && age != nil {
            let person = Person(context: context)
            person.name = name
            person.age = age!
        }
    } else {
        let request: NSFetchRequest<Person> = Person.fetchRequest()
        if let persons = try? context.fetch(request) {
            if !name.isEmpty {
                persons[row!].name = name
            }
            if age != nil {
                persons[row!].age = age!
            }
        }
    }
    appDelegate.saveContext()
    self.navigationController?.popViewController(animated: true)
}

在这个方法中,我们先获取到context(上下文),然后取出textfield中填的数据,再判断是否是添加数据做不同的操作,
如果是添加数据的话,就用context初始化一个Person实体,设置其值,最后保存数据即可。
如果是修改数据的话,就需要将数据库中存在的数据查出,然后再根据传入的下标找到实体实例,修改其值,最后保存数据。
在将数据保存到数据库中之后,就关闭本界面,返回上一个界面。到这里,InsertViewController.swift中的内容就实现完了。

然后我们实现Search界面,也就是SearchViewController的内容。
因为这个界面中使用了UITableView,所以需要实现其代理和数据源

class SearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource

因为要使用Core Data,所以我们需要导入库

import CoreData

然后我们需要声明或初始化以下属性

var nameTextField: UITextField!
var ageTextField: UITextField!
var tableView: UITableView!
var persons = [Person]()
let appDelegate = UIApplication.shared.delegate as! AppDelegate

其中前三个是界面显示的组件,第四个保存查询出的数据,最后一个获取应用的代理(用于数据查询)。

然后在viewDidLoad方法中构建界面

self.view.backgroundColor = UIColor.white
self.title = "Search"

nameTextField = UITextField(frame: CGRect(x: 10, y: 100, width: 200, height: 44))
nameTextField.layer.borderWidth = 1
self.view.addSubview(nameTextField)

let nameBtn = UIButton(frame: CGRect(x: 250, y: 100, width: 100, height: 44))
nameBtn.setTitle("按名字查找", for: .normal)
nameBtn.setTitleColor(UIColor.cyan, for: .normal)
nameBtn.setTitleColor(UIColor.brown, for: .highlighted)
nameBtn.addTarget(self, action: #selector(searchWithName), for: .touchUpInside)
self.view.addSubview(nameBtn)

ageTextField = UITextField(frame: CGRect(x: 10, y: 150, width: 200, height: 44))
ageTextField.layer.borderWidth = 1
self.view.addSubview(ageTextField)

let ageBtn = UIButton(frame: CGRect(x: 250, y: 150, width: 100, height: 44))
ageBtn.setTitle("按年龄查找", for: .normal)
ageBtn.setTitleColor(UIColor.cyan, for: .normal)
ageBtn.setTitleColor(UIColor.brown, for: .highlighted)
ageBtn.addTarget(self, action: #selector(searchWithAge), for: .touchUpInside)
self.view.addSubview(ageBtn)

tableView = UITableView(frame: CGRect(x: 0, y: 200, width: self.view.frame.width, height: self.view.frame.height - 200))
tableView.delegate = self
tableView.dataSource = self
self.view.addSubview(tableView)

接下来就该实现两个按钮的功能,分别实现按照名字查找和按照年龄查找
首先实现按名字查找

@objc func searchWithName() {
    ageTextField.text = ""
    let context = appDelegate.persistentContainer.viewContext

    let name = nameTextField.text

    let request: NSFetchRequest<Person> = Person.fetchRequest()
    if name != nil {
        request.predicate = NSPredicate(format: "name = %@", name!)
    }
    if let persons = try? context.fetch(request) {
        self.persons = persons
        tableView.reloadData()
    }
}

在这个方法中,我们先通过应用代理(appDelegate)获取上下文,然后初始化一个查询请求,该请求为Person的查询请求,并设置查询的谓词(也就是查询的条件),最后将查询的结构保存在数组当中。

按年龄查找的代码类似

@objc func searchWithAge() {
    nameTextField.text = ""
    let context = appDelegate.persistentContainer.viewContext

    let age = Int16(ageTextField.text!)

    let request: NSFetchRequest<Person> = Person.fetchRequest()
    if age != nil {
        request.predicate = NSPredicate(format: "age = %d", age!)
    }
    if let persons = try? context.fetch(request) {
        self.persons = persons
        tableView.reloadData()
    }
}

在实现这两个方法之后,我们就需要实现UITableViewDataSource中要求的两个方法

// MARK: data source

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return persons.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")

    if cell == nil {
        cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
    }

    cell?.textLabel?.text = persons[indexPath.row].name
    cell?.detailTextLabel?.text = String(persons[indexPath.row].age)

    return cell!
}

到这里,我们的SearchViewController.swift就实现完成了,最后我们来实现主界面。
在实现主界面之前,我们需要将其放入导航栏控制器当中,所以在AppDelegate.swift的func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool方法中添加下面一行代码

window?.rootViewController = UINavigationController(rootViewController: ViewController())

这句代码是将导航栏控制器作为window的根视图控制器,并设置该导航栏控制器的根视图控制器为ViewController

然后回到我们的ViewController.swift,声明或初始化以下三个属性

var tableView: UITableView!
var personArray = [Person]()
let appDelegate = UIApplication.shared.delegate as! AppDelegate

第一个属性为视图中的表,第二个保存数据库中的数据,第三个为应用代理

因为要使用Core Data,所以我们需要导入库

import CoreData

然后想导航栏上添加两个按钮,一个添加,一个查询,并将表视图添加到视图上

self.title = "Persons"
self.view.backgroundColor = UIColor.white

tableView = UITableView(frame: self.view.frame)
tableView.delegate = self
tableView.dataSource = self
self.view.addSubview(tableView)

let searchBtn = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(search))
self.navigationItem.leftBarButtonItem = searchBtn

let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(add))
self.navigationItem.rightBarButtonItem = addBtn

接下来实现两个导航栏按钮的功能,分别进入两个不同的控制器

@objc func search() {
    let viewController = SearchViewController()
    self.navigationController?.pushViewController(viewController, animated: true)
}

@objc func add() {
    let viewController = InsertViewController()
    self.navigationController?.pushViewController(viewController, animated: true)
}

现在我们需要实现UITableViewDataSource中的两个方法

// MARK: data source

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return personArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")

    if cell == nil {
        cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
        cell?.accessoryType = .disclosureIndicator
    }

    cell?.textLabel?.text = personArray[indexPath.row].name
    cell?.detailTextLabel?.text = String(personArray[indexPath.row].age)

    return cell!
}

到这里,基本的东西已经实现,但界面没有显示数据,并且不能修改和删除数据。

那我们先来实现数据的显示,因为我们的数据是在界面加载之后显示,并且从添加界面返回之后需要重新加载一次数据,所以我们将数据的显示放到viewWillAppear方法中,这个方法在每一次界面即将显示时就会调用一次,不想viewDidLoad只在第一次加载界面时才调用

override func viewWillAppear(_ animated: Bool) {
    let context = appDelegate.persistentContainer.viewContext

    let request: NSFetchRequest<Person> = Person.fetchRequest()

    if let persons = try? context.fetch(request) {
        personArray = persons
    }
    tableView.reloadData()
}

这个方法的内容非常简单,先从数据库中查找出所有数据,并更新表视图即可。这样,我们的数据就能正常显示到界面上了,现在我们实现点击cell,修改其相应的数据。
这时,我们就需要用到UITableViewDelegate中的方法了,

// MARK: delegate

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let viewController = InsertViewController()
    viewController.row = indexPath.row
    self.navigationController?.pushViewController(viewController, animated: true)
}

在这个方法中,我们先创建一个编辑控制器的实例,然后将cell的下标传入,最后显示界面。这时,我们就实现了编辑数据了。最后还差一个功能——删除数据。

在实现删除数据时,我们需要先调用UITableViewDelegate中的方法,设置每个cell的编辑样式,我们将其所有都设置为删除

func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
    return .delete
}

然后实现UITableViewDataSource中的提交编辑方法。

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        personArray.remove(at: indexPath.row)
        tableView.reloadData()

        DispatchQueue.global().async {
            let context = self.appDelegate.persistentContainer.viewContext

            let request: NSFetchRequest<Person> = Person.fetchRequest()
            if let persons = try? context.fetch(request) {
                context.delete(persons[indexPath.row])
                self.appDelegate.saveContext()
            }
        }
    }
}

在该方法中,我们判断单元格是否可以删除,在将数据数组中相应的数据删除,然后更新表视图。最后我们使用多线程的方式删除数据库中的数据,这样可以减少界面的卡顿。CoreData删除数据的方式很简单,需要先找到待删除的实体实例,然后调用context(上下文)的delete方法即可,它会帮你找到相应的实体,然后从数据库中删除。

到这里,我们的整个程序就实现完成了,最后贴一下所有的代码吧。

AppDelegate.swift

import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        window?.rootViewController = UINavigationController(rootViewController: ViewController())

        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        // Saves changes in the application's managed object context before the application terminates.
        self.saveContext()
    }

    // MARK: - Core Data stack

    lazy var persistentContainer: NSPersistentContainer = {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
        */
        let container = NSPersistentContainer(name: "homework")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() 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.

                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() 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.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

}

ViewController.swift

import UIKit
import CoreData

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    var tableView: UITableView!
    var personArray = [Person]()
    let appDelegate = UIApplication.shared.delegate as! AppDelegate

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.title = "Persons"
        self.view.backgroundColor = UIColor.white

        tableView = UITableView(frame: self.view.frame)
        tableView.delegate = self
        tableView.dataSource = self
        self.view.addSubview(tableView)

        let searchBtn = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(search))
        self.navigationItem.leftBarButtonItem = searchBtn

        let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(add))
        self.navigationItem.rightBarButtonItem = addBtn

    }

    override func viewWillAppear(_ animated: Bool) {
        let context = appDelegate.persistentContainer.viewContext

        let request: NSFetchRequest<Person> = Person.fetchRequest()

        if let persons = try? context.fetch(request) {
            personArray = persons
        }
        tableView.reloadData()
    }

    @objc func search() {
        let viewController = SearchViewController()
        self.navigationController?.pushViewController(viewController, animated: true)
    }

    @objc func add() {
        let viewController = InsertViewController()
        self.navigationController?.pushViewController(viewController, animated: true)
    }

    // MARK: delegate

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let viewController = InsertViewController()
        viewController.row = indexPath.row
        self.navigationController?.pushViewController(viewController, animated: true)
    }

    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
        return .delete
    }

    // MARK: data source

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return personArray.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")

        if cell == nil {
            cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
            cell?.accessoryType = .disclosureIndicator
        }

        cell?.textLabel?.text = personArray[indexPath.row].name
        cell?.detailTextLabel?.text = String(personArray[indexPath.row].age)

        return cell!
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            personArray.remove(at: indexPath.row)
            tableView.reloadData()

            DispatchQueue.global().async {
                let context = self.appDelegate.persistentContainer.viewContext

                let request: NSFetchRequest<Person> = Person.fetchRequest()
                if let persons = try? context.fetch(request) {
                    context.delete(persons[indexPath.row])
                    self.appDelegate.saveContext()
                }
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

InsertViewController.swift

import UIKit
import CoreData

class InsertViewController: UIViewController {

    var row: Int?
    var nameTextField: UITextField!
    var ageTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.view.backgroundColor = UIColor.white

        nameTextField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 44))
        nameTextField.layer.borderWidth = 1
        self.view.addSubview(nameTextField)

        ageTextField = UITextField(frame: CGRect(x: 20, y: 200, width: 300, height: 44))
        ageTextField.layer.borderWidth = 1
        self.view.addSubview(ageTextField)

        let btn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(done))
        self.navigationItem.rightBarButtonItem = btn

        if row == nil {
            self.title = "Add"
        } else {
            self.title = "Edit"
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            let context = appDelegate.persistentContainer.viewContext
            let request: NSFetchRequest<Person> = Person.fetchRequest()
            if let persons = try? context.fetch(request) {
                nameTextField.placeholder = persons[row!].name
                ageTextField.placeholder = String(persons[row!].age)
            }
        }
    }

    @objc func done() {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext

        let name = self.nameTextField.text!
        let age = Int16(self.ageTextField.text!)

        if row == nil {
            if !name.isEmpty && age != nil {
                let person = Person(context: context)
                person.name = name
                person.age = age!
            }
        } else {
            let request: NSFetchRequest<Person> = Person.fetchRequest()
            if let persons = try? context.fetch(request) {
                if !name.isEmpty {
                    persons[row!].name = name
                }
                if age != nil {
                    persons[row!].age = age!
                }
            }
        }
        appDelegate.saveContext()
        self.navigationController?.popViewController(animated: true)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

SearchViewController.swift

import UIKit
import CoreData

class SearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    var nameTextField: UITextField!
    var ageTextField: UITextField!
    var tableView: UITableView!
    var persons = [Person]()
    let appDelegate = UIApplication.shared.delegate as! AppDelegate

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        self.view.backgroundColor = UIColor.white
        self.title = "Search"

        nameTextField = UITextField(frame: CGRect(x: 10, y: 100, width: 200, height: 44))
        nameTextField.layer.borderWidth = 1
        self.view.addSubview(nameTextField)

        let nameBtn = UIButton(frame: CGRect(x: 250, y: 100, width: 100, height: 44))
        nameBtn.setTitle("按名字查找", for: .normal)
        nameBtn.setTitleColor(UIColor.cyan, for: .normal)
        nameBtn.setTitleColor(UIColor.brown, for: .highlighted)
        nameBtn.addTarget(self, action: #selector(searchWithName), for: .touchUpInside)
        self.view.addSubview(nameBtn)

        ageTextField = UITextField(frame: CGRect(x: 10, y: 150, width: 200, height: 44))
        ageTextField.layer.borderWidth = 1
        self.view.addSubview(ageTextField)

        let ageBtn = UIButton(frame: CGRect(x: 250, y: 150, width: 100, height: 44))
        ageBtn.setTitle("按年龄查找", for: .normal)
        ageBtn.setTitleColor(UIColor.cyan, for: .normal)
        ageBtn.setTitleColor(UIColor.brown, for: .highlighted)
        ageBtn.addTarget(self, action: #selector(searchWithAge), for: .touchUpInside)
        self.view.addSubview(ageBtn)

        tableView = UITableView(frame: CGRect(x: 0, y: 200, width: self.view.frame.width, height: self.view.frame.height - 200))
        tableView.delegate = self
        tableView.dataSource = self
        self.view.addSubview(tableView)

    }

    @objc func searchWithName() {
        ageTextField.text = ""
        let context = appDelegate.persistentContainer.viewContext

        let name = nameTextField.text

        let request: NSFetchRequest<Person> = Person.fetchRequest()
        if name != nil {
            request.predicate = NSPredicate(format: "name = %@", name!)
        }
        if let persons = try? context.fetch(request) {
            self.persons = persons
            tableView.reloadData()
        }
    }

    @objc func searchWithAge() {
        nameTextField.text = ""
        let context = appDelegate.persistentContainer.viewContext

        let age = Int16(ageTextField.text!)

        let request: NSFetchRequest<Person> = Person.fetchRequest()
        if age != nil {
            request.predicate = NSPredicate(format: "age = %d", age!)
        }
        if let persons = try? context.fetch(request) {
            self.persons = persons
            tableView.reloadData()
        }
    }

    // MARK: data source

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return persons.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")

        if cell == nil {
            cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
        }

        cell?.textLabel?.text = persons[indexPath.row].name
        cell?.detailTextLabel?.text = String(persons[indexPath.row].age)

        return cell!
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值