简体   繁体   English

为什么我无法用填充有从json提取的数据的单元格填充uiTableView?

[英]Why I can't populate my uiTableView with cells filled with data fetched from json?

This is my class: 这是我的课:

import UIKit
import SwiftyJSON

class ListOfEvents: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var tableView:UITableView?
    var items = NSMutableArray()

    override func viewDidLoad() {
        let frame:CGRect = CGRect(x: 0, y: 100, width: self.view.frame.width, height: self.view.frame.height-100)
        self.tableView = UITableView(frame: frame)
        self.tableView?.dataSource = self
        self.tableView?.delegate = self
        self.view.addSubview(self.tableView!)
        print("aaa")
        getAllRequests()

    }


    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        tableView.registerClass(SingleEventCell.self, forCellReuseIdentifier: "cell")
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! SingleEventCell

        let user:JSON =  JSON(self.items[indexPath.row])
       print(user["username"].description)
       // cell.username.text = user["username"].description
       // cell.descr.text = "ggg"
        print(cell)
        return cell
    }

    func getAllRequests() {
        print("getAllRequests")
        RestApiManager.sharedInstance.getRequests { json in
            let results = json//["username"]
            for (index: String, subJson: JSON) in results {
                let user: AnyObject = JSON.object
                self.items.addObject(user)
                dispatch_async(dispatch_get_main_queue(),{
                    self.tableView?.reloadData()
                })
            }
        }
    }

}

I try to fill my custom UITableViewCell s with data fetched from webservice. 我尝试用从Web服务获取的数据填充自定义UITableViewCell My problem is that: 我的问题是:

print(user["username"].description) //that prints perfectly

but if I uncomment one of the lines below: 但是,如果我取消注释以下行之一:

// cell.username.text = user["username"].description 
// cell.descr.text = "ggg"

I'm getting the error: 我收到错误消息:

fatal error: unexpectedly found nil while unwrapping an Optional value

I suspect that I try to refer to the cells before they are initialized/visible for the algorithm, but if so - how can I prevent it? 我怀疑我尝试在对算法进行初始化/可见之前引用这些单元格,但是如果是这样,我该如何防止呢? I'm using viewDidLoad() method but that doesn't change anything - the error is still the same. 我正在使用viewDidLoad()方法,但是它什么都没有改变-错误仍然相同。

How can I fix it? 我该如何解决?

====EDIT ====编辑

@vadian suggested that it's a different table view in storyboard and in the code.I went with that advice and created an outlet for the tableview from storyboard and in all places in code changed the reference from tableview to newly created outlet: @vadian建议,它在情节串连图板,并在code.I不同的表视图去与建议创建了一个出口从故事板的tableview,并在代码中的所有地方改变从参考tableview到新形成的出口:

import UIKit import SwiftyJSON 导入UIKit导入SwiftyJSON

class ListOfEvents: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tview: UITableView!
    var tableView:UITableView?
    var items = NSMutableArray()

    override func viewDidLoad() {
        let frame:CGRect = CGRect(x: 0, y: 100, width: self.view.frame.width, height: self.view.frame.height-100)
        tview = UITableView(frame: frame)
        tview.dataSource = self
        tview.delegate = self
        self.view.addSubview(tview!)
        print("aaa")
        getAllRequests()

    }


    func tableView(tview: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }

    func tableView(tview: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        tview.registerClass(SingleEventCell.self, forCellReuseIdentifier: "cell")
        let cell = tview.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! SingleEventCell

        let user:JSON =  JSON(self.items[indexPath.row])
       print(user["username"].description)
       // cell.username.text = user["username"].description
        cell.descr.text = "ggg"
        print(cell)
        return cell
    }

    func getAllRequests() {
        print("getAllRequests")
        RestApiManager.sharedInstance.getRequests { json in
            let results = json
            for (index: String, subJson: JSON) in results {
                let user: AnyObject = JSON.object
                self.items.addObject(user)
                dispatch_async(dispatch_get_main_queue(),{
                    self.tview.reloadData()
                })
            }
        }
    }

}

But now when I run it I'm getting error; 但是现在当我运行它时,我得到了错误;

fatal error: unexpectedly found nil while unwrapping an Optional value

here: 这里:

tview.dataSource = self

Is there a way to fix it? 有办法解决吗?

One obvious problem is this line: 这行是一个明显的问题:

tview = UITableView(frame: frame)

That is not how you create a table view in code. 这不是您在代码中创建表视图的方式。 You must call its designated initializer , which is initWithFrame:style: . 您必须调用其指定的初始化程序 ,它是initWithFrame:style: For example: 例如:

tview = UITableView(frame: frame, style: .Plain)

Note, however, that your code has various other problems that could also be an issue here. 但是请注意,您的代码还有其他各种问题,在这里也可能是一个问题。 For example, this line: 例如,这一行:

let frame:CGRect = CGRect(x: 0, y: 100, width: self.view.frame.width, height: self.view.frame.height-100)

That line depends on self.view having a frame, and a frame of sufficient size (ie more than 100 pixels in height). 那条线取决于self.view有一个框架和一个足够大的框架(即高度超过100个像素)。 But you don't know this, because in viewDidLoad , self.view merely exists — it has not yet achieved its final frame because it has not yet been put into the interface and laid out. 但是您不知道这一点,因为在viewDidLoadself.view存在 —由于尚未放入接口并进行布局,因此尚未达到最终框架。 So that line is very risky at that point. 因此,那条线在那时非常冒险。

I'm guessing that you probably don't have your username and/or descr outlets set up correctly inside your SingleEventCell . 我猜测您可能在SingleEventCell正确设置username和/或descr出口。

Take a look here to know how to connect your outlets correctly. 在这里看看如何正确连接插座。

Your problem is, that your JSON object is not yet fetched at the time tableView.cellForRowAtIndexPath wants to load it, therefor giving you an unexpectedly found nil error. 您的问题是, tableView.cellForRowAtIndexPath要加载它时尚未提取JSON对象,因此给您一个意外发现的nil错误。

What You can do is this: 您可以执行以下操作:

Create a new Delegate protocol: 创建一个新的委托协议:

protocol NetworkingDelegate {

    func didFinishLoadingData()
}

Create a class Networking where you put your API request in: 创建一个类Networking ,您可以在其中放置API请求:

class Networking {

var networkingDelegate: NetworkingDelegate?


// (I am using Alamofire here so the function itself will differ a little.)

    func getAllRequests() {

        Alamofire.request(.GET, "YOUR_API_ENDPOINT")
            .responseJSON { response in

                if response.result.isSuccess {
                    let jsonObject = JSON(response.result.value!)

                    User.populateUserDataSourceFromJSON(jsonObject)

                    self.dispatchAndRefresh()
                }
        }
    }
}


func dispatchAndRefresh() {
    dispatch_async(dispatch_get_main_queue()) {
        if let delegate = self.networkingDelegate {
            delegate.didFinishLoadingData()
        }
    }
}

In your Modelclass have a function called populateUserDataSourceFromJSON 在您的Modelclass中,有一个名为populateUserDataSourceFromJSON的函数

class User {

let name = String()
let age = Int()
//...

init() {
}


class func populateUserDataSourceFromJSON(json: JSON) {

    userDataSource = [User]()

    for (_, user): (String, JSON) in json {

        let currentUser = User()

        currentUser.name = user["name"].stringValue
        currentUser.age = user["age"].intValue
        //...

        userDataSource.append(currentUser)
    }
}

In your ViewController add the Delegate we created: 在您的ViewController中,添加我们创建的Delegate:

class ListOfEvents: UIViewController, UITableViewDataSource, UITableViewDelegate, NetworkingDelegate { 
    //...

create a reference of your Networking class: 创建您的网络类的引用:

let networking = Networking()

and set it's delegate to self: 并将其委托设置为self:

override func viewDidLoad() {
    super.viewDidLoad()

    networking.networkingDelegate = self
    //...

Only thing left to do is to make your ViewController conform to the Delegate by implementing didFinishloadingData() 剩下要做的就是通过执行didFinishloadingData()使ViewController符合Delegate。

func didFinishLoadingData() {

    tableView.reloadData()
}

I hope this helps. 我希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM