简单列表应用

1. 简述

  1.1 设置UITableViewController

  1.2 加载"数据",利用闭包模拟网络异步加载

  1.3 自定义Cell,绑定 Cell,通过模型设置 cell 的内容

  1.4 跳转界面 -> DetailViewController,界面的布局

  1.5 传递数据

  1.6 保存数据,刷新表格,利用闭包来实现

2. 设置UITableViewController

  2.1 ViewController 改为 继承 UITableViewController

  class ViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        print("viewDidLoad")
    }
  }

  2.2 Main.storyboard 删除 View Controller,添加 Table View Controller, Custom Class 选项卡中 Class 改为 ViewController,Table View Call 中 Identifler 中输入 Cell

3. 加载"数据",利用闭包模拟网络异步加载

  3.1 创建 Person.swift 模型

class Person: NSObject {
    @objc var name: String?
    @objc var age: Int = 0
    
    init(dict:[String:Any]){
        super.init()
        //字典转模型
        setValuesForKeys(dict)
    }
    
    //对象描述信息,有利于开发调试
    //类似于 java 中的 toString() 函数
    //开发时,在模型中 实现此属性/方法
    override var description: String{
        let keys = ["name","age"]
        //模型转字典 - 网络的 POST JSON
        return "\(dictionaryWithValues(forKeys: keys))"
    }
}

  3.2 数据处理 

//MARK: - 数据处理
//extension 类似于 OC 中的分类,可以将控制器的代码分组,便于维护和管理
extension ViewController{

    //加载数据 -> 字典数组 -> 模型数组
    private func loadData(completion:@escaping (_ array: [Person]) -> ()){
        DispatchQueue.global().async {
            print("耗时操作")
            //拼接个人信息数组
            //1.创建数组
            var dataList = [Person]()
            
            //2.循环生成模拟数据
            for i in 0..<50 {
                let name = "xiaoxiao \(i)"
                //生成一个 18至22的随机数
                let age = Int.random(in: 17...22)
                //建立字典
                let dict:[String:Any] = ["name":name,"age":age]
                //字典转模型
                dataList.append(Person(dict: dict))
            }
            //测试数据
            //print(dataList)

            DispatchQueue.main.async {
                //完成回调
                print("完成回调")
                completion(dataList)
            }
        }
    }

  3.3 调用函数

class ViewController: UITableViewController {
    //个人数据数组
    private var persons: [Person]?
    
    override func viewDidLoad() {
        super.viewDidLoad()
       
        loadData { array in
            //记录接收到回调参数
            self.persons = array
            
            //刷新表格
            self.tableView.reloadData()
        }
    }
}

  3.4 数据源方法

//MARK: - 数据源方法
extension ViewController{

    //设置行高
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 65
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //如果 persons 数组为 nil,直接返回 0
//        if persons != nil{
//            return persons!.count
//        }else {
//            return 0
//        }
        return persons?.count ?? 0
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        //persons!: 只有数据源 才会执行此方法
        cell.textLabel?.text = persons![indexPath.row].name
        return cell
    }
}

4. 自定义 Cell,绑定 Cell

  4.1 自定义 Cell,创建 PersonCell.swift

class PersonCell: UITableViewCell {
    //个人模型 - Swift 中设置没模型可以用 didSet
    var person: Person?{
        didSet{
            //不需要 使用 '_成员变量 = 变量',因为已经完成设置了
            // 当 person 模型被设置值完成后,执行的代码
            nameLable.text = person?.name
            ageLabel.text = "\(person?.age ?? 0)"
        }
    }
    @IBOutlet weak var nameLable: UILabel!
    @IBOutlet weak var ageLabel: UILabel!
}

  4.2 ViewController.swift 中绑定 Cell

 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //模型查询可重用 cell 返回 UITableViewCell 没有 PersonCell 的属性
        //使用 as 转类型
        //通常使用 as 的时候,需要使用 ? 或者 !
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PersonCell
        //persons!: 只有数据源 才会执行此方法
        //persons 是一定有内容的
        cell.person = persons![indexPath.row]
        //cell.textLabel?.text = persons![indexPath.row].name
        return cell
    }

5. 明细界面搭建和连线

  5.1 将Table View Controller 设置导航栏控制器/Navigation Controller:

  操作步骤:选择 Main.storybord 中 View Controller,菜单栏选择 Editor -> Embed In -> Navigation Controller 

  5.2 添加信息 View Controller,点击 Table View 中的 Cell,按住 Ctrl 进行连线 show,个人明细界面布局,Custom Class 选项中选择 DetailViewController

  5.3 创建 DetailViewController.swift

class DetailViewController: UIViewController {
    @IBOutlet weak var nameText: UITextField!
    @IBOutlet weak var ageText: UITextField!
    
    //保存按钮
    @IBAction func save(_ sender: Any) {
        print("save")
    }
    
    //文本变化
    @IBAction func textChanged() {
       //如果 两个输入框都有内容,才允许保存
        navigationItem.rightBarButtonItem?.isEnabled =  nameText.hasText && ageText.hasText
    }
  
    override func viewDidLoad() {
        super.viewDidLoad()
    }
   }

6. 传递数据

  6.1 DetailViewController.swift 添加数据更新

class DetailViewController: UIViewController {
    @IBOutlet weak var nameText: UITextField!
    @IBOutlet weak var ageText: UITextField!
    
    //数据模型
    var person: Person?
//    {
//        didSet{
//            //在传递数值的时候,控制器已经被创建,但是控制器的视图没有被创建!
//            //视图没有被创建,那么字视图同样没有创建
//            //EXC_BAD_INSRTRUCTION 野指针异常??
//            //一旦使用了 view 如果 view == nil, 会调用 loadView() 创建 view 以子视图
//            //print(view)
//            //nameText.text = person?.name
//            //ageText.text = "\(person?.age ?? 0)"
//        }
//    }

    //保存按钮
    @IBAction func save(_ sender: Any) {
        print("save")
    }
    
    //文本变化
    @IBAction func textChanged() {
       //如果 两个输入框都有内容,才允许保存
        navigationItem.rightBarButtonItem?.isEnabled =  nameText.hasText && ageText.hasText
    }
   
    override func viewDidLoad() {
        super.viewDidLoad()
        nameText.text = person?.name
        ageText.text = "\(person?.age ?? 0)"
        //激活按钮
        textChanged()
    }
}

  6.2 ViewController.swift 添加传递参数

class ViewController: UITableViewController {
    //个人数据数组
    private var persons: [Person]?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        loadData { array in
            //记录接收到回调参数
            self.persons = array
            //刷新表格
            self.tableView.reloadData()
        }
    }

    //从一个 VC 跳转到另一个 VC 调用的方法
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //1. 拿到目标控制器
        guard let detailVC = segue.destination as? DetailViewController else{
            return
        }
        //2.获取用户当前选中行数据
       guard let indexPath = tableView.indexPathForSelectedRow else{
            return
        }
        //detailVC & indexPath 全部拿到
        //3.根据 indexPath 获取 Person 数据
        print(persons![indexPath.row])
        //传递数据
        detailVC.person = persons![indexPath.row]
    }
}

7. 保存数据,刷新表格

  7.1 DetailViewController.swift 添加闭包回调

    //定义闭包属性
    var didSaveCallBack: (() -> ())?    
    var didParamSaveCallBack: ((_ person: Person) ->())?

  7.2 保存按钮事件

    //保存按钮
    @IBAction func save(_ sender: Any) {
       //1.使用 UI 更新模型
        person?.name = nameText.text
        //第一个 ! 保证一定有字符串内容
        //第二个 ! 保证一定能转换成整数
        person?.age = Int(ageText.text!) ?? 0
        //print(person)
        //2.完成回调,通知控制器刷新数据 - 闭包
        //? 表示闭包不存在,就不执行 -> OC 中调用 block 之前一定要判断!
        //如果强行解包,同时没有数值,会崩溃
        //didSaveCallBack?()
        didParamSaveCallBack?(person!)
        navigationController?.popViewController(animated: true)
    }

  7.3 ViewController.swift 更新表格

    //从一个 VC 跳转到另一个 VC 调用的方法
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //1. 拿到目标控制器
        guard let detailVC = segue.destination as? DetailViewController else{
            return
        }
        //2.获取用户当前选中行数据
       guard let indexPath = tableView.indexPathForSelectedRow else{
            return
        }
        //detailVC & indexPath 全部拿到
        //3.根据 indexPath 获取 Person 数据
        print(persons![indexPath.row])
        //4.传递数据
        //4.1 个人信息
        detailVC.person = persons![indexPath.row]
        //4.2 完成回调
//        detailVC.didSaveCallBack = {
//            //刷新表格
//            self.tableView.reloadData()
//        }
        //简写回调
        //detailVC.didSaveCallBack = self.tableView.reloadData
        //带参回调
        detailVC.didParamSaveCallBack = { param in
            print(param)
            self.tableView.reloadData()
        }
    }

8. 完成效果图

            

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hanyang Li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值