user3766930 user3766930 - 2 months ago 11
iOS Question

I mixed static and dynamic UITableViewCells in my UITableView and got wrong values in numberOfRowsInSection

In my

swift
ios app I have a
UITableView
- in story board I added there 3 cells. The first two are static ones and the 3rd one is dynamic, basically first two shows some information and the 3rd one (and the rest generated based on 3rd) show comments. I fetch comments as a json from my webserver.

When json is empty I see cell no. 1 and no. 2 - that's fine. But when json has one value, I see only cell no. 1, I don't see either 2 or 3. When json has 2 comments - I see two static cells.
When json has 3 comments, I see two static cells + 3rd comment. Basically I never see two first comments.

The problem might be here - this is how I'm fetching comments from webservice:

@IBOutlet weak var myTableView: UITableView!
var items = NSMutableArray()
....

Alamofire.request(.GET, "\(serverURL)/comments/\(case_id)/comments/")
.validate()
.responseJSON { response in
switch response.result {
case .Success:
self.items.removeAllObjects()
if let jsonData = response.result.value {
let data = JSON(jsonData)
if let responseDictionary = data.dictionary {
if let commentsArray = responseDictionary["comments"]?.array {
for commentObject in commentsArray {
if let singleComment = SingleComment.fromJSON(commentObject){
self.items.addObject(singleComment)
}
}
self.myTableView.reloadData()
}
}

}
self.myTableView.reloadData()

case .Failure(let error):
print("SWITCH ERROR comments")
print(error)
}
}


and my method
numberOfRowsInSection
looks as follows:

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


I thought the solution could be to just modify the return statement in else block above, so that it is
return self.items.count+2
, but that throws an error:


* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 ..
0]'


what could I do in such situation?

====== EDIT

my
cellForRowAtIndexPath
is a longer method, but I trimmed it down for the most important stuff:

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

if indexPath.row == 0 {
let cell = myComments.dequeueReusableCellWithIdentifier("firstCell") as! FirstCell
...
return cell
}

else if indexPath.row == 1 {
let cell = myComments.dequeueReusableCellWithIdentifier("cellStatic") as! SecondCell
...
return cell

} else {
let cell = myComments.dequeueReusableCellWithIdentifier("cell") as! SingleCommentCell
let comment:SingleComment = self.items[indexPath.row] as! SingleComment
...
return cell
}

}

Answer

You need to allow for the 2 static rows in both your numberOfRowsInSection and cellForRowAtIndexPath functions. The number of rows is 2 plus the count of your items

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

When retrieving the item to display, the row value will be two more than then the required items array index, so row 2 will require item[0]:

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

    if indexPath.row == 0 {
        let cell = myComments.dequeueReusableCellWithIdentifier("firstCell") as! FirstCell
        ...
            return cell  
        }

    else if indexPath.row == 1 {
        let cell = myComments.dequeueReusableCellWithIdentifier("cellStatic") as! SecondCell
        ...
            return cell

    } else {
        let cell = myComments.dequeueReusableCellWithIdentifier("cell") as! SingleCommentCell
        let comment =  self.items[indexPath.row - 2] as! SingleComment
        ...
        return cell
    }

}

Also, I would suggest you modify your fetch code and array definition so that that items is var items = [SingleComment]() rather than an NSMutableArray. This will remove the need to downcast the objects you retrieve from the array.