포스트

To Do List (5)

수정기능 마무리

1
2
3
4
5
6
func modifyList(title: String) {
        let i = todoLists.firstIndex { list in
            list.title == title
        }
        todoLists[i!].title = title
    }

함수를 이렇게 적용하였으나

바뀌지 않았다.

생각해보니 파라미터를 잘못했다.

1
2
3
4
5
6
func modifyList(currentTitle: String, modifiedTitle: String) {
        let i = todoLists.firstIndex { list in
            list.title == currentTitle
        }
        todoLists[i!].title = modifiedTitle
    }

이렇게 해주니 성공.

찾아보니 SwiftData는 Update를 해줄 필요가 없다고한다. 데이터가 바뀌면 자동으로 Save가 된다고한다.

Oct-24-2024 17-55-01

완료.

Cell클릭시 화면 전환하기

NavigationLink를 사용한다.

이때 주의점은 NavigationLink를 사용하기전에 NavigationView가 있어야 한다는것.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
var body: some View {
        NavigationStack {
            NavigationView {
            VStack {
                List(todoLists, id: \.self) { list in
                        NavigationLink(value: list) {
                            CellView(isOn: list.isCompleted,
                                     title: "\(list.title)")
                            .swipeActions(edge: .trailing) {
                                Button(action: {
                                    modelContext.delete(list)
                                }) {
                                    Image(systemName: "trash")
                                }
                            }
                            .tint(.red)
                            .swipeActions(edge: .leading) {
                                Button("edit",
                                       systemImage: "pencil") {
                                    isEditing.toggle()
                                    tempoList = list
                                }
                            }
                            .tint(.blue)
                            .alert("TodoList 수정",
                                   isPresented: $isEditing) {
                                TextField("수정", text: $title)
                                Button("OK",
                                       role: .cancel) {
                                    if let currentTitle = tempoList?.title {
                                        modifyList(currentTitle: currentTitle, modifiedTitle: title)
                                    }
                                    title = ""
                                }
                                Button("Cancel", role: .destructive){
                                    
                                }
                            }
                        }
                    }
                    .navigationTitle("ToDoList")
                    .navigationDestination(for: TodoModel.self) { list in
                        DetailView(title: list.title)
                    }
                }
            }
            .toolbar {
                ToolbarItem(id: "add",
                            placement: .navigationBarTrailing) {
                    Button("add",
                           systemImage: "plus.app") {
                        isShowing.toggle()
                    }
                           .alert("TodoList 추가",
                                  isPresented: $isShowing) {
                               
                               TextField("TodoList 추가", text: $title)
                               Button("OK",
                                      role: .cancel) {
                                   addList()
                               }
                               Button("Cancel", role: .destructive){
                                   title = ""
                               }
                           }
                }
                ToolbarItem(id: "DeleteAll",
                            placement: .navigationBarLeading) {
                    Button("DeleteAll",
                           systemImage: "folder.badge.minus") {
                        do {
                            try modelContext.delete(model: TodoModel.self)
                        } catch {
                            print("Error: \(error.localizedDescription)")
                        }
                    }
                }
            }
        }
    }

코드가 꽤나 길어졌다.

CleanShot 2024-10-24 at 19 29 10

빨간색 박스 부분이 Hierarchy로 확인해보니

NavigationBarLargeTitleView(하단), NavigationBarContentView(상단)로 나온다.

Vstack을 지우고

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
NavigationView {
                List(todoLists, id: \.self) { list in
                    NavigationLink(value: list) {
                        CellView(isOn: list.isCompleted,
                                 title: "\(list.title)")
                        .swipeActions(edge: .trailing) {
                            Button(action: {
                                modelContext.delete(list)
                            }) {
                                Image(systemName: "trash")
                            }
                        }
                        .tint(.red)
                        .swipeActions(edge: .leading) {
                            Button("edit",
                                   systemImage: "pencil") {
                                isEditing.toggle()
                                tempoList = list
                            }
                        }
                        .tint(.blue)
                        .alert("TodoList 수정",
                               isPresented: $isEditing) {
                            TextField("수정", text: $title)
                            Button("OK",
                                   role: .cancel) {
                                if let currentTitle = tempoList?.title {
                                    modifyList(currentTitle: currentTitle, modifiedTitle: title)
                                }
                                title = ""
                            }
                            Button("Cancel", role: .destructive){
                                
                            }
                        }
                    }
                }
            }
            .navigationTitle("ToDoList")
            .navigationDestination(for: TodoModel.self) { list in
                DetailView(title: list.title)
            }

NavigationView에 modifier를 적용하니 해결이 되었다.

SearchBar 만들기

YouTube를 참고하여 만들었다.

.searchable(text: $searchText, placement: .navigationBarDrawer, prompt: "Todo Search")

이걸 나는 NavigationStack쪽에 Modifier를 달아주었다.

하지만 적용은 되지 않는데, 이제 필터링 되는 리스트를 만들어 준다.

1
2
3
4
5
var filteredList: [TodoModel] {
        guard !searchText.isEmpty else { return todoLists }
        return todoLists.filter { $0.title.localizedCaseInsensitiveContains(searchText)}
    }
    

여기서 포인트는

  1. 입력을 아무것도 안 했을 때: searchText가 비어 있으면 todoLists 전체를 그대로 반환한다.
  2. 입력을 했을 경우:
    • searchText가 비어 있지 않으면 todoLists필터링하여, 각 항목의 titlesearchText대소문자 구분 없이 포함하는지 확인한다.
    • 일치하는 항목들만 담은 배열을 반환한다.

localizedCaseInsensitiveContains?

  • 역할: localizedCaseInsensitiveContains는 문자열이 특정 텍스트를 포함하고 있는지 확인하는 메서드다.
  • 특징:
    • 대소문자를 구분하지 않고(caseInsensitive) 비교한다.
    • 로케일에 맞게 비교하여, 언어별 특수 문자를 인식한다.
  • 예시:
    • title.localizedCaseInsensitiveContains("todo")title이 “todo”를 포함하는지 확인하며, “Todo”, “TODO” 등 대소문자 차이를 무시하고 비교한다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.