在 swift collectionView 上遇到分页问题

Posted

技术标签:

【中文标题】在 swift collectionView 上遇到分页问题【英文标题】:Having troubles with pagination on swift collectionView 【发布时间】:2020-12-23 21:28:14 【问题描述】:

我的目标是在用户到达我的 collectionViewPokemon 末尾时加载更多信息,但我用来实现此目的的 getPokes 函数被调用 X 次,对应于我实现的 while 语句以获取来自其他端点的信息。这与我预期的行为相差甚远。

这就是我的代码的样子:

服务类

class Service 

let baseUrl = "https://pokeapi.co/api/v2/pokemon"
let limit = 20
var offset = 0
var isPaginating = false

func getPokes(pagination: Bool = false,
              handler: @escaping ([Pokemon]) -> Void) 
    
    let topCalls = (limit*5)-limit
    
    let originalPokes = [Pokemon]()
    let morePokemons = [Pokemon]()
    var endpoint = "\(baseUrl)/?limit=\(limit)&offset=\(offset)"
    
    if pagination 
        while offset < topCalls 
                isPaginating = true
                offset += limit
            
            endpoint = "\(baseUrl)/?limit=\(limit)&offset=\(offset)"
            
            self.mainApiCall(mainList: morePokemons, endpoint: endpoint)  (result) in
                switch result 
                case .success(let pokemons):
                    handler(pokemons)
                    
                    if pagination 
                        self.isPaginating = true
                    
                case .failure(let error):
                    print(error)
                
            
        
     else 
        self.mainApiCall(mainList: originalPokes, endpoint: endpoint)  (result) in
            switch result 
            case .success(let pokemons):
                handler(pokemons)
            case .failure(let error):
                print(error)
            
        
    

ViewController 类(属性)

class ViewController: UIViewController,
                  UICollectionViewDelegateFlowLayout,
                  UICollectionViewDelegate,
                  UICollectionViewDataSource,
                  UIScrollViewDelegate 

private let service = Service()
private var pagingChecker = false

var generalList = [Pokemon]()
var pokemons = [Pokemon]()
var morePokemons = [Pokemon]()

    . . .

viewDidLoad 方法(目前还可以)

    override func viewDidLoad() 
    super.viewDidLoad()
    
    setViews()
    service.getPokes(pagination: false)  [self] (pokes) in
        
        pokemons = pokes
        generalList += pokemons
        DispatchQueue.main.async 
            collectionViewPokemon?.reloadData()
        
        
    

scrollViewDidScroll 方法(这里是错误)

    func scrollViewDidScroll(_ scrollView: UIScrollView) 
    let position = scrollView.contentOffset.y
    if position > ((collectionViewPokemon!.contentSize.height) - 200 - scrollView.frame.size.height) 
        
        guard !service.isPaginating else  return 
        
        if !pagingChecker 
            service.getPokes(pagination: true)  [self] (morePokes) in
                
                morePokemons = morePokes
                generalList += morePokemons
                DispatchQueue.main.async 
                    collectionViewPokemon?.reloadData()
                
            
         else 
            pagingChecker = true
            print("Done paging.")
        
    

问题是我想一次只获取一个口袋妖怪数组,但我同时进行所有端点调用,并将它们附加到我的 generalList 数组中,该数组拥有我的 collectionView 数据源和所有这些东西。

PD:如果有帮助,我想知道,但这是我的控制台的屏幕截图。第一个消息没问题,但只有当用户到达 CollectionView 的末尾时它才应该打印其他消息,而且,这不会发生(相反,它们都会同时返回!)

我不知道如何完成这项工作。非常感谢任何建议或更正,谢谢。

【问题讨论】:

一个叫topCalls的人从哪里来的? 每次调用我会得到 20 个宠物小精灵(这是限制属性),所以我只使用 100 个宠物小精灵(并且只打 5 个电话)。 topCalls 只存储该计算,因此 while 语句一直运行直到达到所需的 pokemon 数量 【参考方案1】:

我知道发生了什么。我正在使用 while 语句重复我的 Api 调用,只要它满足它的条件(limit

所以,我想出了一些不使用该 while 语句的方法,并最终使用一个函数来构造每个 URL,然后设置一个 shouldPage 参数来检查是否需要执行该 apiCall。

我的代码是这样结束的:

let baseUrl = "https://pokeapi.co/api/v2/pokemon"
let limit = 20
var offset = 0

func getPokes(pageNumber: Int = 1,
              shouldPage: Bool = true,
              handler: @escaping ([Pokemon]) -> Void) 
    
    let originalPokes = [Pokemon]()
    let morePokemons = [Pokemon]()
    let endpoint = buildEndpoint(shouldPage: shouldPage)
    
    if  shouldPage 
            
            mainApiCall(mainList: morePokemons, endpoint: endpoint)  (result) in
                switch result 
                case .success(let pokemons):
                    handler(pokemons)
                case .failure(let error):
                    print(error)
                
            
     else 
        mainApiCall(mainList: originalPokes, endpoint: endpoint)  (result) in
            switch result 
            case .success(let pokemons):
                handler(pokemons)
            case .failure(let error):
                print(error)
            
        
    


private func buildEndpoint(shouldPage: Bool = false) -> String 
    
    var endpoint = "\(baseUrl)/?limit=\(limit)&offset=\(offset)"
    
    if shouldPage 
        offset += limit
        endpoint = "\(baseUrl)/?limit=\(limit)&offset=\(offset)"
    
    
    return endpoint

那是在我的服务课上。因此,在我的 CollectionView 数据源中,我在 cellForItemAt 上调用 getPokes(shouldPage: false),在 willDisplay 单元中我说 shouldPage 为 true。这解决了问题。

【讨论】:

以上是关于在 swift collectionView 上遇到分页问题的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 3 中使用 CGSize 的 collectionView 的 100% 宽度

Swift -collectionView 单元格内的属性在 collectionView.performBatchUpdates > reloadItems(at:) 运行后没有更新

collectionView 分为三行 swift 4

在 Swift 中以编程方式为 CollectionView 设置插图

Swift:如何以编程方式在 TableViewCell 中显示 CollectionView

Swift:按下collectionView项目时推送新视图