Flutter 캠프 11일차

은성·2025년 12월 8일

Flutter 본캠프

목록 보기
12/57
post-thumbnail

오늘의 내용

예외, 오류, 라이브러리

모닝스터디

/// 별 피라미드 출력 하기
void main() {
  //        *
  //       ***
  //      *****
  //     *******
  //    **********
  //   ************
  //  **************
  // ****************

  // int star = 1;
  // print("        ${"*" * star}");
  // star = star + 2; // => 3
  // print("       ${"*" * star}");
  // star = star + 2; // => 3+2 = 5
  // print("      ${"*" * star}");
  // star = star + 2; // => 5+2 = 7
  // print("     ${"*" * star}");
  // star = star + 2; // => 7+2 = 9
  // print("    ${"*" * star}");
  // star = star + 2; // => 9+2 = 11
  // print("   ${"*" * star}");
  // star = star + 2; // => 11+2 = 13
  // print("  ${"*" * star}");
  // star = star + 2; // => 13+2 = 15
  // print(" ${"*" * star}");

  int star = 1;
  for (var i = 0; i <= 7; i++) {
    // 1단 => 별 1개
    // 2단 => 별 3개
    // 3단 => 별 5개...
    // 별이 2씩 증가
    String space = ' ' * (7 - i);
    // 여기서 별 출력
    // 공백 => -1씩 빼는거 : Strint 7-"i"
    print(space + '*' * star);
    star = star + 2; // => star 15
  }
  // 별이 반대로 감소 하는 걸로 만듬
  for (var i = 1; i <= 7; i++) {
    int spaceCount = i + 0;
    star = star - 2; // => star 13
    // print("공백 : $spaceCount 현재별개수 : $star");  => 공백 1 => 1++
    print(' ' * spaceCount + '*' * star);
  }
}
void main() {
  // 2는 고정
  // 곱해지는 수가 1씩 증가

  // 첫번째 단계 : 1부터 9까지 반복문으로 출력하기
  // 두번째 미션 : 2단부터 9단까지 출력
  for (var i = 1; i <= 9; i++) {
    print('2 * $i = ${2 * i} ');
  }
  // print(' 2 * 1 = 2 ');
  // print(' 2 * 2 = 4 ');
  // print(' 2 * 3 = 6 ');
  // print(' 2 * 4 = 8 ');
  // print(' 2 * 5 = 10 ');
  // print(' 2 * 6 = 12 ');
  // print(' 2 * 7 = 14 ');
  // print(' 2 * 8 = 16 ');
  // print(' 2 * 9 = 18 ');
}

예외

  • 프로그램이 실행되는 동안 발생하는 예외적인 상황

특징

  • 예외를 처리해주지 않으면 프로그램이 종료되지만,
    처리해주면 프로그램이 정상적으로 실행됨
  • 모든 종류의 예외는 Exception 클래스를 상속받아서 구성됨
  • 모든 종류의 예외는 Exception 클래스의 하위 클래스임
  • 예외는 Exception 클래스를 상속받은 클래스로 객체를 생성해주는것이 좋음

종류

  • 정의하는 주체에 따라 2가지로 나뉜다

Dart가 미리 정의해둔 예외

DeferredLoadException

-필요한 시점에 로드되도록 설정한 라이브러리가 로드되지 못 했을 때 발생

DeferredLoadException(String message)

message 에 예외에 대한 설명을 써주면 돼요.

FormatException

  • 데이터가 처리가능한 형태가 아니라 데이터를 처리하기 어려울 때 발생
FormatException([String message = "", dynamic source, int? offset])

message : 예외에 대한 설명
source : 예외가 발생한 원인이 되는 것

IOException

  • 입,출력 관련동작을 하는 중 발생
FileSystemException
  • 파일을 다룰 때 발생
  • 파일에 접근할 수 없는 경우, 파일이 없는경우, 파일을 찾을 수 없는 경우 등
  • HttpException
  • ProcessException
  • SignalException
  • SocketException
  • StdinException
  • StdoutException
  • TlsException
  • WebSocketException

OSError

  • 운영체제 레벨에서 발생
  • 운영체제로부터 받은 오류에 대한 정보를 가지고 있음
OSError([String message = "", int errorCode = noErrorCode])

message 에는 운영체제가 제공하는 예외에 대한 설명이 들어가요.
운영체제가 설명을 제공하지 않으면 빈 문자열 (””) 이 적용돼요.
errorCode 에는 운영체제가 제공하는 오류 코드가 들어가요.

TimeoutException

  • 비동기 결과를 기다리는 동안 특정 시간이 초과되었을 때 발생
TimeoutException(String? message, [Duration? duration])

message 에는 시간 초과가 발생한 원인에 대한 설명이 들어가고,
duration 에는 초과된 시간이 들어가요.

사용자가 직접 정의한 예외

  • Dart가 정의한 예외들이 마음에 안들어 커스텀하고 싶을 때 사용

사용법

  • Exception 클래스를 상속 받아서 새로운 예외 클래스를 만들수 있음
class AgeException implements Exception {
  final String message;
  
  AgeException(this.message);
}

상속 받을 때 implements 키워드를 사용한다고 했던 것 기억하죠 ~?

class AgeException implements Exception {
  final String? message;
  
  AgeException(this.message);
  
  
  String toString() => message ?? 'AgeException 이 발생했어요 !';
}

예외 클래스도 당연히  를 통해 재정의할 수 있어요 👍🏼
상속 받은 후에  를 통해 재정의할 수 있다고 했던 것 기억하죠 ~?

예시

class AgeException implements Exception {
  final String? message;
  
  AgeException(this.message);
}

void printAge(int age) {
	if (age < 0) {
		throw AgeException(null);
	}
  print(age);
}

void main() {
	try {
		printAge(-8);
	} catch (e) {
    print(e);
  }
}

printAge() 의 매개변수에 음수값을 전달했기 때문에
Instance of 'AgeException’ 이 출력돼요.

class AgeException implements Exception {
  final String? message;
  
  AgeException(this.message);
}

void printAge(int age) {
	if (age < 0) {
		throw AgeException(null);
	}
  print(age);
}

void main() {
	try {
		printAge(8);
	} catch (e) {
    print(e);
  }
}

printAge() 의 매개변수에 0 이상의 값을 전달했기 때문에 8 만 출력돼요.

class AgeException implements Exception {
  final String? message;
  
  AgeException(this.message);
  
  
  String toString() => message ?? 'AgeException 이 발생했어요 !';
}

void printAge(int age) {
	if (age < 0) {
		throw AgeException(null);
	}
  print(age);
}

void main() {
	try {
		printAge(-8);
	} catch (e) {
    print(e);
  }
}

printAge() 의 매개변수에 음수값을 전달했기 때문에
AgeException 이 발생했어요 ! 가 출력돼요.

class AgeException implements Exception {
  final String? message;
  
  AgeException(this.message);
  
  
  String toString() => message ?? 'AgeException 이 발생했어요 !';
}

void printAge(int age) {
	if (age < 0) {
		throw AgeException('0 이상의 값을 넣어야 해요 !');
	}
  print(age);
}

void main() {
	try {
		printAge(-8);
	} catch (e) {
    print(e);
  }
}

AgeException 의 생성자에 null 이 아닌 값을 넣어 주었기 때문에
0 이상의 값을 넣어야 해요 ! 가 출력돼요.

예외 키워드

try,catchmon,finally

  • 발생한 예외를 처리하기 위한 경우 사용
  • 예외가 발생할 수 있는 코드를 넣는다
  • 예외 처리 구문을 쓸 때 꼭 넣어야 한다.

try

  • try 의 코드 블록 실행 중에 예외가 발생하면
    try 의 코드 블록에 있는 뒷 코드들은 실행되지 않아요.
try {
	// 예외가 발생할 수 있는 코드
}

catch

  • try의 코드 블록 싱행 중에 예외가 발생했을 때 실행할 코드를 넣는 부분
  • try의 코드 블록에서 예외가 발생하지 않으면 실행되지 않음
  • 예외 처리 구문을 쓸때 꼭 넣어야 하고, 개수에 제한이 없음
catch (e) {
	print(e);
}

발생한 예외의 객체가 catch 의 매개변수로 전달돼요.

on

  • try 의 코드 블록에서 발생할 수 있는 예외 중 특정 타입의 예외를 다루는 부분
  • 예외 처리 구문을 쓸 때 넣지 않아도 됨
  • 단독으로 사용할 수 없고, catch 와 항상 같이 써야함
on IOException catch (e) {
	// IOException 이 발생했을 때 실행할 코드
}

void main(){
try
String invalidNumber = "abc";
int result = int.parse(invalidNumber);
} catch (e) {
print(e);
	}
}

on 으로 예외 타입을 특정해 주지 않으면
Exception 이 기본적으로 가지고 있는 4가지 요소만 사용할 수 있어요.

```dart
void main(){
try
String invalidNumber = "abc";
int result = int.parse(invalidNumber);
} on FormatException catch (e) {
print(e);
	}
}

on 으로 예외 타입을 특정해 주면 그 타입이 가지고 있는 요소들을 사용할 수 있어요.

finally

  • 예외 발생 여부와 상관없이 실행할 코드를 넣는다.
  • try,catch를 모두 거친 후 실행
  • 구문 넣이 않아도 된다.
finally {
	// 예외 처리 후 실행할 코드
}

try {
	String invalidNumber = "abc";
	int result = int.parse(invalidNumber);
	print(result);
} catch (e) {
	print(e);
}

e 에 FormatException 클래스의 객체가 전달돼서
FormatException: abc 라고 출력된답니다 !
try 의 코드 블록에 있는 int.parse(invalidNumber); 에서 예외가 발생했기 때문에
그 아래에 있는 print(result); 는 실행되지 않고, catch 문으로 넘어가요.

try {
	String invalidNumber = "abc";
	int result = int.parse(invalidNumber);
	print(result);
} on FormatException catch (e) {
	print(e);
}


마찬가지로 e 에 FormatException 클래스의 객체가 전달돼서
FormatException: abc 라고 출력돼요.

try {
	String invalidNumber = "abc";
	int result = int.parse(invalidNumber);
	print(result);
} on FormatException catch (e) {
	print(e);
} catch (e) {
	print(e);
}
on FormatException catch (e) {} 는 FormatException 이 발생하면 실행되고,
catch (e) {} 는 FormatException 이 아닌 다른 예외가 발생하면 실행돼요.

try {
  String invalidNumber = "abc";
  int result = int.parse(invalidNumber);
  print(result);
} catch (e) {
  print(e);
} finally {
  print('예외 처리 끝 -');
}

FormatException: abc 랑 예외 처리 끝 - 이 차례대로 출력되겠죠 ?

try {
  String validNumber = "123";
  int result = int.parse(validNumber);
  print(result);
} catch (e) {
  print(e);
} finally {
  print('예외 처리 끝 -');
}123” 은 정수형으로 변환할 수 있기 때문에 예외가 발생하지 않아요.
그래서 result 값인 123 이랑 예외 처리 끝 - 이 차례대로 출력된답니다 !

throw

  • 예외를 의도적으로 발생시키기 위한 경우
  • 특정 경우에 예외를 의도적으로 발생시키기 위해
  • Exception 클래스나 Error 클래스를 통해 생성한 객체를 던짐
    Exception 클래스나 Error 클래스를 상속 받은 클래스도 가능

void printAge(int age) {
  if (age < 0) {
    throw Exception('나이는 0 이상이어야 해요 !');
  }
  print(age);
}

void main() {
  try {
    printAge(-8);
  } catch (e) {
    print(e);
  }
}

printAge() 의 매개변수에 음수값을 전달하면 Exception 이 발생하기 때문에
Exception: 나이는 0 이상이어야 해요 ! 가 출력돼요.
try 의 코드 블록 실행 중에 Exception 이 발생했으니
print(age); 는 실행되지 않겠죠 ?
  • throw 를 통해 발생된 예외는 try, catch, on 으로 처리할 수 있음

void printAge(int age) {
  if (age < 0) {
    throw Exception('나이는 0 이상이어야 해요 !');
  }
  print(age);
}

void main() {
  try {
    printAge(8);
  } on Exception catch (e) {
    print(e);
  }
}

printAge() 의 매개변수에 0 이상의 값을 전달하면
Exception 이 발생하지 않기 때문에 print(age);8 이 출력돼요.

오류

  • 주로 프로그램 외부의 환경이나 시스템 레벨에서 발생하는 심각한 문제

특징

  • 모든 종류의 Error크래스를 상속받아서 구성
  • 발생하면 프로그램이 정상적으로 실행되기 어려워짐

Dart가 미리 정의해 둔 오류

ArgumentEroor

  • 허용되지 않는 인자를 함수에 전달했을 때 발생함

AssertionError

  • assert() 문의 매개변수에 전달하는 조건문이 거짓일 때 발생해요.
    assert : 매개변수에 넣은 조건문이 참이면 정상적으로 실행이 계속 되고,
    조건문이 거짓이면 예외 (AssertionError) 를 발생시켜요.
  • 논리 적인 오류를 잡아낼 때 사용
void checkAge(int age) {
  assert(age > 0, 'Age must be positive');
}

void main() {
  checkAge(-5); // AssertionError 발생
}


checkAge() 의 매개변수에 -5 를 전달하면
assert() 의 매개변수에 있는 조건문이 거짓이 되기 때문에
AssertionError 가 발생하겠죠 ?

종류

assert([조건문]);

assert(text != null);

text 가 null 이면 AssertionError 가 발생하겠죠 ?

assert(number < 100);

number 가 100 이상이면 AssertionError 가 발생하겠죠 ?

assert(urlString.startsWith('https'));

urlString 이 ‘https’ 로 시작하지 않으면
AssertionError 가 발생하겠죠 ?
참고로, startsWith() 는 문자열이 특정 값으로 시작하는지 판별하는 함수랍니다 !

assert([조건문], '[메시지]');

assert(number < 100, '100 이상이면 안 돼요 !');

조건문이 거짓이면 조건문 옆에 있는 메시지가 출력돼요.

RangeError

  • 허용되지 않는 범위의 값이 매개변수로 전달되었을 때 발생
    ArgumentError클래스를 상속 받은 클래스

var numbers = [1, 2, 3];
print(numbers[3]);

numbers 는 요소의 개수가 3 이기 때문에 Index 가 3 인 요소는 있을 수 없겠죠 ?
그래서 RangeError 가 발생한답니다 😅

IndexError

  • 허용되지 않는 범위의 index를 사용했을 때 발생
  • RangError클래스를 상속 받은 클래스
var numbers = [1, 2, 3];
print(numbers[-1]);
print(numbers[5]);

Index 는 0 이상의 정수만 가능하다고 했던 것 기억하시나요 ? 🧐
그래서 Index 에 음수를 넣으면 IndexError 가 발생해요.

NoSuchMethodError

  • 함수나 메서드를 실행할 수 없는 경우 발생

OutOfMemoryError

  • 프로그램이 시스템 메모리를 너무 많이 써서 더 이상 할당할 수 없을 때

StackOverflowError

  • 스택 오버 플로우 일 때 발생
  • 메모리 공간 중 하나인 스택 영역이 수용 가능한 범위를 넘어갈 때

메모리공간

  • 코드 : 프로그램에서 실행할 코드를 담는 공간
  • 데이터 : 전역 변수 , 정적 변수를 담는 공간
  • 힙 : 개발자가 직접 할당하고, 해제할 수 있는 동적 공간
  • 스택 : 지역 변수 , 매개변수 를 담는 공간

StateError

  • 객체의 현재 상태로는 특정 동작 수행이 불가능한 경우

TypeError

  • 예상한 타입이 맞지 않는 경우

UnimplementedError

  • 구현되지 않은 메서드나 기능을 호출했을 때 발생

UnsupportedError

  • 객체를 통해 실행될 수 없는 동작일 때 발생

사용자가 직접 정의한 오류

  • Dart가 정의한 오류가 별로라 커스텀 할 때
    Error클래스를 상속받아서 새로운 오류 클래스를 만들면 됨
class AgeError extends Error {
  final String message;
  
  AgeError(this.message);
}

class AgeError extends Error {
  final String? message;
  
  AgeError(this.message);
  
  
  String toString() => message ?? 'AgeError 가 발생했어요 !';
}

  • 오류 클래스도 당연히 @override 를 통해 재정의할 수 있어요 👍🏼
    상속 받은 후에 @override 를 통해 재정의할 수 있다고 했던 것 기억하죠 ~?

예외, 오류 차이점

발생시점

  • 예외 : 코드가 논리적으로 맞지 않거나 적절하지 않은 값이 입력되었을 때
  • 오류 : 주로 시스템에 문제가 생겼을 때

예상가능여부

  • 예외 : 예상 할 수 있음
  • 오류 : 예상 할 수 없음

발생 후 처리

  • 예외 : try-catch 를 통해 처리할 수 있다.
  • 오류 : 발생을 예상할 수 없기 때문에 처리할 수 없어요.

발생 후 프로그램 실행 여부

  • 예외 : 발생 후 처리 해줄경우 정상적으로 실행 가능
  • 오류 : 발생 시 프로그램이 종료

라이브러리

  • 특정 기능이나 작업을 쉽고 빠르게 수행할 수 있도록 미리 만들어둔 코드의 집함
  • 작업을 수행할 때 자주 사용하는 코드들을 모아둔 것

사용이유

효율성

  • 필요한 기능만 뽑아서 사용할 수 있음
  • 많은 시간이 걸리는 작업을 빠르게 구현할 수 있음
  • 모든 코드를 직접 작성하지 않아도 원하는 기능을 구현할 수 있음

재사용성

  • 같은 코드를 여러 번 작성하지 않고, 코드를 재사용할 수 있음

코드 가독성

  • 같은 코드를 여러 번 작성하지 않기 때문에 코드가 간단해짐

종류

Dart SDK 에 포함되어 있는 라이브러리

  • Dart SDK 표준 라이브러리라고 부름

특징

  • 프로그래밍에 필요한 기능을 제공하는 핵심 라이브러리 들을 가지고 있음

모든 플랫폼

dart:core

  • 타입 , 콜렉션 등 핵심 기능을 지원함
  • Dart 프로그램에 포함되어 있어서 따로 import 해주지 않아도 됨

dart:async

  • Future, Stream 과 같은 클래스를 통해 비동기 프로그래밍을 지원함

dart:collection

  • dart:core에서 제공하지 않는 무거운 콜렉션 타입을 제공함
    예시 : queue, linked list, hashmap, binary tree

dart:convert

  • 서로 다른 데이터 표현 방식을 가진 데이터 (JSON , UTF-8)을 전환하기 위한 인코더 와 디코더를 제공함

dart:developer

  • 디버거 같은 개발자 도구와 상호작용하는 기능을 제공함

dart:math

  • 수학 상수와 함수, 난수 생성 등의 수학 관련 기능을 제공함

Native platform

  • Native platform의 타겟은 Mobile, Desktop

dart:ffi

  • DartC API를 사용할 수 있도록 하는 기능을 제공함

dart:io

  • 파일, 소켓, http, 기타 입,출력 드의 기능을 제공함

Web platform

  • JavaScript 로 컴파일되는 코드랍니다 !

package:web

  • 가벼운 브라우저 API와 연결하는 기능을 제공함

dart:js_interop

  • JavaScript 와 브라우저 API 를 상호운용할 수 있는 기능을 제공함

dart:html

  • HTML 요소들과 Web 기반 응용 프로그램 리소스들을 제공함

Dart SDK 에 포함되어 있지 않은 라이브러리

  • Dart SDK가 제공하는 표준 라이브러리가 아닌 외부 개발자들이 만든 라이브러리
  • Pub.dev 에서 다양한 외부 라이브러리를 쉽게 찾아서 사용할 수 있음

Pub.dev

cupertino_icons

  • FlutterCupertino 위젯에 쓰이는 기본 아이콘 에셋을 제공함

intl

  • 번역, 날짜 포맷팅, 숫자 포맷팅 등 국제화와 현지화 기능을 제공함

shared_preferences

  • 간단한 데이터를 다루는 기능을 제공함
  • OSmacOS 에서 사용하는 NSUserDefaults,
    Android 에서 사용하는 SharedPreferences 와 같은 역할

url_launcher

  • URL 을 다루는 기능을 제공함

image_picker

  • iOSAndroid 에서 사진 다루는 기능을 제공함
  • 예시로 카메라로 사진 찍는 기능이랑 앨범에서 사진 선택하는 기능이 있음

firebase_core

  • Firebase 와 연동하는 작업할 때 필요한 핵심 기능을 제공함

firebase_auth

  • Firebase 인증 API 를 사용하기 위한 기능을 제공함

google_fonts

  • 폰트 에서 제공하는 폰트를 사용하기 위한 기능을 제공함

permission_handler

  • iOSAndroid 의 권한을 다루는 기능을 제공함

custom_lint

  • Lint 규칙을 쉽게 적용할 수 있도록 해주는 기능을 제공함
    Lint : 오류가 발생할 수 있는 코드, 코드 스타일에 어긋난 코드, 비효율적이거나 불필요한 코드 등을 찾아내서 경고를 띄워주는 도구

flutter_svg

  • SVG 를 렌더링하기 위한 기능을 제공함

cached_network_image

  • 네트워크를 통해 사진을 받아오고, 캐싱하는 기능을 제공함

flutter_local_notifications

  • 로컬 알림을 다루는 기능 (ex. 알림 표시, 알림 예약) 을 제공함

path_provider

  • 파일 시스템을 사용하기 위한 기능을 제공함

geolocator

  • iOS 와 Android 에서 위치를 다루기 위한 기능을 제공함

dio

  • HTTP 네트워크 사용을 위한 기능을 제공함

사용법

import

import 'dart:html';

Dart 에서 제공하는 html 을 가져온다는 뜻 !

import 'package:http/http.dart'

http 패키지를 가져온다는 뜻 !
보통 pub.dev 에 있는 외부 라이브러리를 가져올 때 package: 접두사가 붙어요.

특징

as

  • 라이브러리에 별칭을 부여할 수 있음
import 'package:http/http.dart' as http;

package:http/http.dart 는 http 라는 별명이 생긴 것이랍니다 !

show

  • 필요한 부분만 선택적으로 가져올 수 있음
import 'package:lib1/lib1.dart' show foo;

package:lib1/lib1.dart 에서 foo 만 가져온다는 뜻 !

hide

  • 특정 부분을 제외하고 가져올 수 있음
import 'package:lib2/lib2.dart' hide foo;

package:lib2/lib2.dart 에서 foo 를 제외하고 가져온다는 뜻 !

deferred as (지연로딩)

  • 라이브러리가 필요한 시점에 로드되도록 할 수 있음
  • 초기화 시간 단축 , 성능 향상
    (Wepplatform 에서만 지원)

import ‘[라이브러리 이름이나 파일 경로]’ deferred as [식별자];

import 'package:greetings/hello.dart' deferred as hello;

  • deferred as 뒤에 썼던 식별자를 통해 loadLibrary() 를
    라이브러리가 필요한 시점에 호출하면 그 라이브러리를 불러와요 !
import 'package:greetings/hello.dart' deferred as hello;

Future<void> greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

참고로, await 는 실행이 끝날 때까지 다음 작업을 못 하도록 해요.
그럼 await hello.loadLibrary(); 때문에
라이브러리가 로드될 때까지 멈춰 있겠죠 ?
  • 저는 loadLibrary() 를 정의한 적이 없는데, 어떻게 된건가요 ?
    deferred as [식별자] 를 통해 식별자를 만들어 주는 순간,
    그 식별자에 loadLibrary() 가 자동으로 정의된답니다 🤩

0개의 댓글