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

Swift MVC架构下解析JSON的listings并加载至UITableViewCell问题

我来帮你搞定这个MVC架构下的JSON解析和UITableView加载问题,咱们一步步来,先理清楚每个环节该怎么做:

第一步:先定义对应JSON的数据模型(Model层)

首先要给你的listings字段创建一个结构化的Model,比直接用字典更清晰,也能避免解析错误。假设你的JSON结构大概是这样(如果和你的实际结构有出入,调整属性即可):

示例JSON结构:

{
  "listings": [
    {
      "id": 1,
      "title": "Sample Product",
      "price": "$39.99",
      "imageUrl": "https://example.com/image1.jpg"
    },
    {
      "id": 2,
      "title": "Another Product",
      "price": "$19.99",
      "imageUrl": "https://example.com/image2.jpg"
    }
  ]
}

创建一个Listing.swift文件,定义模型:

import Foundation

// 单个listing的模型
struct Listing: Codable {
    let id: Int
    let title: String
    let price: String
    let imageUrl: String
}

// 对应整个JSON的根模型,用来解析外层的listings数组
struct ListingResponse: Codable {
    let listings: [Listing]
}
第二步:完善DataManager的数据获取逻辑(Model层)

DataManager负责数据的下载和解析,应该通过闭包回调的方式把解析好的listings数组传递给ViewController,不要用全局变量或者直接赋值,这样更符合MVC的职责分离。修改你的DataManager.swift:

import Foundation

class DataManager {
    // 用单例方便全局调用
    static let shared = DataManager()
    
    // 定义闭包回调,传递结果(成功返回数组,失败返回错误)
    func fetchListings(completion: @escaping (Result<[Listing], Error>) -> Void) {
        guard let requestUrl = URL(string: "你的JSON接口地址") else {
            completion(.failure(NSError(domain: "InvalidURL", code: -1, userInfo: [NSLocalizedDescriptionKey: "地址无效"])))
            return
        }
        
        URLSession.shared.dataTask(with: requestUrl) { data, _, error in
            // 先处理网络错误
            if let error = error {
                completion(.failure(error))
                return
            }
            
            guard let responseData = data else {
                completion(.failure(NSError(domain: "NoData", code: -2, userInfo: [NSLocalizedDescriptionKey: "未获取到数据"])))
                return
            }
            
            // 解析JSON
            do {
                let decodedResponse = try JSONDecoder().decode(ListingResponse.self, from: responseData)
                completion(.success(decodedResponse.listings))
            } catch {
                completion(.failure(error))
            }
        }.resume()
    }
}
第三步:在ViewController中接收数据并配置UITableView(Controller层)

ViewController作为控制器,负责从DataManager拿数据、更新UI,同时实现UITableView的数据源方法。修改你的ViewController.swift:

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    // 存储listings数据的数组
    private var listings: [Listing] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
        loadListingsData()
    }
    
    private func setupTableView() {
        tableView.delegate = self
        tableView.dataSource = self
        // 注册cell:如果是系统默认cell,直接注册;如果是自定义cell,替换成对应的xib或者类
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "ListingCell")
    }
    
    private func loadListingsData() {
        DataManager.shared.fetchListings { [weak self] result in
            // 网络请求在后台线程,必须切回主线程更新UI
            DispatchQueue.main.async {
                switch result {
                case .success(let fetchedListings):
                    self?.listings = fetchedListings
                    self?.tableView.reloadData()
                case .failure(let error):
                    print("数据加载失败:\(error.localizedDescription)")
                    // 这里可以给用户显示错误提示,比如弹出Alert
                }
            }
        }
    }
}

// MARK: - UITableView 数据源与代理
extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // 返回listings数组的长度
        return listings.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ListingCell", for: indexPath)
        let currentListing = listings[indexPath.row]
        // 配置cell内容,这里用系统默认cell举例,自定义cell的话直接操作对应的控件即可
        cell.textLabel?.text = currentListing.title
        cell.detailTextLabel?.text = currentListing.price
        return cell
    }
}
常见失败原因排查

如果还是不行,你可以检查这几个点:

  • 是否在主线程更新UI:网络请求是后台线程,必须用DispatchQueue.main.async包裹tableView.reloadData(),否则UI不会刷新
  • 模型结构和JSON是否匹配:检查Listing的属性名、类型和JSON里的字段完全一致,不一致的话可以用CodingKeys做映射
  • UITableView是否注册了cell:没注册cell会直接崩溃,自定义cell要记得注册对应的xib或者类
  • 接口权限问题:iOS 14+如果用HTTP接口,需要在Info.plist里添加NSAppTransportSecurity的例外配置
  • DataManager的回调是否正确:有没有正确传递解析后的数组,有没有处理错误情况

内容的提问来源于stack exchange,提问作者Ferrakkem Bhuiyan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 23:12:54