Dravidian Dravidian - 3 months ago 10
iOS Question

Programmatically delete a row from tableView from its customCell class with animation

GOAL

To delete a row from the TableView called from

customTableViewCell


I have a
tableView
in my
CustomTableViewController
which deque's a
customTableViewCell
.

In that
customTableViewCell
class i have a
UIButton
Action which needs to change its buttonTitle when pressed, accordingly and delete the row itself if required.For this i am passing the indexPath of that cell to a globalVariable in that
customTableViewCell
class, which i use to delete my row accessing through the instance of
CustomTableViewController
.

CODE

Code for
retrieving
the database from firebase and
struct
is unnecessary ,just included for reference.

CustomTableViewController
which has embed
tableView
in it:-

class FriendsListController: UIViewController , UITableViewDelegate , UITableViewDataSource,addingFriendDelegate{

var profileFeed = [profileStruct]() //profileFeed is the an array of type struct, in which i am storing my retrieved database value's
var customCellHandler = FriendsTableViewCell()
override func viewDidLoad() {

super.viewDidLoad()
listTableView.delegate = self
listTableView.dataSource = self
customCellHandler.delegate = self
if friendListTable == true && profileFeed.isEmpty == true{

FIRControllerHandle.retrievingForTheFriendListTableView { (userName, lctn, ID) in

let temp = profileStruct.init(userName: userName, location: lctn, UID: ID)
self.profileFeed.insert(temp, atIndex: 0)
self.listTableView.reloadData()
self.presentViews()

}

}else if friendListTable == false && profileFeed.isEmpty == true{

print(profileFeed)
print(profileFeed.isEmpty)

FIRControllerHandle.retrievingForThePendingFriendRequests({ (userName, location, userId) in

if self.profileFeed.isEmpty == true{

let temp = profileStruct.init(userName: userName, location: location, UID: userId)
self.profileFeed.insert(temp, atIndex: 0)
self.listTableView.reloadData()
self.presentViews()
}
})
}
}

//Code for storing the data in a struct is just for reference , trivial w.r.t context of my question

}


//addindFriendDelegate methods
func deleteRowAtTheIndex(index: NSIndexPath){

listTableView.deleteRowsAtIndexPaths([index], withRowAnimation: .Fade)

}


//TableView delegate Functions.

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return profileFeed.count
}

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

let cell = listTableView.dequeueReusableCellWithIdentifier("friendsCell") as! FriendsTableViewCell

cell.userNameLabel.text = profileFeed[indexPath.row].profileName
cell.userUID = profileFeed[indexPath.row].profileUserId
cell.userName = profileFeed[indexPath.row].profileName
cell.userLocationLabel.text = profileFeed[indexPath.row].profileLocation
cell.currentUserName = currentuserName_initial
cell.friendsListBool = friendListTable
cell.cellIndexPath = indexPath //Sending the indexPath of that row


return cell

}
}





customTableViewCell
class which responds to buttons action:-

protocol addingFriendDelegate {
func deleteRowAtTheIndex(index: NSIndexPath)
}

class FriendsTableViewCell: UITableViewCell {

var userName : String!
var userLocation : String!
var userUID : String!
var FIRControllerHandle : FIRController = FIRController() //I am using firebase as my backend and `FIRController` class handles all the firebase functions.
var delegate: addingFriendDelegate!
var friendsListBool : Bool = true // I am managing two tableViews datasource in one tableView , and `friendsListBool` tells me which node to retrieve from my database.
var currentUserName : String!
var cellIndexPath : NSIndexPath!
var listTableViewController : FriendsListController = FriendsListController() // Instance of viewController in which my tableView is embed


@IBAction func addFriendsBtnAction(sender: CustomButton) {

if friendsListBool{
FIRControllerHandle.sendFriendRequest(userUID, completionBlock: {

self.addFriendsBtn.setTitle("Sent", forState: .Normal) //Setting the title

print(self.cellIndexPath.row) //Printing Fine
self.listTableViewController.listTableView.deleteRowsAtIndexPaths([self.cellIndexPath], withRowAnimation: .Fade)


})

} else if !friendsListBool {

FIRControllerHandle.accepFriendRequest(currentUserName, friendID: userUID, friendName : userName ,completionBlock: {

self.addFriendsBtn.setTitle("Friends", forState: .Normal)



})
}
}
}


WHAT HAVE I TRIED

self.listTableViewController.listTableView.deleteRowsAtIndexPaths([self.cellIndexPath], withRowAnimation: .Fade)


called in
@IBAction func addFriendsBtnAction(sender: CustomButton)
where
listTableViewController
is Instance of viewController in which my tableView is embed, and
cellIndexPath
indexPath of the row i want to delete

LINE OF ERROR

self.listTableViewController.listTableView.deleteRowsAtIndexPaths([self.cellIndexPath], withRowAnimation: .Fade)


Error:- fatal error: unexpectedly found nil while unwrapping an Optional value

(lldb)

PS:- I am not particularly inclined towards
protocol-delegate
method for this.I am looking for an alternative.

Answer

Never initialize a view controller with the default initializer like FriendsListController().
It will create a brand new instance which is not the instance you expect in the view hierarchy.

An suitable alternative to protocol / delegate is a completion closure.

According to your latest code change the following:

  • Delete

    var customCellHandler = FriendsTableViewCell()
    var delegate: addingFriendDelegate!
    
  • Insert in cellForRowAtIndexPath

    cell.delegate = self
    
  • Insert in deleteRowAtTheIndex

    profileFeed.removeAtIndex(index.row)
    
Comments