Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UITableViewController Basic #106

Open
soapgu opened this issue Feb 10, 2022 · 0 comments
Open

UITableViewController Basic #106

soapgu opened this issue Feb 10, 2022 · 0 comments
Labels

Comments

@soapgu
Copy link
Owner

soapgu commented Feb 10, 2022

  • 前言

UITableViewController虽然在前面的练习中有接触,但是并没做过系统性总结。
这篇的blog是怼UITableViewController基本用法的归纳。以及后面我想要做一个相对难一点的动态加载数据的一个预热,算是一个过渡章节吧

  • UITableView

首先UITableViewController和UITableView是配对一起使用的,和前面的控件有点不一样。而且是直接是以ViewController这个相对更高阶一点的层次。和它同级的都是Navigation Controller 和 Tab Controller这种。
这是一个真正意义上的数据集合控件,和数据紧密联系在一起,可以创建动态视图
和下面的控件类似
WPF:ItemSource、ListView
Andriod:RecyclerView

  • 最简实现

  1. 新建UITableViewController

我们还是通过Storyboard的接口来创建
删掉默认的UIViewController
直接+ UITableViewController,拖动到预览图里面
设置好 “Is Intial View Controller” 设为 true

  1. 修改ViewController的基类
    修改继承 “UIViewController” 改为 UITableViewController

  2. 在Storyboard里面修改UITableViewController
    再回到Main.storyboard 的IDE
    图片
    把关联的Class 从UITableViewController改到我们前面改的“ViewContoller”
    注:ViewController基类没改之前是上不去的

  3. 修改Table Cell
    通过IDE,Style改为“Basic”,Identifier加上“Item”为了以后Code的时候关联

  4. UITableViewDelegate&UITableViewDelegate
    图片
    通过右侧边栏点-> Show the connections inspector可以看到IDE已经帮我们设置好了UITableViewDelegate和UITableViewDelegate
    还有一个prefetchDataSource不知道是干啥的,这个我后面慢慢捋。

UITableViewDelegate都到ViewContoller上
再转到UITableViewController定义

@available(iOS 2.0, *)
open class UITableViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
...
}

由此可见UITableViewController是UIViewController的派生类,同时已经实现了UITableViewDelegate,UITableViewDataSource。

这里如果你看一些相对“老”一点的教程,UITableViewDataSource和UITableViewDataSource都要自己定义的。新版Swift帮我们整合一块了方便很多。

  1. 在ViewController实现 UITableViewDelegate&UITableViewDelegate 接口
    UITableViewController虽然实现了这两个接口,但是只是空载实现。真正和业务数据的绑定还需要我们进行override掉
  • 创建业务数据源
var dataSource = (0..<40).map { "item-\($0)" }

为了省事,随便弄点数据

  • 实现numberOfRowsInSection
    完整的签名是 tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int ,swift的函数命名有点意思,表意不再函数名而是参数名,这是要告诉UI,一共要显示多少行
    其中numberOfRowsInSection是章节,我们这里做single section,所以我们这里不care当前section的值(永远0)
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }
  • 实现cellForRowAt
    这个函数是实现怎么呈现一个单元格
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Item", for: indexPath)
        cell.textLabel?.text = dataSource[indexPath.row]
        return cell
    }

这里要说明下,tableView默认已经实现“虚拟化UI”的,每个cell都是复用的,所以我们需要调用dequeueReusableCell方法从单元格池里面去拿,有点类似线程池一样的概念。
直接显示下文字结束
图片

  • 加餐 UITableViewDataSourcePrefetching

前面说了prefetchDataSource不知道干啥的

不如直接看代码

// this protocol can provide information about cells before they are displayed on screen.

public protocol UITableViewDataSourcePrefetching : NSObjectProtocol {

    
    // indexPaths are ordered ascending by geometric distance from the table view
    @available(iOS 2.0, *)
    func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])

    
    // indexPaths that previously were considered as candidates for pre-fetching, but were not actually used; may be a subset of the previous call to -tableView:prefetchRowsAtIndexPaths:
    @available(iOS 2.0, *)
    optional func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath])
}

这个接口是预加载接口
第一个接口是返回要预加载数据的索引,第二个接口是取消预加载的数据索引

说的好像那么一回事,但是怎么都不“直观”

直接上代码加Log来看看两个api的效果

首先把prefetchDataSource关联上ViewController
图片

   func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
        print("prefetchRowsAt rows:\(productIndexStr( indexPaths))")
    }
    
    func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
        print("cancelPrefetchingForRowsAt rows:\(productIndexStr( indexPaths))")
    }
    
    func productIndexStr( _ indexPaths: [IndexPath] ) -> String {
        var indexStr = ""
        for index in indexPaths{
            indexStr += "\(index.row) "
        }
        return indexStr.trimmingCharacters(in: .whitespaces)
    }

swif的collection好像没有Linq的Aggregate函数这种写法的,只能for了接下来看看效果

  • 初始加载

图片

日志空空如也,说明初始化的那批数据并不会触发预加载。界面上显示了17条数据

往下拉

prefetchRowsAt rows:19 20 21 22 23 24 25 26 27 28
prefetchRowsAt rows:29
prefetchRowsAt rows:30
prefetchRowsAt rows:31
prefetchRowsAt rows:0
prefetchRowsAt rows:32
prefetchRowsAt rows:33
prefetchRowsAt rows:34
prefetchRowsAt rows:35
prefetchRowsAt rows:36
prefetchRowsAt rows:37
prefetchRowsAt rows:38
prefetchRowsAt rows:39
cancelPrefetchingForRowsAt rows:0
prefetchRowsAt rows:19 18 17 16 15 14 13 12 11 10
prefetchRowsAt rows:20

再拉到top

prefetchRowsAt rows:9
prefetchRowsAt rows:8
prefetchRowsAt rows:7
prefetchRowsAt rows:6
prefetchRowsAt rows:5
prefetchRowsAt rows:4
prefetchRowsAt rows:3
prefetchRowsAt rows:2
prefetchRowsAt rows:1
prefetchRowsAt rows:0
prefetchRowsAt rows:21 22 23 24 25 26 27 28 29 30
prefetchRowsAt rows:20
prefetchRowsAt rows:19
prefetchRowsAt rows:18

基本上可以看出来,他是对加载数据进行了一个“预测”

这个对静态数据没用,对动态加载数据有用

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant