无法使用 json 数据填充 UITableview

Posted

技术标签:

【中文标题】无法使用 json 数据填充 UITableview【英文标题】:Cannot populate UITableview with json data 【发布时间】:2019-03-18 13:06:26 【问题描述】:

我有一个本地 json 文件(你可以找到它here)。

我正在尝试使用此 json 填充 UITableView,然后我可以生成表格。

但我只能看到提到的标题,而不是这些标题单元格下方的相应数据。

我会在下面发布一些代码,如果有帮助可以分享更多

enum ProfileViewModelItemType 
    case nameAndPicture
    case about
    case email
    case friend
    case attribute


protocol ProfileViewModelItem 
    var type: ProfileViewModelItemType  get 
    var rowCount: Int  get 
    var sectionTitle: String   get 


extension ProfileViewModelItem 
    var rowCount: Int 
        return 1
    


class ProfileViewModelNameItem: ProfileViewModelItem 
    var type: ProfileViewModelItemType 
        return .nameAndPicture
    

    var sectionTitle: String 
        return "Main Info"
     


class ProfileViewModelNameAndPictureItem: ProfileViewModelItem 
    var type: ProfileViewModelItemType 
        return .nameAndPicture
    

    var sectionTitle: String 
        return "Main Info"
    

    var rowCount: Int 
        return 1
    

    var pictureUrl: String
    var name: String

    init(name: String , pictureUrl: String) 
        self.name = name
        self.pictureUrl = pictureUrl
    


class ProfileViewModelAboutItem: ProfileViewModelItem 
    var type: ProfileViewModelItemType 
        return .about
     

    var sectionTitle: String 
        return "About"
    
    var rowCount: Int 
        return 1
    

    var about: String

    init(about: String) 
        self.about = about
    


class ProfileViewModelEmailItem: ProfileViewModelItem 
    var type: ProfileViewModelItemType 
        return .email
    

    var sectionTitle: String 
        return "Email"
    
    var rowCount: Int 
        return 1
    
    var email: String

    init(email: String) 
        self.email = email
    


class ProfileViewModelAttributeItem: ProfileViewModelItem 
    var type: ProfileViewModelItemType 
        return .attribute
    

    var sectionTitle: String 
        return "Attributes"
    

    var rowCount: Int 
        return attributes.count
    

    var attributes: [Attribute]

    init(attributes: [Attribute]) 
        self.attributes = attributes
    


class ProfileViewModeFriendsItem: ProfileViewModelItem 
    var type: ProfileViewModelItemType 
        return .friend
    

    var sectionTitle: String 
        return "Friends"
    

    var rowCount: Int 
        return friends.count
    

    var friends: [Friend]

    init(friends: [Friend]) 
        self.friends = friends
    


class ProfileViewModel: NSObject 
    var items = [ProfileViewModelItem]()

    override init() 
        super.init()
        guard let data = dataFromFile("ServerData"), let profile =  Profile(data: data) else 
            return
        

        if let name = profile.fullName, let pictureUrl = profile.pictureUrl 
            let nameAndPictureItem = ProfileViewModelNameAndPictureItem(name: name, pictureUrl: pictureUrl)
            items.append(nameAndPictureItem)
        

        if let about = profile.about 
            let aboutItem = ProfileViewModelAboutItem(about: about)
            items.append(aboutItem)
        

        if let email = profile.email 
            let dobItem = ProfileViewModelEmailItem(email: email)
            items.append(dobItem)
        

        let attributes = profile.profileAttributes
        // we only need attributes item if attributes not empty
        if !attributes.isEmpty 
             let attributesItem = ProfileViewModelAttributeItem(attributes: attributes)
            items.append(attributesItem)
        

        let friends = profile.friends
        // we only need friends item if friends not empty
        if !profile.friends.isEmpty 
            let friendsItem = ProfileViewModeFriendsItem(friends: friends)
             items.append(friendsItem)
        
    


extension ProfileViewModel:UITableViewDataSource 


    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
        return items[section].sectionTitle
    

    func numberOfSections(in tableView: UITableView) -> Int 
        return items.count
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return items[section].rowCount
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let item = items[indexPath.section]
        switch item.type 
        case .nameAndPicture:
            if let cell = tableView.dequeueReusableCell(withIdentifier: NameAndPictureCell.identifier, for: indexPath) as? NameAndPictureCell 
                cell.item = item
                return cell
            
        case .about:
            if let cell = tableView.dequeueReusableCell(withIdentifier: AboutCell.identifier, for: indexPath) as? AboutCell 
                cell.item = item
               return cell
            
        case .email:
            if let cell = tableView.dequeueReusableCell(withIdentifier: EmailCell.identifier, for: indexPath) as? EmailCell 
                cell.item = item
                return cell
            
        case .friend:
            if let item = item as? ProfileViewModeFriendsItem, let cell = tableView.dequeueReusableCell(withIdentifier: FriendCell.identifier, for: indexPath) as? FriendCell 
                let friend = item.friends[indexPath.row]
                cell.item = friend
                return cell
            
        case .attribute:
            if let item = item as? ProfileViewModelAttributeItem, let cell = tableView.dequeueReusableCell(withIdentifier: AttributesCell.identifier, for: indexPath) as? AttributesCell 
                cell.item = item.attributes[indexPath.row]
               return cell
            
        

        // return the default cell if none of above succeed
        return UITableViewCell()
    



public func dataFromFile(_ filename: String) -> Data? 
    @objc class TestClass: NSObject  

    let bundle = Bundle(for: TestClass.self)
    if let path = bundle.path(forResource: filename, ofType: "json") 
        return (try? Data(contentsOf: URL(fileURLWithPath: path)))
    
    return nil


class Profile 
    var fullName: String?
    var pictureUrl: String?
    var email: String?
    var about: String?
    var friends = [Friend]()
    var profileAttributes = [Attribute]()

    init?(data: Data) 
        do 
             if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
                let body = json["data"] as? [String: Any] 
                self.fullName = body["fullName"] as? String
                self.pictureUrl = body["pictureUrl"] as? String
                self.about = body["about"] as? String
                self.email = body["email"] as? String

                if let friends = body["friends"] as? [[String: Any]] 
                    self.friends = friends.map  Friend(json: $0) 
                

                if let profileAttributes = body["profileAttributes"] as? [[String: Any]] 
                    self.profileAttributes = profileAttributes.map  Attribute(json: $0) 
                
            
         catch 
            print("Error deserializing JSON: \(error)")
            return nil
        
    


class Friend 
    var name: String?
    var pictureUrl: String?

    init(json: [String: Any]) 
        self.name = json["name"] as? String
        self.pictureUrl = json["pictureUrl"] as? String
    


class Attribute 
    var key: String?
    var value: String?
    init(json: [String: Any]) 
        self.key = json["key"] as? String
        self.value = json["value"] as? String
    
 

表格视图不仅应该包含朋友的名字,还应该包含资产中存在的图像。

我还为所有不同类型的单元格定义了自定义类,并将它们出列并注册了它们

已经看了一个星期了,但还是没有,任何帮助将不胜感激

我还提供了框架并将所有标签、图像等作为子视图添加到表格视图中,但没有运气

【问题讨论】:

【参考方案1】:

我有点难以理解。首先,“我还提供了框架并将所有标签、图像等作为子视图添加到表视图中”听起来是错误的。你永远不需要在 UITableView 上调用addSubview(...)。您可以通过 tableCell.contentView.addSubview(...) 将 UI 元素添加到 UITableViewCell,但即便如此,您最好使用自动布局在界面构建器中设计表格视图单元格。现在设置框架几乎没用了,因为自动布局已经永远存在了。唯一设置实际帧的地方是layoutSubviews()

其次,它不显示是因为您将 rowHeight 设置为常量而不是 UITableView.automaticDimension 吗?也许您的单元格设计为特定高度,但您没有告诉表格视图它们具有该高度?我建议使用谷歌搜索“自动调整大小的表格单元格”或使用表格视图委托方法...heightForRowAt indexPath: ...

最后,查看您的代码,我建议您对 JSON 解析方法进行现代化改造:

类似this,或者只是谷歌“JSON 和 Codable swift”

【讨论】:

添加到表格视图是一个绝望的措施,当没有工作时,我在视图控制器中调用了自动尺寸,我没有使用界面生成器构建,但全部通过代码,我已经将框架设置为整个屏幕使用CGRect 在我看来,您在这方面没有太多经验。什么框架?恐怕很难回答你的问题。您的问题似乎有 2 个组成部分:首先将 JSON 数据解析为模型,然后使用这些模型填充表视图。可能使用自动调整大小的表格单元格。我建议在 raywenderlich.com 上做一些教程 horseshoe7,是的,我对 swift 本身还是很陌生,我已经完成了这篇文章,但在这种特殊情况下无法帮助我。我想我还是会尝试一下并回复你

以上是关于无法使用 json 数据填充 UITableview的主要内容,如果未能解决你的问题,请参考以下文章

从 UITableView 中删除顶部填充

使用 JSON 数据填充 INPUT 和 SELECT

使用 JSON 数据填充 HTML 表

如何使用大型 json 数据填充 RecyclerView [重复]

无法将json数组填充到数组列表android开发

使用 JSON 和 AFNetworking NSDictionary 使用数据填充 tableview