1. 조건문
조건문이란? 조건문은 프로그램이 특정 조건을 만족할 때만 특정 코드를 실행하도록 제어하는 문장이다. 조건문은 프로그램의 흐름을 제어하는 데 사용되며 정말 많이 사용하게 되는 중요한 문법이라고 기억하면 된다. 조건문에는 if문과 switch문으로 구분할 수 있다.
- if/else 예시
if문은 괄호 안에 조건이 참인 경우에만 코드 블록을 실행하게 된다.
if( 조건 비교 ){
참인 경우 실행될 로직
} else {
위 조건이 거짓일 경우 실행될 로직
}
void main() {
int number = 3;
if (number > 5) {
print('number는 5보다 큽니다.');
} else {
print('number는 5보다 크지 않습니다.');
}
}
- switch 예시
switch 문은 하나의 변수 값에 따라 여러 분기에서 코드를 실행한다.
switch문을 사용하는 경우
- 조건이 특정 값(상수)과 비교될 때
- 코드의 가독성을 높이고 싶을 때
- enum 타입과 같은 열거형을 비교할 때
- 열거형의 경우 IDE에서 자동으로 모든 case를 자동으로 만들어주기 때문에 enum을 비교할때는 switch문을 사용하는 것이 좋다.
자동으로 case만드는 방법
switch 에 커서를 위치 시키고 command + . 키 window의 경우 ctrl + . 키를 눌러 Add missing switch cases 를 눌러준다.
enum을 switch로 사용할 경우 모든 type을 case로 정의해줘야 오류가 없어진다.
EX)
switch( 확인할 변수 ) {
case [환인할 변수에 해당되는 값] :
실행로직;
break;
case [환인할 변수에 해당되는 값2] :
실행로직;
break;
case [환인할 변수에 해당되는 값3] :
실행로직;
break;
default:
모든 case에 해당되지 않는 경우 실행 로직 ;
}
void main() {
int number = 2;
switch (number) {
case 1:
print('number는 1입니다.');
break;
case 2:
print('number는 2입니다.');
break;
case 3:
print('number는 3입니다.');
break;
default:
print('number는 1, 2, 3 중 하나가 아닙니다.');
}
}
- instantFirstCard 생성
int instantFirstCard = -1;
- 카드 선택이 처음일때 onTopCard함수 로직
void onTapCard(int cardIndex) {
print('$cardIndex 번째 카드를 선택하셨습니다.');
if (instantFirstCard == -1) { // 추가
instantFirstCard = cardIndex;
}
setState(() {
cardsFlippedState[cardIndex] = true;
});
}
- 카드 선택이 두번째일때 onTapCard함수 로직
void onTapCard(int cardIndex) {
print('$cardIndex 번째 카드를 선택하셨습니다.');
if (instantFirstCard == -1) {
instantFirstCard = cardIndex;
}else{
// 두번째 카드가 선택되었을때 로직 추가
}
setState(() {
cardsFlippedState[cardIndex] = true;
});
}
- 카드 선택이 두번째일때 else 케이스 로직1
else{
// 두번째 카드가 선택되었을때 로직 추가
var firstCard = cards[instantFirstCard];
var secondCard = cards[cardIndex];
}
- 카드 선택이 두번째일때 else 케이스 로직2
else{
// 두번째 카드가 선택되었을때 로직 추가
var firstCard = cards[instantFirstCard];
var secondCard = cards[cardIndex];
if (firstCard == secondCard) {
print('짝이 맞았습니다.');
}
}
- 두 개의 카드가 같지 않은 경우
else {
// 두번째 카드가 선택되었을때 로직 추가
var firstCard = cards[instantFirstCard];
var secondCard = cards[cardIndex];
if (firstCard == secondCard) {
print('짝이 맞았습니다.');
} else {
cardsFlippedState[instantFirstCard] = false; // 추가
cardsFlippedState[cardIndex] = false; // 추가
}
}
- 카드 뒤집기 오류 해결
void onTapCard(int cardIndex) {
print('$cardIndex 번째 카드를 선택하셨습니다.');
if (instantFirstCard == -1) {
instantFirstCard = cardIndex;
} else {
// 두번째 카드가 선택되었을때 로직 추가
var firstCard = cards[instantFirstCard];
var secondCard = cards[cardIndex];
if (firstCard == secondCard) {
print('짝이 맞았습니다.');
} else {
setState(() {
cardsFlippedState[instantFirstCard] = false;
cardsFlippedState[cardIndex] = false;
});
return; //추가
}
}
setState(() {
cardsFlippedState[cardIndex] = true;
});
}
- 첫번째 문제 해결
void onTapCard(int cardIndex) {
print('$cardIndex 번째 카드를 선택하셨습니다.');
if (instantFirstCard == -1) {
instantFirstCard = cardIndex;
} else {
// 두번째 카드가 선택되었을때 로직 추가
var firstCard = cards[instantFirstCard];
var secondCard = cards[cardIndex];
if (firstCard == secondCard) {
print('짝이 맞았습니다.');
instantFirstCard = -1; // 추가
} else {
setState(() {
cardsFlippedState[instantFirstCard] = false;
cardsFlippedState[cardIndex] = false;
});
instantFirstCard = -1; // 추가
return;
}
}
setState(() {
cardsFlippedState[cardIndex] = true;
});
}
2. 동기/비동기
동기(Synchronous)란? 동기 방식에서는 작업이 순차적으로 처리되는 것을 의미한다. 하나의 작업이 끝나야 다음 작업이 진행이 되는 것이다.
동기 방식의 일상 예시
은행 창구에 창구가 하나인 은행이 있다. 사람들은 입/출금을 할 때 은행 창구에 번호표를 뽑고 기다린다. 내 차례가 되기 위해서는 나보다 먼저 번호표를 뽑은 사람들이 모든 업무를 다 보고 나서야 내 차례가 된다.
이런 방식이 동기 방식으로 일처리를 한다 생각면 된다.
동기 방식의 단점
1.블로킹
• 특히 시간이 오래 걸리는 작업이 있을 경우 전체 프로그램의 응답성이 저하됩니다.
• 하나의 작업이 완료될 때까지 다른 작업이 블로킹됩니다.
2.비효율성
• 예를 들어, 네트워크 요청 동안 CPU는 유휴 상태가 됩니다.
• 자원이 비효율적으로 사용될 수 있습니다.
- 동기 방식 소스코드
void main() {
print('작업 1 시작');
performTask();
print('작업 1 완료');
}
void performTask() {
print('작업 2 실행');
}
출력
작업 1 시작
작업 2 실행
작업 1 완료
비동기(Asymchronous)
비동기란? 비동기 방식에서는 작업이 병렬적으로 처리될 수 있다. 즉, 작업이 완료될 때까지 기다리지 않고 다음 작업을 바로 시작한다. 주로 네트워크 요청, 파일 읽기/쓰기 등 시간이 걸리는 작업에 사용된다.
비동기 방식의 일상의 예시
은행 창구가 하나였던 은행이 사업이 잘 되는 것과 동시에 사용자들의 불편사항을 개선하기로 하여 창구를 4개로 늘렸다. 이제부터 4명씩 동시에 입/출금을 할 수 있게 되어 빠른 회전율이 생겼다.
이러한 방식이 비동기 방식이라고 볼 수 있다.
비동기 방식의 단점
1.복잡성
• 코드가 복잡해질 수 있습니다. • 비동기 함수의 오류 처리 등이 복잡합니다.
2.디버깅 어려움
• 비동기 코드의 흐름을 추적하고 디버깅하는 것이 더 어렵습니다. • 이벤트 루프와 비동기 호출 스택을 이해해야 합니다.
-비동기 방식 소스코드
void main() {
print('작업 1 시작');
performTask();
print('작업 1 완료');
}
Future<void> performTask() async {
await Future.delayed(Duration(seconds: 2));
print('작업 2 실행');
}
출력
작업 1 시작
작업 1 완료
(2초뒤에)
작업 2 실행
async/await
동기와 비동기에 대한 설명을 들으면 동기 방식보다 비동기 방식이 무조건적으로 좋다고 느껴질 수 있다. 하지만 프로그래밍을 하다 보면 비동기 상황을 동기처럼 처리해야 할 때가 있다.
비동기처리를 동기처럼 해야 할때 일상 예시
은행 창구를 4개로 늘렸던 은행에 현금 흐름이 빨라지다 보니 은행 내부에 보유해야 하는 현금의 비율이 20% 이하로 떨어지게 되어 은행 출금 시에는 현금의 상태를 체크해가면서 출금을 해줘야 하는 상황이 왔다. 여전히 업무는 4개의 창구에서 동시에 처리 되지만 4명의 고객이 출금을 요청할 경우 4구좌가 순서를 정해서 현금 상태가 고객이 요청하는 금액보다 여유가 있는지 체크를 하고 현금 상태를 반영하고 그 뒤를 기다렸다가 다음 사람이 받아서 처리하는 방식으로 해야 문제가 발생되지 않는다.
이러한 상황이 비동기 처리를 동기식으로 해야 할 예시이다.
프로그래밍에서 비동기적인 상황은 다양하게 발생할 수 있다. 가장 대표적으로 서버로부터 데이터를 요청할 때이다. 서버부터 데이터를 요청 시 요청한 것을 받아야만 화면에 결과를 보여줄 수 있기 때문에 요청하고 나서 결과를 받을 때까지 기다려야 하는 상황을 만들어줘야 하는데 그것을 처리할 수 있게 도와주는 것이 async와 await 문법이다.
async 키워드
- 함수에 async를 붙이면 비동기 함수가 된다.
- 비동기 함수는 항상 Future 객체를 반환되도록 설계 되어있다.
await 키워드
- await은 비동기 함수 내에서만 사용이 가능하다.
- await은 Future가 완료될때가지 기다리며 완료되면 결과 값을 반환한다.
- await은 비동기 코드를 동기 코드처럼 작성할 수 있게 해준다.
- 비동기 방식 > 동기 방식으로 처리하는 소스코드
void main() async{
print('작업 1 시작');
await performTask();
print('작업 1 완료');
}
Future<void> performTask() async {
await Future.delayed(Duration(seconds: 2));
print('작업 2 실행');
}
출력
작업 1 시작
(2초뒤에)
작업 2 실행
작업 1 완료
- onTapCard 소스 코드 분리
void onTapCard(int cardIndex) {
print('$cardIndex 번째 카드를 선택하셨습니다.');
if (instantFirstCard == -1) {
instantFirstCard = cardIndex;
} else {
// 두번째 카드가 선택되었을때 로직 추가
var firstCard = cards[instantFirstCard];
var secondCard = cards[cardIndex];
if (firstCard == secondCard) {
print('짝이 맞았습니다.');
instantFirstCard = -1; // 추가
} else {
resetInstantCards(instantFirstCard, cardIndex); // 추가
}
}
setState(() {
cardsFlippedState[cardIndex] = true;
});
}
void resetInstantCards(int firstIndex, int secondIndex) {
setState(() {
cardsFlippedState[firstIndex] = false;
cardsFlippedState[secondIndex] = false;
});
instantFirstCard = -1;
return;
}
-resetInstantCards 2초 지연
void resetInstantCards(int firstIndex, int secondIndex) async{
await Future.delayed(Duration(seconds: 2)); // 추가
setState(() {
cardsFlippedState[firstIndex] = false;
cardsFlippedState[secondIndex] = false;
});
instantFirstCard = -1;
}
3. 클래스(객체)
클래스(객체)란? 우리 일상의 삶도 모든 것이 객체로 이루어져 있다. 예를 들어, 우리가 사용하는 스마트폰, 타고 다니는 자동차, 그리고 우리가 사는 집까지 모두 객체로 볼 수 있다. 각각의 객체는 고유한 속성과 기능을 가지고 있다. 심지어 사람까지 객체로 볼 수 있다.
3-1. 객체의 구성
class [클래스명] {
생성자()
맴버변수//특성
메서드(){
//기능
}
}
3-2. 객체 생성
인간을 객체로 만들어 보기
class Human{}
사람의 특성 중 고유 식별자 번호 주민번호를 멤버변수로 설정
class Human {
final String id; //주민번호
}
- final이란
final을 넣게 되면 한번 값을 주입하면 바꿀 수 없을을 compiler에게 알려주는 것이다.
Compiler란?
컴퓨터는 0과 1만 이해할 수 있다. 컴퓨터로 이 프로그램을 돌리려면 0과 1로만 개발을 해야 맞다. 하지만 그러면 어느 누구도 개발을 하지 못할 것이다. 그래서 컴퓨터와 개발자와의 중간다리 역할을 해주는 녀석이 필요한데 그것이 Compiler이다. 우리는 우리들이 이해하는 언어로 프로그래밍을 하고 compiler가 우리가 작성한 코드를 컴퓨터가 알수있는 언어로 변환을 시켜 프로그램이 돌아가도록 하는 것이다.
몇 가지 특성을 부여해 볼것 이다. 이름과 나이 그리고 성별이 있다. 이것을 추가로 정의해 보겠다.
class Human{
final String id;
final String name;
final int age;
final Gender gender;
}
여기에서 id,name,age 타입은 알겠는데 Gender 타입은 처음 볼 것입니다. 이것은 Custom Enum 타입으로 만들어줄 것입니다. enum은 열거형입니다. Gender는 다음과 같이 작성하겠습니다.
enum Gender{
M,W
}
3-3. 생성자(constructor)
인스턴스화를 위해 생성자만들기
class Human{
final String id;
final String name;
final int age;
final Gender gender;
const Human( // 생성자
this.id,
this.name,
this.age,
this.gender,
);
}
3-4. 메서드 정의
나이를 한살씩 먹는 메서드를 추가해보기
class Human {
final String id;
final String name;
int age;
final Gender gender;
Human({
required this.id,
required this.name,
required this.age,
required this.gender,
});
void addAge(){
age++;
}
}
3-5. 클래스 응용 예제
void main() async {
var totalYears = 10;
print('프로그램 시작');
var man = Human(
id: '860319-xxxxxxx',
name: '김성덕',
age: 39,
gender: Gender.M,
);
for (var currentYear = 1; currentYear < totalYears; currentYear++) {
await Future.delayed(Duration(seconds: 1));
print('$currentYear년이 흘렀습니다.');
man.addAge();
print('${man.name}은 ${man.age} 나이입니다.');
}
print('프로그램 종료');
}
출력결과
프로그램 시작
1년이 흘렀습니다.
김성덕은 40 나이입니다.
2년이 흘렀습니다.
김성덕은 41 나이입니다.
.
.
.
8년이 흘렀습니다.
김성덕은 47 나이입니다.
9년이 흘렀습니다.
김성덕은 48 나이입니다.
프로그램 종료
'flutter앱개발과정' 카테고리의 다른 글
flutter앱개발 - StatelessWidget과 StatefulWidget (0) | 2025.02.11 |
---|---|
flutter앱개발 - 위젯 (1) | 2025.02.11 |
flutter앱개발 - Dart 문법 (0) | 2025.02.06 |
flutter 앱개발 개발환경 세팅 - flutter doctor 명령어 이슈 대응 (0) | 2025.02.05 |
flutter앱개발 - Windows개발환경 설정 (0) | 2025.02.04 |