스닥
Playground
스닥
전체 방문자
오늘
어제
  • 분류 전체보기 (125)
    • 개발자 기본기 (1)
    • Swift 아키텍처 (6)
    • iOS 개발 (55)
      • Swift (12)
      • UIKit (17)
      • SwiftUI (9)
      • CoreData (9)
      • MusicKit (4)
      • WebKit (2)
      • 개발 환경 (0)
      • WatchOS (2)
    • 애플 개발자 아카데미 (4)
    • 막 쓰는 개발일지 (0)
    • 운영체제 (4)
    • 네트워크, 서버 (16)
      • Network (9)
      • Server (7)
    • 알고리즘 (8)
    • C언어 (7)
      • 함수 (7)
    • 하루 이야기 (23)

블로그 메뉴

  • GitHub계정
  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 서버
  • struct class 성능
  • 깊이 우선
  • ip주소
  • 너비 우선
  • 도커
  • SWIFT
  • swift performance
  • BFS
  • Core Animation
  • dfs
  • 자료구조
  • core data
  • 알고리즘
  • docker
  • C 언어
  • ios rendering
  • 문자열 복사
  • 트리
  • Server

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
스닥

Playground

[UITableView] SwipeAction -  cell 삭제 (확인 Alert와 함께)
iOS 개발/UIKit

[UITableView] SwipeAction - cell 삭제 (확인 Alert와 함께)

2021. 11. 29. 02:17

 

 

 

TableView는 자체적으로 Delegate를 통해, 스와이프 액선을 지정해주고 있습니다.

 

저는 Cell을 스와이프해서 해당 Cell을 삭제해주는 작업을 구현해보았습니다.

 

 

 

 

Cell을 삭제할 때, Delete를 할 것인지 한번 확인하지 않으면, 사용자의 입장에서는 원치 않은 삭제를 할 수 있고

개발자는 이를 복구해줄 수 있는 툴을 만들어 주지 않는 이상, 반드시 사용자에게 정말 삭제할 것인지를 한번 확인받아야 한다고 생각합니다.

유저는 마치 쓰고 있던 블로그 글을 통채로 날린 느낌일 것이기 때문이에요..ㄸㄸ

 

 

다음은 제 tableView가 UITableViewDelegate를 채택해서 구현해야 하는 함수로

스와이프 하면 다음과 같은 삭제 버튼이 나타나게 됩니다.

 

 

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath)
    -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: nil) { (_, _, completionHandler) in
            self.alertForSafeDeletion(indexPath: indexPath)
            completionHandler(true)
        }
        deleteAction.image = UIImage(systemName: "trash")
        deleteAction.backgroundColor = .systemRed
        let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
        return configuration
}

 

이 configuration만 만들어서, 리턴 해주면, 스와이프 했을때, 저렇게 빨갛고 예쁜 삭제버튼이 짜잔하고 드러납니다ㅎㅎ

 

 

조금 더 설명을 해보자면, 먼저 deleteAction은 UIContextualAction으로 만들어줘야 하는데

UIContextualAction은 다음과 같이, 유저가 cell의 row를 스와이프 했을 때 일어나는 액션을 정의한다.

 

 

액선이 완료되면 destructive 스타일로 작동을 하게 되는데

이 스타일은 Cell 하나가 이렇게 사라지는 방식을 의미한다.

 

 

하지만 이게 정말로 지워지는 건 아니고, 지워지는 척만 하는것이다.

 

 

그리고 이 액션이 끝나고 나면 함수를 작동시켜서 실제로 DB나 리스트에서 지워주어야 한다!!

나의 경우는 다음 함수를 사용해서 해당 indexPath.row의 객체를 remove해주었다.

self.alertForSafeDeletion(indexPath: indexPath)

 

 

이 함수는 해당 indexPath를 삭제하는 함수인데,

나는 여기에 Alert로 한번 확인을 하는 과정을 거쳤다.

 

    func alertForSafeDeletion(indexPath: IndexPath) {
        impactFeedbackGenerator?.impactOccurred()
        let alert = UIAlertController(title: nil, message: "정말 기록을 삭제할까요?", preferredStyle: .alert)
        
        let yesAction = UIAlertAction(title: "네", style: .default) { _ in
            // Yes를 눌렀을 때 할 일,
        }
        alert.addAction(yesAction)
        let noAction = UIAlertAction(title: "아니오", style: .cancel) { _ in
            // No를 눌렀을 때 할 일
        }
        alert.addAction(noAction)
        present(alert, animated: true, completion: nil)
    }

이렇게 Yes를 눌렀을 때는 지워주면 되고,

No를 눌렀을 때는 원하는 동작을 지정해주면 된다. (나같은 경우는 굳이 아무런 동작을 하지 않는다.)

 

 

내 전체 코드는 다음과 같다.

 

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath)
    -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: nil) { (_, _, completionHandler) in
            self.alertForSafeDeletion(indexPath: indexPath)
            completionHandler(true)
        }
        deleteAction.image = UIImage(systemName: "trash")
        deleteAction.backgroundColor = .systemRed
        let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
        return configuration
    }
    
    func alertForSafeDeletion(indexPath: IndexPath) {
        impactFeedbackGenerator?.impactOccurred()
        let alert = UIAlertController(title: nil, message: "정말 기록을 삭제할까요?", preferredStyle: .alert)
        
        let yesAction = UIAlertAction(title: "네", style: .default) { _ in
            let context = CoreDataStack.shared.managedObjectContext
            let date = self.recordsByDate[indexPath.section][indexPath.row].createdDate ?? Date()
            var calendar = Calendar.current
            calendar.timeZone = NSTimeZone.local
            context.delete(self.recordsByDate[indexPath.section][indexPath.row])
            CoreDataStack.shared.saveContext()
            self.recordsByDate[indexPath.section].remove(at: indexPath.row)
            self.listTableView.deleteRows(at: [indexPath], with: .fade)
            if self.recordsByDate[indexPath.section].count == 0 {
                var matchingDate = [FinalDate]()
                let fetchRequest = FinalDate.fetchRequest()
                let dateFrom = calendar.startOfDay(for: date)
                let dateTo = calendar.date(byAdding: .day, value: 1, to: dateFrom) ?? Date()
                let fromPredicate = NSPredicate(format: "%@ <= %K", dateFrom as NSDate, #keyPath(FinalDate.creationDate))
                let toPredicate = NSPredicate(format: "%K < %@", #keyPath(FinalDate.creationDate), dateTo as NSDate)
                let datePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [fromPredicate, toPredicate])
                fetchRequest.predicate = datePredicate
                do {
                    matchingDate = try context.fetch(fetchRequest)
                } catch { print("context Error") }
                if matchingDate.count > 0 {
                    context.delete(matchingDate[0])
                }
                self.recordsByDate.remove(at: indexPath.section)
                self.dateSections.remove(at: indexPath.section)
                self.onlyDateStr.remove(at: indexPath.section)
                self.listTableView.deleteSections([indexPath.section], with: .fade)
                self.showEmptyMessage()
                self.calendarCalculation()
            }
            self.calendarView.reloadData()
            CoreDataStack.shared.saveContext()
            feedbackGenerator?.notificationOccurred(.success)
        }
        alert.addAction(yesAction)
        let noAction = UIAlertAction(title: "아니오", style: .cancel) { _ in
            impactFeedbackGenerator?.impactOccurred()
        }
        alert.addAction(noAction)
        
        present(alert, animated: true, completion: nil)
    }
}

 

'iOS 개발 > UIKit' 카테고리의 다른 글

[Auto Layout] Multiplier(2)  (0) 2021.12.22
[Auto Layout] Multiplier(1)  (0) 2021.12.21
[Auto Layout] Equal Constraints에 대해서  (0) 2021.12.20
[UIGestureRecognizer] tableview와 함께 사용하기  (0) 2021.11.29
[UITextView] 줄 수, 글자 수 제한  (0) 2021.11.22
[UIView] 정말 예쁜 blur Effect  (0) 2021.11.21
[Swift] App 첫 로딩을 감지하는 법 (first loading detection)  (0) 2021.11.20
[Swift] 앱 안에서 메일 보내기  (0) 2021.11.20
    스닥
    스닥
    https://github.com/feldblume5263

    티스토리툴바