You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift新手求助:如何全局访问videoLink无需重复调用fetchBroadcasts

解决方案:缓存数据实现全局访问

Hey there!作为Swift初学者,你的思路已经很清晰啦,咱们来一步步解决这个不用重复调用网络请求就能全局访问videoLink的问题~

核心思路是在你的BroadService单例里缓存解析后的Games数据,这样后续需要获取videoLink时直接读取缓存即可,不用每次都发起网络请求。

修改后的完整代码

struct Games: Decodable { 
    let videoLink: String 
}

class BroadService { 
    // 保持单例模式不变
    static let sharedInstance = BroadService()
    
    // 新增:私有属性,用来缓存解析后的Games数组
    private var cachedGames: [Games]?
    
    // 新增:线程锁,保证多线程环境下缓存访问的安全性
    private let lock = NSLock()
    
    // 优化fetch方法:支持强制刷新,优先返回缓存
    func fetchBroadcasts(forceRefresh: Bool = false, completion: @escaping ([Games]?) -> ()) {
        // 如果有缓存且不需要强制刷新,直接返回缓存内容
        if !forceRefresh, let cachedGames = self.cachedGames {
            completion(cachedGames)
            return
        }
        
        let jsonUrlString = "LINK IS HERE."
        guard let url = URL(string: jsonUrlString) else { 
            completion(nil) 
            return 
        }
        
        URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
            guard let self = self else { return }
            
            guard let data = data else {
                print("Failed to get data from network")
                completion(nil)
                return
            }
            
            do {
                let games = try JSONDecoder().decode([Games].self, from: data)
                // 加锁更新缓存,避免多线程竞态问题
                self.lock.lock()
                self.cachedGames = games
                self.lock.unlock()
                
                completion(games)
            } catch let jsonError {
                print("Error deserializing JSON: \(jsonError.localizedDescription)")
                completion(nil)
            }
        }.resume()
    }
    
    // 新增:直接从缓存获取指定索引的videoLink
    func getVideoLink(at index: Int) -> String? {
        // 加锁读取缓存,保证线程安全
        lock.lock()
        defer { lock.unlock() }
        
        guard let games = cachedGames, index >= 0, index < games.count else {
            return nil
        }
        return games[index].videoLink
    }
}

怎么使用?

  1. 首次加载/刷新数据:
    还是用你原来的方式调用fetchBroadcasts,如果需要强制刷新最新数据(比如下拉刷新),可以传forceRefresh: true:

    BroadService.sharedInstance.fetchBroadcasts(forceRefresh: true) { games in
        // 这里可以做UI更新等操作
        if let games = games {
            print("Loaded \(games.count) broadcasts")
        }
    }
    
  2. 全局访问videoLink:
    之后任何地方需要获取指定索引的videoLink,直接调用缓存读取方法即可,不用再发起网络请求:

    // 比如在tableView的cellForRow里
    if let videoLink = BroadService.sharedInstance.getVideoLink(at: indexPath.row) {
        // 使用videoLink做你需要的操作,比如加载视频
        print("Video link: \(videoLink)")
    }
    

关键细节说明

  • 线程安全:加入NSLock是因为网络请求的回调在后台线程,而UI线程可能同时读取缓存,加锁可以避免多线程访问时的竞态条件,防止数据错乱。
  • 缓存边界处理:getVideoLink方法里做了索引越界判断,避免数组越界崩溃。
  • 灵活性:forceRefresh参数让你可以主动触发数据更新,兼顾缓存效率和数据新鲜度。

如果你还有其他疑问,比如想实现缓存过期机制(比如缓存超过1小时就自动刷新),随时问哦~

内容的提问来源于stack exchange,提问作者George Constantine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:19:01