I am not able to wrap my head around the implementation of sections in cellForRowAtIndexPath
.
I have a UITableView
in which I would like to show 2 sections.
- Incoming Friend Requests
- Friends
In Storyboard, I change my UITableView
Style
to Grouped
.
Next, I would like there to be no Friend Request
section if there are no friend requests. In viewDidLoad
:
override func viewDidLoad() { super.viewDidLoad() (...) if friendRequests.isEmpty { friendsDataSource = friends } else { friendsDataSource = [friendRequests, friends] } }
The rest:
func numberOfSectionsInTableView(tableView: UITableView) -> Int { return friendsDataSource.count } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return friendsDataSource[section].count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let friendRequest = friendsDataSource[0][indexPath.row] let friend = friendsDataSource[1][indexPath.row] if let cell = tableView.dequeueReusableCellWithIdentifier("FriendCell") as? FriendCell { cell.configureProfileCell(userProfile) return cell } else { return FriendCell() } }
I know my cellForRowAtIndexPath
is disgusting but I have absolutely no idea how to implement it.
Any help in the right direction, greatly appreciated
Discovered if (indexPath.section == 0)
, and I just hacked around that.
My eyes hurt looking at this so Please post better ways of doing this. For now:
var friendRequests = [FriendRequest]() var friends = [UserProfile]() var friendsDataSource = [] override func viewDidLoad() { super.viewDidLoad() friends = FriendManager.instance.myFriends friendRequests = FriendManager.instance.incomingFriendRequests if friendRequests.isEmpty { friendsDataSource = [friends] } else { friendsDataSource = [friendRequests, friends] } } func numberOfSectionsInTableView(tableView: UITableView) -> Int { return friendsDataSource.count } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return friendsDataSource[section].count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { if let cell = tableView.dequeueReusableCellWithIdentifier("FriendCell", forIndexPath: indexPath) as? FriendCell { if friendRequests.isEmpty { let friendCell = friends[indexPath.row] cell.configureProfileCell(friendCell) } else { if (indexPath.section == 0) { let friendRequestCell = friendRequests[indexPath.row] cell.configureRequestCell(friendRequestCell) } else if (indexPath.section == 1) { let friendCell = friends[indexPath.row] cell.configureProfileCell(friendCell) } } return cell } else { return FriendCell() } }
You should use the other, newer dequeueing method: dequeReusableCellWithIdentifier(_:forIndexPath:)
instead (passing the actual index path).
That one is guaranteed to always succeed, so you can do without this if/else
structure:
if let cell = ... { ... return cell } else { return FriendCell() }
By the way, you are returning the FriendCell
instance fresh, without configuring it. Is that what you really want?
Clarification The method dequeReusableCellWithIdentifier(:)
succeeds only if there is one or more cells with the specified identifier already enqueued for reuse; the first few times you call it it will return nil and you need to fallback to instantiating a new cell (with the same identifier), for immediate use (and later reuse):
func tableView(tableView:UITableView, cellForRowAtIndexPath:NSIndexPath) -> UITableViewCell { if let cell = tableView.dequeReusableCellWithIdentifier("Identifier") as? FriendCell { // Successfully dequeued for reuse; // configure it: // (set labels' texts, etc.) return cell } else{ // No cell enqueued; create anew let cell = FriendCell(style:.Plain, reuseIdentifier:"Identifier") // configure it // (set labels' texts, etc.) return cell } }
...But because this check is a pain, Apple added a new method:
dequeReusableCellWithIdentifier(identifier:String, forIndexPath:NSIndexPath)
that internally performs the dequeueing and also initializes a new cell if no one is available. This eliminates the need for an else path in the code above, and it gets smarter:
func tableView(tableView:UITableView, cellForRowAtIndexPath:NSIndexPath) -> UITableViewCell { let cell = tableView.dequeReusableCellWithIdentifier("Identifier", forIndexPath:indexPath) as! FriendCell // (Never fails - provided identifier is right and class is registered for it) // configure it: // (set labels' texts, etc.) return cell }