Dynamically Implementing Section in cellForRowAtIndexPath

匿名 (未验证) 提交于 2019-12-03 01:45:01

问题:

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

回答1:

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()     } } 


回答2:

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 } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!