본문 바로가기
취미노트/코딩공부

[flutter] 11 효율적인 데이터 관리 2, For Loop

by 복습쟁이 2024. 8. 30.
반응형

* 지난 포스팅의 예제에 계속 이어서 학습

 

 

 

반복문은 굉장히 많이 쓰이는 문법이다.

지난 포스팅에서 운동명과 횟수를 고정된 형태에서 유연하게 바꾸기 위해 리스트를 사용했었다.

 

오늘의 운동 주말 운동
1. 싯업   50 1. 싯업   20
2. 친업   15 2. 푸시업   50
3. 스쿼트   100 3. 버피   45
      4. 스쿼트   200
        5.친업   30

 

하지만 위 표처럼 운동의 갯수 자체와 운동명, 횟수 모든 것들이 변경된다면

리스트구조만으로는 대응이 어렵다. 컬럼 이하에 있는 운동의 갯수가 고정되어 있기 때문임. 

운동 갯수를 자동으로 생성하는 구조를 만들어야 대응이 가능하다.

 

 

 

 

 

[dart]에는 총 4가지 루프문이 있다.

  • for
  • for-in
  • forEach
  • while, do-while

 

하나만 잘 알아두면 나머지는 비슷한 논리로 동작한다.

for문부터 자기 것으로 만들어버리자.

 

 

 

 

 

 

for문의 구조

[예문]
for var i=1; i<=3; i++){
 print('$i일차 운동 완료');
}
초기화문 for문에서 사용될 변수를 초기화. 통상 i값을 사용함.
조건문 for문의 실행문이 수행될 조건을 만듦. 조건이 true일 때, 실행문이 수행된다.
증감문 for문이 한 번 반복될 때 마다 실행되는 구문. 초기화 된 i를 증가시키는 코드를 통상 넣음.
실행문 for문의 body. 실제로 실행되는 코드.
[해석]
i를 1로 초기화하고
i가 3보다 작거나 같을 동안 실행문을 반복해서 수행한다
한번 반복될 때 마다 i를 1씩 증가시킨다
실행할 내용은 print부분
[결과]
'1일차 운동완료' print 작동 후 처음으로 돌아간다.
2일차 운동완료 작동 후 처음으로 돌아간다.
3일차 운동완료 작동 후 처음으로 돌아간다.
4는 3보다 크므로, 조건이 false가 되어 실행문을 실행 않고 for문을 벗어난다.

 

증가연산자는 개발자의 의도에 따라 증감을 폭을 조절할 수 있다.

i++ // i가 1씩 증가

i+=2 // i가 2씩 증가

 

 

 

 

 

 

 

 

Continue와 Break의 활용

루프문에는 continue와 break가 있다. 이를 잘 활용하면 풍부하게 만들 수 있다.

continue :  현재 반복 회차를 무시 및 종료하고 다음 회차 시작지점으로 넘기는 것.

break : 이 구문을 만나게 되면 반복을 종료한다.

아래 예제를 논리적으로 따라가보며 다시 이해를 해 보자.

 

좌측은 코드이고, 우측은 코드의 실행결과이다.

 

1. student라는 변수에 정수 100을 넣음

2. for 문을 보면 i가 0부터 100보다 작거나 같을 때까지 반복, 한번 회전마다 1씩 증가한다.

3. if 이하에서 i가 20보다 큰 경우  break문을 만나, for문이 종료되고 Loop 괄호 다음 라인이 실행된다.(print('Loop문 종료'))

4. if(i%2==0) 은 i를 2로 나누었을 때 나머지가 0인 것, 즉 짝수인 것을 의미한다.

5. i가 짝수면 continue를 만나, for문의 실행문(print('홀수: $i'))를 실행않고 for문의 시작점으로 되돌아간다.

6. 홀수값 1,3,5,7,9....만 출력이 되고 값이 20보다 커지면 break에 걸려 for문이 종료된다.

 

 

서두에 언급한 예제 시나리오 대응을(운동 갯수 등 증가) 위한 코딩을 해보자.

 

 

 

 

 

 

이번에 코딩할 for문의 논리적 흐름

1. 운동명 리스트 생성

2. 운동횟수 리스트 생성

3. workoutsToday 라는 변수 생성

--- for문 구간 : 조건에 의해 반복해서 운동명, 운동횟수의 추가가 수행됨 --

4. 실행문에 의한 운동명 Row 반복 추가

 

이런 흐름으로 만들어진다.

 

 

 

 

For Loop 예제 실습

 

1. Row를 원하는 수 만큼 갯수를 맞춘다. (당연히 List도 원하는만큼 만들어준다, 안그러면 에러가 발생한다)

2. 리스트 데이터 개수 만큼 Row를 생성해서 출력시키는 형태로 해야 한다.

 

3. List를 선언하고 Row위젯을 저장, 이름은 workoutsToday, 초기값은 빈 리스트로 주자.

4. workout메인에 필요한 수 만큼 Today에 Row가 추가되도록 만들자.

 

 

5. 이 때, Today에는 값이 고정되어 있지 않다. 그럼 그 값은 언제 읽어올까? 그 타이밍은 페이지가 열릴때이다.

6. WorkoutTrackerPage가 열릴 때, 그리고 아직 화면이 다 출력되기 전일 때가 타이밍임.

7. 위젯의 특정 시점을 잡아낼 때는, 위젯의 라이프사이클을 활용해야 한다.

8. STF 위젯은 라이프사이클 상의 상태를 몇가지 가진다. 위젯이 생성되는 순간, 갱신되는 순간, 사라지는 순간 호출되는 함수들이 있다. 이렇게 특정 시점에 호출되는 함수들을 생명주기(라이프사이클)이라 부른다.

9. Today가 생성되는 시점은 위젯이 생성되는 시점이어야 하며 initState로 쓴다. 이는 STF함수 고유의 기능으로, 변수를 초기화해줄 때 많이 활용한다. 원치 않아도 플러터 프레임워크에 의해 자동으로 호출된다. 그래서 그 안에 코드를 넣어주기만 하면 된다.

10. 작성법은 ini 치면 자동완성 되고, super 아래쪽으로 원하는 코드 넣으면 된다.

 

void initState() {
  // TODO: implement initState
  super.initState();

  for(var i=0;i<workoutName.length;i++) {

    workoutsToday.add(
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text('${i+1}. ${workoutName[i]}'),
            Text('${workoutGoal[i]}회'),
          ],
        )
    );
  }
}

11. for문의 논리를 보자면, var타입을 준 뒤

(초기화문) i값의 초기값은 0으로 초기화했다. List의 순서를 0부터 세기 때문이다.

(조건문) 조건은 workoutName의 데이터 수가 i보다 클 때까지 반복되는 걸로,

(증감문) i는 1씩 추가되는걸로 구성되었다.

(실행문) workoutsToday 리스트에 Row 구문이 add되는 코드가 실행이 된다.

 

 

12. 이렇게 하면, 운동명 리스트 안에 들어있는 운동명의 개수 만큼 운동명과 회수가 기록된 Row를 실행하는 반복구문이 완성이 된다.

 

body: Center(
  child: Column(
    children: [
      Card(
        child: Column(
          children: [
            Text('오늘의 운동'),
            ...workoutsToday
          ],
        ),
      ),
    ],
  ),
),

 

12. body로 내려가서, 기존에 한 땀 한 땀 만들었던 Row를 날리자. 이제는 for 구문에서 자동으로 반복실행을 해주니까.

대신 ...workoutsToday라는 코드 한 줄을 넣어주자. 

 

 

위와 같은 결과물이 앱으로 나타난다.

Row를 한 땀 한 땀 추가하며 만든 것과 결과물은 같지만, 코드 자체도 훨씬 간결해지고

리스트에 운동명과 갯수만 넣거나 빼면, 바로바로 변경이 가능하다.

 

 

 

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const WorkoutTrackerPage(),
    );
  }
}

class WorkoutTrackerPage extends StatefulWidget {
  const WorkoutTrackerPage({super.key});

  @override
  State<WorkoutTrackerPage> createState() => _WorkoutTrackerPageState();
}

class _WorkoutTrackerPageState extends State<WorkoutTrackerPage> {

  List<String> workoutName=['싯업','친업','스쿼트','푸시업','버피'];
  List<int> workoutGoal=[50,15,100,45,30];
  List<Row> workoutsToday=[];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    for(var i=0;i<workoutName.length;i++) {

      workoutsToday.add(
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text('${i+1}. ${workoutName[i]}'),
              Text('${workoutGoal[i]}회'),
            ],
          )
      );
    }
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('운동추적', style: TextStyle(backgroundColor:Colors.amberAccent ,color: Colors.black),),

      ),
      body: Center(
        child: Column(
          children: [
            Card(
              child: Column(
                children: [
                  Text('오늘의 운동'),
                  ...workoutsToday
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

 

* 다음 포스팅에서 계속

728x90
반응형

댓글