UITableViewCell 如何知道从数组或字典中加载啥 JSON

Posted

技术标签:

【中文标题】UITableViewCell 如何知道从数组或字典中加载啥 JSON【英文标题】:How can a UITableViewCell know what JSON to load from an Array or DictionariesUITableViewCell 如何知道从数组或字典中加载什么 JSON 【发布时间】:2016-04-22 10:32:12 【问题描述】:

假设我有一个包含 3 个 JSON 字典的数组,每个字典都有自己的类型(演示、条目、评论)。

[

    "_id": "random ID",
    "profile": "random ID Profile",
    "demo": 
        "_id": "random ID",
        "profile": 
            "_id": "random ID",
            "name": "name",
            "username": "username",
            "description": "description",
            "picture": "/picture"
        ,
        "path": "/path",
        "created": "date"
    ,
    "type": "demo",
    "source": "570aa8f647a70780a7111e91",
    "__v": 0,
    "created": "date"
,

    "_id": "random ID",
    "comment": "random comment ID",
    "type": "comment",
    "source": "57077c4e356c10371ca91ad9",
    "__v": 0,
    "created": "date"
,

    "_id": "random ID",
    "entry": "random entry ID",
    "type": "entry",
    "source": "57077c4e356c10371ca91ad9",
    "__v": 0,
    "created": "date"

]

现在我正在检查请求中的类型,所以我只得到了演示。

    func getTimeline(urlString: NSURL, completion: ([ModelDemos]) -> Void) 
    Alamofire.request(.GET, urlString).responseJSON  response in

        if let httpResponse = response.response 
            switch httpResponse.statusCode 
            case 200:
                var modelTimeline = [ModelDemos]()

                if let demos = response.result.value as? [JSONDictionary] 
                    for demo in demos 
                        if let type = demo["type"] as? String 
                            if type == "demo" 
                                if let demo = demo["demo"] as? JSONDictionary 
                                    let JSON = ModelDemos(data: demo)
                                    modelTimeline.append(JSON)
                                
                            
                        
                    
                 else  print("not working") 

                dispatch_async(dispatch_get_main_queue()) 
                    completion(modelTimeline)
                    print("Am I back on the main thread ? Response: \(NSThread.isMainThread())")
                
            default:
                return
            
        
    

在我的 TimelineViewController 中设置完成方法后

var timelineDemos = [ModelDemos]()

func runApiManagerTimeline() 
    guard let urlString = urlString else return
    apiManagerCurrentUserProfile.getTimeline(urlString, completion: didGetCurrentUserProfileDemos)


func didGetCurrentUserProfileDemos(demos: [ModelDemos]) 
    timelineDemos = demos
    timelineCollectionView.reloadData()

一切正常,我只得到演示字典,我可以将它加载到 DemoUITableViewCell。

现在我必须为数组中的每个 Dictionary 创建 3 种不同类型的 UITableViewCell。把它想象成一个 Facebook 订阅源,其中每个字典都不同,并且数量不断增长。

我如何告诉每个 Cell 应该加载什么内容?

【问题讨论】:

您的问题最后不清楚,请在您的问题中解释“告诉每个单元格应该加载哪些内容”的确切含义。你想拥有多少个细胞?每本词典 1 个? 这就像 Facebook 或 Instagram 应用程序上的通知选项卡,可能有无限数量的字典(单元格),但每个单元格都有自己的信息,并按每个通知的发出日期排序。跨度> 如果字典是 Demo 类型,我想在 DemoUItableViewCell 中加载该信息,如果字典是 Entry 类型,我想在 EntryUItableViewCell 中加载该信息,依此类推……但在JSON 响应给我的订单。 总是难以理解,但我已经尝试给出答案 【参考方案1】:

另一个使用自定义结构作为数据源数组模型的好例子。

首先创建一个enum 以将String 类型映射到enum 案例

enum DataType : String  case Demo = "demo", Comment = "comment", Entry = "entry" 

创建一个自定义的struct 项目作为数据源模型。声明三种数据类型的所有公共属性不带初始值,单个属性初始值以使用隐式成员初始化器创建Item实例并赋值取决于类型的各个属性。示例属性来自 JSON,仅作为示例

struct Item 
  // common properties
  var type : DataType
  var source : String
  var created : String

  // individual properties
  var username = ""
  var description = ""
  var picture = ""

在 TableView 控制器中创建数据源数组

var modelTimeline = [Item]()

并在解析 JSON 时创建 Item 实例

...
if let demos = response.result.value as? [JSONDictionary] 
  for demo in demos 
    if let type = demo["type"] as? String 
      let source = type["source"] ?? ""
      let created = type["date"] ?? ""
      var item = Item(type: DataType(rawValue:type), source: source, created: created)
      if type == "demo" 
        if let demo = demo["demo"] as? JSONDictionary, profile = demo["profile"] as? JSONDictionary 
          item.username = profile["username"] ?? ""
          item.description = profile["description"] ?? ""
          item.picture = profile["picture"] ?? ""
        
      
      modelTimeline.append(item)
    
  
 else  print("not working") 
...

cellForRowAtIndexPath 中创建单元格并根据类型为 UI 元素分配值

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
  let item = modelTimeline[indexPath.row]
  switch item.type 
    case .Demo:
    let cell = tableView.dequeueReusableCellWithIdentifier("DemoCell", forIndexPath: indexPath) as! DemoUItableViewCell
    cell.usernameLabel.text = item.username
    cell.descriptionLabel.text = item.description
    cell.sourceLabel.text = item.source
    // populate other UI elements
    return cell

    case .Comment:
    cell = tableView.dequeueReusableCellWithIdentifier("CommentCell", forIndexPath: indexPath)  as! CommentUItableViewCell
    cell.sourceLabel.text = item.source
    // populate other UI elements
    return cell

    case .Entry:
    cell = tableView.dequeueReusableCellWithIdentifier("EntryCell", forIndexPath: indexPath)  as! EntryUItableViewCell
    cell.sourceLabel.text = item.source
    // populate other UI elements
    return cell
  

代码不是一个完整的工作版本,它只是一个建议如何为不同的类型使用不同的单元格。

【讨论】:

这是一个最适合作为构建基础的框架,非常感谢!我将更新它在完整实施后的样子。 我喜欢您的代码,但我不同意“没有初始值的声明”,如果您的数据可以由 NSCoder 处理,您可能会遇到一些问题.. @AlessandroOrnano 如前所述,这是一个建议。但是没有初始值的声明仅意味着使用所需的成员初始化器将可靠地初始化公共变量的所有值,因为它们是非可选的。【参考方案2】:

使用这些方法:

    // MARK: - Table view Functions
override func numberOfSectionsInTableView(tableView: UITableView) -> Int 
    //3 because of 3 different dictionaries
    return 3


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
//Define the amount of rows for each section
    if (section == 0) 
        return --amount of entries in regarding dictionary--
     else if (section == 1) 
        return --amount of entries in regarding dictionary--
     else 
        return --amount of entries in regarding dictionary--
    


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
 if (indexPath.section == 0) 
      //Dict 1
  else if (indexPath.section == 1) 
      //Dict 2
  else 
      //Dict 3
 

【讨论】:

感谢您的回复,当您知道回复的确切数量以及每个回复必须在该部分中的位置时,这将很有效。将我的示例想象为 Facebook 提要,其中每个帖子都不同,您需要确定 Cell 需要加载的内容。【参考方案3】:

我认为您可以尝试自定义数据源,创建一个类(内部类或非内部类),例如:

class GeneralNotificationInfo: NSObject 
    var notificationTime:NSDate! = NSDate()
    enum notificationType: Int 
        case Demo = 1
        case Entry = 2
        case Test = 3
    
    var data:NSDictionary! = NSDictionary()
    ...

通过这种个性化,您可以轻松处理您的手机。

关于您的代码:

typealias AlamoNetSuccess = (result: NSDictionary?) -> Void
typealias AlamoNetProgress = (result: NSDictionary?) -> Void
typealias AlamoNetFailure = (error: NSDictionary?) -> Void

var params :[String: AnyObject]? = ["user": "David", "age": 40]

func getTimeline(urlString: NSURL,params: [String: AnyObject], success successBlock :AlamoNetSuccess,
        failure failureBlock :AlamoNetFailure) 
.request(.GET, url, parameters: params, encoding: ParameterEncoding.URL)
            .responseJSON  response in
                print("∙ ---")
                print("∙ Net URLs: \(response.request?.URL)")  // original URL request
                print("∙ ---")
                //print(response.response) // URL response
                //print(response.data)     // server data
                //print(response.result)   // result of response serialization
                if response.result.isSuccess 
                    let jsonDic = response.result.value as! NSDictionary
                    successBlock(result: jsonDic)
                 else 
                    let httpError: NSError = response.result.error!
                    let statusCode = httpError.code
                    let error:NSDictionary = ["error" : httpError,"statusCode" : statusCode]
                        failureBlock(error: error)
                


let wrappedNetSuccess: AlamoNetSuccess = (result: NSDictionary?) -> Void in // 
    print ("∙ Net Success: \(result)")
    // do whatever you want with your dictionary, parse it into datasource...


let wrappedAPIFailure: AlamoNetFailure = (error: NSDictionary?) -> Void in
    print ("∙ Net Failure: \(error)")
    // handle your network error with alertViews or other..


apiManagerCurrentUserProfile.getTimeline(urlString,params:[], success: wrappedAPISuccess, failure: wrappedAPIFailure)

【讨论】:

以上是关于UITableViewCell 如何知道从数组或字典中加载啥 JSON的主要内容,如果未能解决你的问题,请参考以下文章

编辑完成后如何从自定义uitableviewcell的文本字段向数组添加数据

多个 UITableViewCell 中的多个数组 [关闭]

设置从 HTML 字符串生成的 UITableViewCell 标签

Swift - 如何将数据从 UITableViewCell 类传递到 UIViewController

如何从 cgpoint 获取 UItableviewcell?

从函数或方法返回内存