Как правильно сделать кнопку удаления ячейки?

ios

#21

Приложения крашнулось
Thread 1
Console:
2019-03-06 14:25:39.704712+0300 Wolo[2039:108725] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/arthur/Library/Developer/CoreSimulator/Devices/7D448F41-E055-488F-BD3B-1AE862AADF4E/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2019-03-06 14:25:39.722004+0300 Wolo[2039:108725] [MC] Reading from private effective user settings.
вфвф
2019-03-06 14:25:50.030621+0300 Wolo[2039:108725] -[Wolo.UserViewController deleteTap:]: unrecognized selector sent to instance 0x7f843c51acc0
2019-03-06 14:25:50.171438+0300 Wolo[2039:108725] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[Wolo.UserViewController deleteTap:]: unrecognized selector sent to instance 0x7f843c51acc0’
*** First throw call stack:
(
0 CoreFoundation 0x000000010ec2d1bb __exceptionPreprocess + 331
1 libobjc.A.dylib 0x000000010c646735 objc_exception_throw + 48
2 CoreFoundation 0x000000010ec4bf44 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 UIKitCore 0x00000001129bfb4a -[UIResponder doesNotRecognizeSelector:] + 287
4 CoreFoundation 0x000000010ec31ed6 forwarding + 1446
5 CoreFoundation 0x000000010ec33da8 _CF_forwarding_prep_0 + 120
6 UIKitCore 0x0000000112992ecb -[UIApplication sendAction:to:from:forEvent:] + 83
7 UIKitCore 0x00000001123ce0bd -[UIControl sendAction:to:forEvent:] + 67
8 UIKitCore 0x00000001123ce3da -[UIControl _sendActionsForEvents:withEvent:] + 450
9 UIKitCore 0x00000001123cd31e -[UIControl touchesEnded:withEvent:] + 583
10 UIKitCore 0x0000000112566018 _UIGestureEnvironmentSortAndSendDelayedTouches + 5387
11 UIKitCore 0x000000011255ffd1 _UIGestureEnvironmentUpdate + 1506
12 UIKitCore 0x000000011255f9ad -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:] + 478
13 UIKitCore 0x000000011255f71d -[UIGestureEnvironment _updateForEvent:window:] + 200
14 UIKitCore 0x00000001129cf78a -[UIWindow sendEvent:] + 4058
15 UIKitCore 0x00000001129ad394 -[UIApplication sendEvent:] + 352
16 UIKitCore 0x0000000112a825a9 __dispatchPreprocessedEventFromEventQueue + 3054
17 UIKitCore 0x0000000112a851cb __handleEventQueueInternal + 5948
18 CoreFoundation 0x000000010eb92721 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
19 CoreFoundation 0x000000010eb91f93 __CFRunLoopDoSources0 + 243
20 CoreFoundation 0x000000010eb8c63f __CFRunLoopRun + 1263
21 CoreFoundation 0x000000010eb8be11 CFRunLoopRunSpecific + 625
22 GraphicsServices 0x00000001165981dd GSEventRunModal + 62
23 UIKitCore 0x000000011299181d UIApplicationMain + 140
24 Wolo 0x000000010baa78c7 main + 71
25 libdyld.dylib 0x00000001100c0575 start + 1
26 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)


#22

на guard менял? если да то отмени и попробуй свой вариант
плюс этот код проверь
@objc func deleteUser(sender: UIButton) {
let index = sender.tag
users.remove(at: index)
var indexPath = IndexPath()
indexPath.row = index
indexPath.section = 1
tableView.deleteRows(at: [indexPath], with: .automatic)
}


#23

Пробовал и то, и другое, все равно крашится


#24

ты прописал обработчик deleteTap в коде а потом его взял и удалил скорее всего, экскод на него ругается

копай в этом направлении - ты по кнопке удалить тянул экшн во вьюконтроллер скорее всего, потом экшн ты удалил, а связь в интерфейсбилдере осталась, поэтому крашится приложение.


#25

Покажите просто скриншот вашего VC


#26

Вот простой пример с обработкой событий ячеек в таблице


#27

Теперь тут ошибка
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)


#28

Ну покажите вы уже ваш код целиком. Мы так долго гадать будем.


#29

class UserViewController: UIViewController {

var users: [String] = []

func addUser(nameUser: String){
    users.append(nameUser)
    print(nameUser)
}



@objc func deleteUser(sender: UIButton) {
    let index = sender.tag
    users.remove(at: index)
    var indexPath = IndexPath()
    indexPath.row = index
    indexPath.section = 0
    tableView.deleteRows(at: [indexPath], with: .automatic)
}

func loadData(){
    
}


@IBOutlet weak var tableView: UITableView!

@IBOutlet weak var textField: UITextField!




@IBAction func pushAddButton(_ sender: Any) {
    if textField.text != nil || textField.text == " " {
        addUser(nameUser: textField.text!)
        let indexPath = IndexPath(row: users.count - 1, section: 0)
        
        tableView.beginUpdates()
        tableView.insertRows(at: [indexPath], with: .automatic)
        tableView.endUpdates()
        
        textField.text = ""
        view.endEditing(true)
    } else {
        let ac = UIAlertController(title: nil, message: "Пожалуйста введите имя игрока", preferredStyle: .alert)
        let alertAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        ac.addAction(alertAction)
        present(ac, animated: true, completion: nil)
    }
}




override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

}
extension UserViewController: UITableViewDelegate, UITableViewDataSource{

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
    return users.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? UserTableViewCell
        else {
    return UITableViewCell()
}
    cell.textLabel?.text = users[indexPath.row]
    cell.deleteButton.tag = indexPath.row
    cell.deleteButton.addTarget(self, action: #selector(deleteUser(sender:)), for: .touchUpInside)

return cell

}


#30

@objc func deleteUser(sender: UIButton) {
на
@objc func deleteUser(_ sender: UIButton) {

cell.deleteButton.addTarget(self, action: #selector(deleteUser(sender:)), for: .touchUpInside)
на
cell.deleteButton.addTarget(self, action: #selector(deleteUser(_:)), for: .touchUpInside)

@objc func deleteUser(_ sender: UIButton) {
    if let cell = sender.superview as? UserTableViewCell {
        let indexPath = tableView.indexPath(for: cell)
        users.remove(at: indexPath.row)
        tableView.deleteRow(at: indexPath, with: .automatic)
    }
}

#31

58 47 Снимок экрана 2019-03-06 в 15.37.58
Снимок экрана 2019-03-06 в 15.37.47


#32

в tableView.deleteRow(at: передайте массив indexPath

tableView.deleteRow(at: [indexPath], with: .automatic)

#33

да и еще все-таки правильно будет deleteRows

для исправления ошибки с опциональным indexPath, поменяйте немного конструкцию if
if let cell = sender.superview as? UserTableViewCell, let indexPath = tableView.indexPath(for: cell) {


#34

Теперь не крашится, но и не удаляется
@objc func deleteUser(_ sender: UIButton) {
if let cell = sender.superview as? UserTableViewCell, let indexPath = tableView.indexPath(for: cell) {
users.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}

func loadData(){
    
}


@IBOutlet weak var tableView: UITableView!

@IBOutlet weak var textField: UITextField!




@IBAction func pushAddButton(_ sender: Any) {
    if textField.text != nil || textField.text == " " {
        addUser(nameUser: textField.text!)
        let indexPath = IndexPath(row: users.count - 1, section: 0)
        
        tableView.beginUpdates()
        tableView.insertRows(at: [indexPath], with: .automatic)
        tableView.endUpdates()
        
        textField.text = ""
        view.endEditing(true)
    } else {
        let ac = UIAlertController(title: nil, message: "Пожалуйста введите имя игрока", preferredStyle: .alert)
        let alertAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        ac.addAction(alertAction)
        present(ac, animated: true, completion: nil)
    }
}




override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

}
extension UserViewController: UITableViewDelegate, UITableViewDataSource{

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
    return users.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? UserTableViewCell
        else {
    return UITableViewCell()
}
    cell.textLabel?.text = users[indexPath.row]
    cell.deleteButton.tag = indexPath.row
   cell.deleteButton.addTarget(self, action: #selector(deleteUser(_:)), for: .touchUpInside)

return cell

}


#35

теперь остается понять во сколько View у вас обернута сама кнопка в ячейке, что бы правильно получить доступ к самой ячейке.
добавьте print там где идет удаление, внутрь if и добавляйте к .superview еще .superview столько раз, сколкьо у вас parent view над кнопкой, исключая root view

либо покажите структуру вашей ячейки из IB


#36

Снимок экрана 2019-03-06 в 16.13.25


#37

после

tableView. ReloadData() вызови


#38

это не код, а бардак. Извините. :pensive:


#39

это не обязательно делать


#40

Я имел в виду панельку слева, где показана иерархия самих элементов