티스토리 뷰

안녕하세요 😁

지난 글에 이어 계속해서 SwiftUI로 Todo 앱을 만들어 볼게요

 

Todo앱 만들기 1편 바로가기

 

[SwiftUI] 기본적인 Todo 앱 만들기 01 (Stack으로 View 구성하기)

안녕하세요. 오늘은 SwiftUI 로 가장 기본적인 Todo앱을 만들어보려고 합니다. 제가 아직 초보이다 보니 유튜브를 보고 따라 만들며 모르는 부분은 채워나갈 예정입니다. 최대한 많이 찾아보며 할

malchafrappuccino.tistory.com

 

지난 주에는 껍데기(View)를 구성했으니 이제는 실제로 todo 리스트가 작동하기 위한 함수를 만들 것 입니다.

 

 

todo 앱

해야할 일

제가 만드려는 앱을 다시보면서 만들어야할 동작에 대해 정리하겠습니다.

1. TextField에 할 일(Todo) 입력

2. Button 클릭시 List에 추가

3. List에 있는 항목 옆으로 슬라이드 시 삭제 버튼 나오기

크게 3가지입니다.

 

변수 선언

우선은 TextField에 할 일을 입력해야 되는데요, 그러기 위해서는 TextField 안에서 할 일을 보관할 변수와 List를 관리할 변수 이렇게 2가지가 필요합니다. 그 변수 들을 선언해 주겠습니다.

TextField 안에서 키보드로 글자를 타이핑 하겠죠? String으로 newTodo를 선언합니다.

그리고 String을 저장할 구조체(struct) TodoItem를 만들고, 그 구조체를 담을 배열 allTodos를 선언하겠습니다.

근데 여기서 처음 접하는 사람이라면 @State 는 뭐지라는 생각이 들 것입니다.

 

자 '아' 하세요. 공식문서 들어갑니다~

 

 

@State 란

애플 공식 문서 https://developer.apple.com/documentation/swiftui/state

영어로 적혀있으니 해석해볼까요?

 

State

SwiftUI 에 의해 관리되는 value(값) 을 쓰고 읽을 수 있는 property wrapper type이다 

SwiftUI는 State로 선언한 property를 관리해준다고 합니다 (똑똑한걸?)

State 는 그 자체로 value가 아니고 'value를 쓰고 적는 것' 이 State 라고 합니다.  

State value가 바뀌면 뷰가 기존에 보여주던 걸 없애고 body를 다시 계산합니다 ( invalidate = 무효화하다)

-> State 로 선언하면 state value가 바뀌면 다시 계산해서 view를 보여주는 것입니다!

     만약 State로 선언하지 않으면 값이 바뀌었는데도 view에는 안 나오겠죠??

 

State는 오직 view's body, methods 에서만 State를 사용할 수 있습니다.

따라서 선언할 때 private으로 선언하여 client(사용자)가 view에서 그들에게 직접적으로 접근하는 것을 막습니다.

-> public으로 선언 시 개발자의 의도와는 다르게 state 가 변경될 수 있습니다. 이를 방지하기 위해 private 으로 선언해서 메소드(methods)를 통해서만 접근할 수 있도록 하는 것입니다.

 

그리고 접근시 변수 이름과 $ 표시를 같이 사용합니다. 

 

코드를 보면 newTodo는 입력창에서 값을 받아오는데요,  키보드를 눌러 타이핑을 하면 newTodo 값이 바뀌고, State로 선언했기 때문에 SwiftUI가 이를 감지하고 view에 새로운(사용자가 입력한) newTodo 값을 보여주는 것입니다.

 

 

만약 State가 아니라면 사용자가 키보드를 입력하면 newTodo값은 변해도 입력창은 변하지 않겠죠?

그러면 사용자는 "왜 키보드가 안 먹지" 라고 생각할 것입니다. (state 사용설명을 위한 극단적인 예시입니다 ㅎㅎ)

 

그리고 자세히 보면 newTodo랑 allTodos 의 모습이 다른데요. allTodos 뒤에는 :[TodoItem]이 있습니다.

 

원래는 newTodo도 다음과 같이 선언합니다.

하지만 우리 모두가 ""는 String이라는 것을 알고 있습니다. (몰랐어도 지금 알았으니까 아는 겁니다 😉)

Swift도 이 사실을 알기 때문에 :String은 생략해서 작성할 수 있는 것입니다.

 

 

 

 

 

다음으로 List에 있는 할 일 목록을 구조체로 선언하였습니다.

여기서 구조체에 Identifiable이 있는데요, 다시 공식 문서를 보도록 하겠습니다.

 

Identifiable이란

 

Identifiable은 protocol로써 class 혹은 value에게 identity를 줘서 구별할 수 있도록 해줍니다.

protocol은 지켜야할 규칙이라고 생각하시면 됩니다. (protocol = 규칙 이라고 생각하면 이해하기 쉽습니다)

TodoItem이라는 구조체(struct)를 만들 때 id값이 필요합니다.

 

만약 Identifiable이라는 protocol을 사용했는데 이를 지키지 않으면 어떻게 될까요? 

 

위와 같이 바로 에러가 납니다.

 

저는 할 일이 적힌 이 구조체를 배열에 넣어서, View 안에서 List, ForEach로 보여줄 것입니다.

SwiftUI에서는 List와 ForEach를 사용하려면 id값이 필수로 필요합니다.

따라서  Identifiable이라는 protocol을 사용하여 TodoItem에 필수적으로 id 값을 부여해줄 것입니다.

 

id 값은 개발자가 정해줄 수 있지만 Unique Identifier, 즉 1 개만 있어야 합니다.

리스트가 10개면 1~10 로 하면 쉽겠죠?

하지만 어플을 만들고 관리하다보면 데이터가 10개가 아니라 셀 수 없이 많을 것입니다.

그렇게 많은 데이터에 일일이 identifier 을 정해주는 것은 매우 힘든 일이겠죠?

따라서 이미 만들어져 있는 UUID를 사용하면 됩니다!

구조체를 선언한 것을 다시보면 var id = UUID() 를 볼 수 있습니다

UUID 로 선언 할 경우 Swift가 알아서 unique identifier를 생성해줍니다! (역시 똑똑해~)

 

여태까지 3가지 변수를 선언해주었는데요, 이해하기 쉽게 그림으로 그려보았습니다.

노란색이 TextField에서 String을 입력받을 변수인 newTodo

빨간색이 id 와 Todo를 가지고 있는 Struct TodoItem

파란색이 Struct TodoItem을 가지고 있는 AllTodos입니다.

완전히 이해되셨죠?? 

 

이제 이 변수를 View 안에 넣어주겠습니다.

기존에 Text 를 지워주고 TextField 를 적어주면 됩니다.

TextField()에 첫번째 인자는 placeholder 입니다

 

https://www.youtube.com

위 이미지는 유튜브 검색창인데요. 검색 키워드를 입력하기 전에 '검색' 이라는 글씨 보이나요? 저게 바로 placeholder 입니다.

Text입력 창 에서 입력하기 전에 설명을 위한 글자입니다.

 

두번째 text:는 TextField에서 다룰 value입니다. 앞서 선언한 newTodo 를 넣어주면 되는데요, newTodo는 State로 선언했으니까 $ 표시 붙여서 적어주면 됩니다.

 

List 안에는 ForEach 로  allTodos 를 풀어서 나열해주겠습니다.

ForEach는 무엇일까요?

다시 공식문서를 불러오겠습니다,

 

https://developer.apple.com/documentation/applearchive/archiveheader/3589189-foreach/

 

forEach 는 Instance Method 중 하나인데요. 직역하면

'각 element 에 주어진 closure 를 for-loop 를 통해 연속적으로, 똑같은 순서로 부른다'

라고 되어있네요. parameter를 받아 클로저 상수로 전달하는 메소드라고 생각하면 쉽게 이해할 수 있을 거 같습니다.

솔직히 이렇게 정의만 보면 1번에 이해하기 어렵습니다. 그래서 바로 아래 있는 예제를 가져왔습니다.

 

 

배열에 있는 value를 출력할 때 보통은 for-in을 사용해서 출력을 합니다. ForEach도 똑같이 동작을 하는데요. 그럼 for-in을 쓰면 되는데 왜 ForEach를 쓰는 걸까요??

 

ForEach의 사용은 2가지 방법으로 for-in 사용과 나뉩니다.

1. for-in은 loop {} 안에서 break와 continue 를 사용할 수 있고 ForEach는 사용할 수 없다.

2. for-in 은 return을 사용하면 함수종료, forEach는 return을 사용하면 전달하는 클로저(=익명함수)가 종료 된다

 

2가지 차이점이 있지만 이 차이점을 통해서 왜 굳이 forEach를 사용해야하는지는 모르겠네요...(저만 그런가요..? ㅎㅎ)

 

조금 공부해본 결과 forEach는 closure(=익명함수) 를 사용할 수 있는 이점이 있다고 합니다. for-loop 속에 동작을 하나 더 넣을 수 있다는 것은 더 큰 이점이겠죠? 또한 break와 continue 문을 사용하지 않아 반복문이 끝날 때까지 게속해서 출력할 수 있습니다. 제가 만들 어플에서는 리스트를 아무런 조건 없이 모두 출력할 것이기 때문에 forEach문이 더 알맞습니다.

 

제가  여태까지 경험한 바에 의하면 List 안에는 대부분 forEach를 사용해주었습니다. 특별한 경우가 아니면 forEach를 사용한다고 생각하면 될 것 같습니다.

 

그래서 이 forEach를 그림으로 나타내면

todoItem이 바뀌어가면서 List에 출력해주는 것을 한 눈에 이해할 수 있습니다.

 

이제 resume을 눌러 확인해주면 

 

TextField에 잘 입력되는 것을 확인할 수 있습니다 😆

 

이로써 해야할 일 1. TextField에 Todo 입력하기를 완료했습니다!

다음에는 함수를 구현해 2. button을 눌러 list에 추가하기 를 이어서 하겠습니다.

 

피드백은 항상 환영입니다 😊

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
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
글 보관함