Swift学习日记(3) --关于请求多个接口导致UI绘制顺序不正确及GCD

调用多个接口然后刷新列表导致加载顺序不正确

问题描述:在我写的controller里面 需要去请求三个接口:广告接口 九宫格接口 单曲接口

每个接口对应的是tableview里面每一个cell的数据,为了图省事,我把三个接口直接扔在viewdidload里面,然后在每个接口请求完数据之后刷新一下列表。
代码如下:

    override func viewDidLoad() {
        super.viewDidLoad()

        fetchDataAndUpdateUI()
        
    }

这个 fetchDataAndUpdateUI()是广告接口
在这个广告接口里面代码如下:

func fetchDataAndUpdateUI() {
        let position = 0
        let target:DefaultService = .ads(position: position)
        
        let cancellable = NetWorkManage.request(target, completion: { responseDict in
            // 解析成功的响应
            if let nestedData = responseDict["data"] as? [String: Any],
               let dataArray = nestedData["data"] as? [[String: Any]] {
                var ads = [Ad]()
                for adData in dataArray {
                    if let ad = Ad.deserialize(from: adData) {
                        ads.append(ad)
                    } else {
                        print("Failed to parse ad data.")
                    }
                }

                let bannerData = BannerData(ads)
                self.datum.removeAll()
                self.datum.append(bannerData)
                self.datum.append(ButtonData())
                self.sheets()
                
            } else {
                print("Nested data field not found in JSON or has incorrect format.")
            }
        }, fail: { networkError in
            // 处理请求失败的情况
            print("Network request failed with code: \(networkError.code ?? "") and message: \(networkError.message ?? "")")
        })
    }

重点是 self.sheets()在这里我调用了第二个九宫格数据接口,原来的话我是直接reloadData()刷新一下列表。
然后接着来看Sheets()这个接口
代码如下:

func sheets() {
        let size = 12
        let target:DefaultService = .sheets(size: size)
        
        let cancellable = NetWorkManage.request(target, completion: { responseDict in
            // 解析成功的响应
            if let nestedData = responseDict["data"] as? [String: Any],
               let dataArray = nestedData["data"] as? [[String: Any]] {
                var sheets = [Sheet]()
                for adData in dataArray {
                    if let sheet = Sheet.deserialize(from: adData) {
                        sheets.append(sheet)
                    } else {
                        print("Failed to parse ad data.")
                    }
                }
                
                self.datum.append(SheetData(sheets))
                self.loadSong()
            } else {
                print("Nested data field not found in JSON or has incorrect format.")
            }
        }, fail: { networkError in
            // 处理请求失败的情况
            print("Network request failed with code: \(networkError.code ?? "") and message: \(networkError.message ?? "")")
        })
    }

同样的 这里的重点是 请求了一下self.loadSong()请求了一下单曲数据
最后再来看一下loadSong里面的代码

func loadSong(){
        let size = 12
        let target:DefaultService = .songs
        
        let cancellable = NetWorkManage.request(target, completion: { responseDict in
            // 解析成功的响应
            if let nestedData = responseDict["data"] as? [String: Any],
               let dataArray = nestedData["data"] as? [[String: Any]] {
                var songs = [Song]()
                for adData in dataArray {
                    if let song = Song.deserialize(from: adData) {
                        songs.append(song)
                    } else {
                        print("Failed to parse ad data.")
                    }
                }
            
                self.datum.append(SongData(songs))
                self.tableView.reloadData()
            } else {
                print("Nested data field not found in JSON or has incorrect format.")
            }
        }, fail: { networkError in
            // 处理请求失败的情况
            print("Network request failed with code: \(networkError.code ?? "") and message: \(networkError.message ?? "")")
        })
    }

请求完loadSong之后 我才调用self.tableView.reloadData()来刷新整个tableview
这样嵌套的话就不会出现cell绘制的过程中顺序错误。

当然其实这只能说是最低端的写法,只是给初学者进行参考(ps:我也是),但是查阅资料学习的过程中发现了问题。

其实优化一下的话是要用gcd来进行并发处理请求回来这三个数据之后再去reloadData()刷新列表,但我还没用上。

我问的GPT代码贴到下方:

class DiscoveryController: UIViewController {

    // ... 省略了其他代码

    override func viewDidLoad() {
        super.viewDidLoad()
        // ... 省略了其他代码
        fetchDataAndUpdateUI()
    }

    func fetchDataAndUpdateUI() {
        let group = DispatchGroup()

        group.enter()
        fetchAdsData(group: group)

        group.enter()
        fetchSheetsData(group: group)

        group.notify(queue: .main) {
            self.tableView.reloadData()
        }
    }

    func fetchAdsData(group: DispatchGroup) {
        // ... 省略了网络请求的代码,保持和之前一样的逻辑
        // 记得在请求完成或失败后调用 group.leave()
    }

    func fetchSheetsData(group: DispatchGroup) {
        // ... 省略了网络请求的代码,保持和之前一样的逻辑
        // 记得在请求完成或失败后调用 group.leave()
    }

    // ... 省略了其他代码

}

这里就是等待三个接口都请求回来数据然后再进行刷新
当然肯定不止这种方法,如果可以的话希望多多给我这个菜鸟意见我会认真学习。

那我写的方法和这个gcd的区别是什么呢,是耗时问题,这里不再多说。一层层依赖的请求一个之后再请求另外一个接口的耗时肯定是要比并发用GCD方式耗时要长。

其实当我修改完正确代码我并不清楚问题发生的原因,然后我去问GPT
给我的回答如下

这个问题可能源自于多个网络请求导致的数据加载和刷新问题。当每个接口请求数据并且刷新 tableView 时,数据的加载顺序和速度可能会有所不同,从而导致显示混乱。

在你最初的方法中,每个接口请求都会触发 tableView.reloadData(),这意味着每个接口完成都会导致整个表格刷新。如果这些网络请求的完成顺序与你期望的不一致,就会导致 UI 上的显示问题,出现数据错乱或九宫格和单曲数据交错显示的情况。

使用 GCD 或者串行请求的方式可以确保你按照正确的顺序获取和处理数据,然后在所有数据都准备好后再一次性刷新 tableView。这样可以避免多个接口请求导致的显示混乱问题。

另外,也可以检查数据模型的赋值和对应的 UI 绑定是否正确。确保每个数据源和对应的 cell 显示的数据是匹配的,避免数据源出现错位或重叠的情况。

最重要的是要确保在刷新 tableView 之前,数据已经完全准备好,否则可能导致显示上的混乱。

以上是本节内容,希望有错误大佬们指正。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值