Skip to main content

13 posts tagged with "dart"

about dart grammar

View All Tags

운동하실 앱을 만들면서 느낀 것!

· 4 min read
Junseok Yang
Football Loving Programmer
  • 조별 과제를 마무리하면서

이번 위치 기반 채팅앱 과제를 듣고 나서 예전부터 운동 관련해서 이 기능과 비슷한 서비스를 만들어 보고 싶었는데 때마침 이런 과제가 나와서 좋았고 팀원들도 저의 의견을 반영해 주셔서 감사했던 것 같음

그래서 내가 만들어 보고 싶은 서비스였기 때문에 평소보다는 의욕 넘치게 앱 로고도 만들어 보고 직접 와이어프레임도 만들었던 것 같음


빌드 문제

프로젝트를 시작하고 IOS 시뮬레이터 build가 안되어서 여러 가지 시도를 했고 가장 도움이 됐던 것은 flutter run —verbose 로 빌드과정을 콘솔에서 보면서 에러 메시지를 통해서 문제원인을 찾아갈 수 있었고 결국 빌드문제를 해결할 수 있었다.


Firebase 연동 및 filter 기능 구현

firebase를 통해 boards 데이터를 가지고 오고 특정 버튼을 누르면 게시글 가운데 축구, 농구, 풋살, 러닝 등 특정 운동에 관련된 게시글만을 띄우는 기능을 구현하고자 함

ViewModel에서 필터 로직 내장하기

  1. BoardStatefilterType 필드를 추가
  2. BoardViewModelsetFilter(String?) 메서드 구현 → state = .. 로 필터 타입 변경
  3. 상태 객체 안에서 filteredBoards 를 계산된 프로퍼티로 노출
class BoardState {
final List<Board> boards;
final String? filterType;

BoardState({
this.boards = const [], this.filterType
});

List<Board> get filteredBoards => filterType == null
? boards
: boards.where((board) => board.type == filterType).toList();

BoardState copyWith({ List<Board>? boards, String? filterType}){
return BoardState(
boards : boards ?? this.boards,
filterType : filterType
)
}
}

Getter 문법

  • 클래스 내의 변수의 값을 상태나 값을 계산한 다음에 제공
  • get foofoo 가 변수인 것
  • obj.foo 로 사용 가능
  • 매개변수는 받을 수 없음 (메서드는 받을 수 있음)
class BoardViewModel extends Notifier<BoardState>{
@override
build() {
return BoardState(filterType: null);
}

void getBoards() async {
BoardRepository boardRepository = BoardRepository();
List<Board>? boards = await boardRepository.getBoardsData();
state = state.copyWith(boards: boards);
}

void setFilter(String? type) {
state = state.copyWith(filterType: type);
}

}

getBoards()

  • filter가 없는 boards 를 가지고 와줌

setFilter()

  • filter 를 정함으로써 statefilteredBoards 의 상태가 변하게 됨

Board_page.dart

Expanded(
child: ListView.builder(
itemCount: boardState.filteredBoards?.length ?? 0,
itemBuilder: (context, index) {
final List<Board> boards = boardState.filteredBoards!;
return BoardItem(boards[index]);
},
),
),
  • board_page 에서 boardStateboards 가 아닌 filteredBoards 를 사용함으로써 filterType 의 유무에 따라 달라지는 filteredBoards 을 받을 수 있음
FilterButton(
text: '전체',
filterFunction: () => ref
.read(boardViewModelProvider.notifier)
.setFilter(null),
),
  • ref.read(boardViewModelProvider.notifier) → boardViewModel
  • ref.watch(boardViewModelProvider) → boardState

결론

  • vue에서 다른 값이 변하면 자동으로 바뀌는 computed 하고 dart의 getter 가 비슷해서 dart의 getter를 활용해서 값이 변경됐을 때 자동으로 변경되는 변수를 만들 수 있음

플러터 기초 복습

· 4 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

  • 오늘은 환경설정 및 플러터 위젯에 대해서 다시 복습을 했다.
  • 다트를 학습하다 보니까 플러터 위젯에 대해서 많이 까먹은 부분이 있어서 강의를 보면서 다시 복습을 할 수 있었다.

✍️ 주요 학습 내용

배운 내용

  • 플러터 환경설정
  • 플러터 위젯

새로 알게된 개념

  • Column() Widget
  • Row() Widget
  • Text() Widget
  • SafeArea() Widget
  • Spacer() widget
    • 사용 가능한 모든 공간을 차지함
    • flex 옵션을 사용해 크기 비율 조정 가능
  • Padding
    • Options
      • padding : EdgeInsets.all(16.0)
        • all() : 상하좌우
        • symmetric(horizonal : 8.0) : 좌우만
        • symmetric(vertical : 8.0) : 상하만
        • only (left : 40.0)
  • Image
    • Image.network(’url’) : 인터넷의 이미지를 사용
    • Image.asset(’assets/image.png’) : 프로젝트에 추가해준 이미지 사용
    • Image.file(File(’디바이스 내 파일경로’)) : 디바이스 내 저장된 사진
    • Image.memory(bytes) : 메모리 내에 있는 이미지 사용
      • fit 옵션
        • BoxFit.contain : 원본사진의 가로 세로 비율 변화 없음
        • BoxFit.fill : 원본사진의 비율을 무시하고 지정한 영역에 사진을 맞춤
        • BoxFit.cover : 원본사진의 가로 세로 비율을 유지한 채로 지정한 영역에 사진을 맞춤. 장점은 사진의 비율을 유지할 수 있다는 점이고 단점은 사진이 지정한 크기를 벗어나면 잘릴 수 있음
  • Expanded
    • Row, Column 내에서 남은 공간을 확장하여 공간을 채울 수 있도록 하는 위젯
  • SizedBox()
    • width
    • height
    • child

기타

cmd + . → Wrap with widget

flutter devtools

cmd + shift + p(command pallete) : Devtools Widget Inspector을 실행

  • debug 제거
  • MaterialApp의 debugShowCheckedModeBanner : false

사용할 이미지 추가

  • 이미지를 프로젝트 경로 내의 폴더 (/assets)를 만들어 복사해 주기
  • pubspec.yaml에 해당 경로에 assets (이미지 등의 파일)이 있다고 알려주기
assets:
- assets/

main 함수와 runApp()

  • flutter를 시작하기 위해서는 main 함수에서 runApp() 함수를 호출해야 함
  • runApp 호출 시 넘겨주는 위젯이 앱의 루트 위젯이 됨
    • 루트 위젯은 플러터가 그림을 그릴 때 가장 먼저 그리는 위젯

Class 구성

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

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

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

class StorePage extends StatelessWidget {
@override
Widget build(BuildContext context){
return Scaffold();
}
}
  • MyApp 에서는 MaterialApp으로 전체 구조를 잡아주고 StorePage에서는 Scaffold로 구성을 해 줌.

실습한 내용

  • Store 앱

🚨 발생한 문제/에러

  • 없음

📝 코드 스니펫

// 오늘 배운 주요 코드
SizedBox(
height : 10.0,
child : Card(child : Text('hello world')),
}

📚 내일 학습할 내용

  • 플러터 나머지 강의

💭 오늘의 회고

잘한 점 👍

  • 플러터 복습

개선할 점 🔨

  • 아침 시간 활용

배운 점 💡

  • 플러터 위젯들

✏️ 참고 자료

RPG 게임 제작하면서 알게 된 점

· 4 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

  • 오늘 최종적으로 과제를 제출할 수 있었다. 과제를 하면서 확실히 어떻게 코드를 구성해야 하는지 생각해 보고 문법 강의에서 배웠던 내용들을 프로젝트에 사용해 봄으로써 내 것으로 만들 수 있었다.
  • 무지성으로 프로그래밍을 하다 보면 코드가 지저분해지는데 조금 더 코드 리펙토링을 해 가면서 깔끔하게 쓸 수 있도록 바꿔나가는 게 필요할 것 같다.

✍️ 주요 학습 내용

새로 알게된 개념

  • 생성자에서 일부는 미리 지정을 해줄 때가 헷갈렸는데 아래의 두 가지 방법으로 가능했다!

class Game{
late Character character;
List<Monster> monsterList;
int killedMonster = 0;

Game({
required this.character,
required this.monsterList
});

Game(this.character, this.monsterList);

}

입력 받기

  • 입력받을 때 null handling을 이런 식으로 강사님이 하시고 계셨다.
stdout.write('이름을 입력해라 짜슥아');
String? name = stdin.readLineSync();

if(name == null){
return ; // 프로그램 종료
}

몬스터 입력

  • file.readAsLinesSync()
    • 이것을 통해서 줄별로 리스트에 넣어줄 수 있다.
    • 이것을 몰라서 split(’,’) 으로 코딩을 해서 고쳤다.
File file = File('monsters.txt');
List<String> lines = file.readAsLinesSync();
// line 단위로 List에 넣어줌
for(var line in lines){
List<String> stats = line.split(',');
if(stats.length != 3) throw FormatException('Invalid Monster');
String name = stats[0];
String name = int.parse(stats[1]);
String name = int.parse(stats[2]);
}

기타

  • while 조건문에서 bool 변수를 만들어 줘서 코딩을 했는데 isNotEmpty 같은 함수를 활용해서 조금 더 간결하게 코드를 짤 수 있었다.
throw StateError('몬스터가 없습니다');

max(0, attack - monster.defense);
= 큰 값을 골라주는 것

while(monsterList.isNotEmpty){}

정규표현식

RegExp(r'^[a-zA-Z가-힣]+$').hasMatch(name);
// regular expression

결과저장

//game class
saveResult(){}

랜덤 30%

  • 100 중에서 30까지 나오면 실행
Random random = Random();

  • 도전 기능 메서드로 구현하기!
increaseDefence(){
defence += 2;
}

실습한 내용

  • RPG game 만들기

🚨 발생한 문제/에러

  • 문제/에러 1

    1. 문제/에러 정의

    2. 시도한 해결 방법

    3. 최종 해결 방법

    4. 새롭게 알게 된 점

    5. 다음에 비슷한 문제를 만난다면?

📝 코드 스니펫

// 오늘 배운 주요 코드
List<String> lines = file.readAsLinesSync();

📚 내일 학습할 내용

  • 과제 코드 리펙토링

💭 오늘의 회고

잘한 점 👍

  • 과제 마무리한 것

개선할 점 🔨

  • 과제 복습 및 문법 부족한 부분 복습하자

배운 점 💡

  • 여러 가지

✏️ 참고 자료

RPG 게임 완성하기

· 4 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

오늘은 RPG 게임 완성을 하는 데 시간을 많이 쏟았던 것 같다. 코드를 최대한 예쁘게 작성하려고 했지만 만들면 만들수록 점점 지저분해지는 내 코드를 볼 수 있었는데 다시 한번 코드를 보면서 기능별로 함수처리를 해서 예쁘게 만들어야 될 것 같다.

그래도 과제를 하면서 콘솔 입출력에 대해서도 익숙해지게 되고 클래스와 인스턴스의 개념에 대해서도 내가 모르는 부분에 대해서 확실히 알게 되었다. 강의를 들을 때에는 확실히 알고 있다고 생각했지만 역시나 내가 직접 짤려고 하니 required ,final , late 등 언제 무엇을 써야될 지 멘붕이 올 때가 있었다. 그리고 생성자도 다양한 생성방법이 있는데 거기서 내가 어떤 방법을 적용해서 클래스를 만들어야 할지 그런 부분에서도 내가 아직 개념이 부족하다는 것을 알게 되었다.

역시 만들어 보면서 부족한 부분이 많이 나오는 것 같다. 그리고 반복문을 자주 쓰다 보니까 break , continue 의 개념에 대해서도 확실히 알게 된 것 같고 함수, 클래스, 객체 지향 프로그래밍, 값 복사, 참조 복사 이 개념에 대해서 명확히 해서 포스팅을 해야겠다.

역시 내가 개념을 정리해 가면서 공부할 때 내 것이 되는 것 같다.

✍️ 주요 학습 내용

배운 내용

  • 파일출력
  • 정규식

새로 알게된 개념

파일 출력

String contents = '파일 내용';
var file = File('파일 저장 위치');
file.writeAsStringSync(contents);
// 파일 저장 완료!

정규식

RegExp nameRegulation = RegExp(r"^[ㄱ-ㅎ가-힣a-zA-Z]*$");
String text = "검사하고 싶은 문자열";
if(!nameRegulation.hasMatch(text)){
//문자열이 조건에 맞지 않을 때
}
  • 정규식 한글은 r”^[ㄱ-ㅎ가-힣]*$”
  • 정규식 영문은 r”^[a-zA-Z]*$”
  • 정규식 숫자는 r”^[0-9]*$”
  • hatMatch(문자열) 메서드를 통해서 조건일치여부 반환(True or False)

현재시간 얻기

var now = DateTime.now();
int year = now.year;
int month = now.month;
int day = now.day;

실습한 내용

  • RPG Game 만들기

🚨 발생한 문제/에러

없음

📝 코드 스니펫

// 오늘 배운 주요 코드
RegExp nameRegulation = RegExp(r"^[ㄱ-ㅎ가-힣0-9a-zA-Z]*$");
String text = 'Study hard';
if(!nameRegulation.hasMatch(text){
print('Study Again');
}

📚 내일 학습할 내용

  • Code refactoring

💭 오늘의 회고

잘한 점 👍

  • 과제 필수 기능 구현

개선할 점 🔨

  • 도전 기능 구현하기

배운 점 💡

  • 클래스 개념
  • 값 복사, 참조 복사

✏️ 참고 자료

콘솔 RPG 게임 필수 기능 만들기

· 2 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

  • 콘솔 RPG 게임 만들기

✍️ 주요 학습 내용

배운 내용

  • 랜덤으로 값을 뽑아내는 기능
  • 파일 입출력을 처리하는 기능

새로 알게된 개념

콘솔 입력

  • stdin.readLineSync()

콘솔 입력 받기 전에 안내문구 입력

  • stdout.write()

파일 관련

final file = File(’./gameStats/characters.text’);
final contents = file.readAsStringSync();
final stats = contents.split(',');

랜덤값 구하기

import 'dart:math';
int attackingPower = Random().nextInt(100) + 10

nextInt(100)

→ 0부터 99까지의 랜덤값을 출력

→ +를 사용해 최소값을 정할 수 있음

실습한 내용

  • 필수기능 구현

🚨 발생한 문제/에러

  • 아직까진 없음

📝 코드 스니펫

// 오늘 배운 주요 코드
int randomInt = Random().nextInt(100) + 10;

📚 내일 학습할 내용

  • 개인과제 도전 기능 구현

💭 오늘의 회고

잘한 점 👍

  • 음 .. 최선을 다한 것?

개선할 점 🔨

  • 시간관리

배운 점 💡

  • 파일 입출력

✏️ 참고 자료

비동기 프로그래밍

· 6 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

아침에 코딩

주어진 문자열 haystack과 needle이 있을 때, needle이 haystack 내에서 처음 나타나는 위치를 반환합니다. needle이 존재하지 않으면 -1을 반환합니다.

int strStr(String haystack, String needle) {
return haystack.indexOf(needle);
}

알게 된 점

  • String 에서 indexOf로 특정 String 이 들어가는 시작 인덱스를 알 수 있다는 것을 배웠다.
  • 그리고 해당 문자열이 없으면 -1 로 반환된다는 것을 배워서 간단한 문제였음.

✍️ 주요 학습 내용

배운 내용

  • 동기 프로그래밍
  • 비동기 프로그래밍

새로 알게된 개념

비동기 프로그래밍
  • 작업이 완료될 때까지 기다리지 않고, 미래의 특정 시점에 값을 반환해요.
  • 결과값이 나올 때까지 멈춰 있지 않고, 수행할 수 있는 다른 작업을 찾아서 수행해요
  • dart:async
    • Future , Stream 클래스를 통해 비동기 프로그래밍 지원
Future 클래스
  • 작업이 성공적으로 완료되었을 때 해당 결과값을 반환하고 실행을 종료

  • 하나의 작업에 대해 값이나 이벤트가 한번 발생하는 단일 비동기 작업에 사용

  • Future 에 있는 delayed() 라는 메서드에 대해 알아보고 갑시다 👀

    • Future.delayed(Duration(seconds: [지연 시간]));

      void main() {
      int seconds = 2;
      print('실행 시작 !');
      Future.delayed(Duration(seconds: seconds));
      print('실행 끝 !');
      }

      /*
      실행 시작 !
      실행 끝 !
      */
    • Future.delayed(Duration(seconds: [지연 시간]), () {[지연 시간 후의 동작]});

      void main() {
      int seconds = 2;
      print('실행 시작 !');
      Future.delayed(Duration(seconds: seconds), () {
      print('$seconds초 다 기다림 !');
      });
      print('실행 끝 !');
      }

      /*
      실행 시작 !
      실행 끝 !
      2초 다 기다림 !
      */

async ~ await

→ 비동기 프로그래밍을 동기 프로그래밍으로!

await 을 사용하려면 Future<void> 를 반환타입에 명시해 줘야 함

한계점

  • 하나의 작업당 결과값을 1번만 받을 수 있음
  • 하나의 작업에 결과값이 여러 번 나오는 경우가 있을 수 있기 때문에 Stream 이 등장
Stream 클래스
  • 실행을 종료해 주지 않으면 계속 실행됨

  • 비동기 연산의 결과값이 여러 번 반환되는 경우 그 값을 순차적으로 받기 위해 사용됨

  • 코드를 본격적으로 써보기 전에 몇 가지에 대해 알아보고 갑시다 👀

    • yield

      • 값을 방출하도록 하는 키워드
        Stream<String> emitNames() async* {
        yield '강미래';
        yield '강현재';
        yield '강과거';
        }
        Stream<String> emitNames(List<String> names) async* {
        for (var i = 0; i < names.length; i++) {
        yield '${i + 1}번째는 ${names[i]} ~';
        }
        }
      • 함수메서드 에서 사용하는 return 과 같은 개념이라고 보시면 돼요 🙂
    • listen()

      • 방출되는 소리를 듣고 있는다는 뜻으로 생각하면 돼요 🙂

      • yield 를 통해 방출되는 값을 받기 위해 사용하는 메서드

        Stream<String> emitNames() async* {
        yield '강미래';
        yield '강현재';
        yield '강과거';
        }

        void main() {
        int number = 1;

        emitNames().listen((name) {
        print('$number번째는 $name ~');
        number += 1;
        });
        }

        /*
        1번째는 강미래 ~
        2번째는 강현재 ~
        3번째는 강과거 ~
        */
        Stream<String> emitNames(List<String> names) async* {
        for (var i = 0; i < names.length; i++) {
        yield '${i + 1}번째는 ${names[i]} ~';
        }
        }

        void main() {
        List<String> names = ['강미래', '강현재', '강과거'];
        emitNames(names).listen((element) {
        print(element);
        });
        }

        /*
        1번째는 강미래 ~
        2번째는 강현재 ~
        3번째는 강과거 ~
        */
  • async* 이렇게 사용을 해줘야 함.

실습한 내용

  • 없음

🚨 발생한 문제/에러

  • 없음

📝 코드 스니펫

// 오늘 배운 주요 코드
Stream<int> emitNumbers(int first) async* {
for(var i = first; i >= 0 ; i--){
yield i;

await Future.delayed(Duration(seconds : 1));
}
}

📚 내일 학습할 내용

  • 개인 과제

💭 오늘의 회고

잘한 점 👍

  • 집중 공부

개선할 점 🔨

  • 나태함 이기기

배운 점 💡

  • Future 클래스
  • Stream 클래스

✏️ 참고 자료

라이브러리를 이용한 확장

· 9 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

아침에 코딩
* 문제
주어진 배열 nums에서 특정 값 val을 제거해야 합니다.
제거한 후의 배열은 배열의 처음 부분에 남겨두고, 배열의 길이를 반환해야 합니다.
배열에서 제거된 값은 결과에 포함되지 않아야 하며,
반환된 길이를 기준으로 원래 배열의 처음 부분에 남은 값이 올바른 결과로 여겨집니다.

* 조건
1. 0 <= nums.length <= 100
2. 0 <= nums[i] <= 50
3. 0 <= val <= 100
class Solution {
int removeElement(List<int> nums, int val) {
int k = 0; // val이 아닌 요소의 개수를 셀 포인터

for (int i = 0; i < nums.length; i++) {
if (nums[i] != val) {
nums[k] = nums[i]; // val이 아닌 요소를 k 위치에 배치
k++; // 다음 위치로 이동
}
}

return k; // val이 아닌 요소의 개수를 반환
}
}

void main() {
Solution solution = Solution();
print(solution.removeElement([3, 2, 2, 3], 3)); // 2
print(solution.removeElement([0, 1, 2, 2, 3, 0, 4, 2], 2)); // 5
}

알게 된 점

  • 특정 요소가 제거된 후의 배열까지 만들려고 했었는데 그게 아니라 제거된 후 배열의 길이만 구하면 되어서 간단하게 할 수 있었다.

google_fonts , image_picker 등 다양한 꿀 외부 라이브러리에 대해서 알게 됐다.

  • import '[라이브러리 이름]';
    import 'dart:html';
    import 'package:http/http.dart'
  • import '[파일 경로]';
    import 'src/my_utils.dart';

✍️ 주요 학습 내용

배운 내용

  • 라이브러리 개념
  • 라이브러리 특징
  • 라이브러리 종류

새로 알게된 개념

라이브러리 종류

Dart SDK 표준 라이브러리

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

  • 모든 플랫폼에서 사용 가능

    • dart:core
    • dart:async
    • dart:collection
    • dart:convert
      • Json, UTF-8
      • 인코더, 디코더 제공
    • dart:developer
    • dart:math
  • Native Platform에서 사용 가능

    • Native platform 은 타겟이 Mobile, Desktop 이라고 했던 것 기억하시죠 ~?
    • dart:ffi
      • DartC API 를 사용할 수 있도록 하는 기능을 제공해요.
    • dart:io
      • 파일, 소켓, HTTP, 기타 입출력 등의 기능을 제공해요.
  • Web platform에서 사용 가능

    • 참고로, Web platformJavaScript 로 컴파일되는 코드랍니다 !
    • package:web
      • 가벼운 브라우저 API 와 연결하는 기능을 제공해요.
    • dart:js_interop
      • JavaScript 와 브라우저 API 를 상호운용할 수 있는 기능을 제공해요.
    • dart:html
      • HTML 요소들과 Web 기반 응용 프로그램 리소스들을 제공해요.

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

  • Pub.dev 에서 다양한 외부 라이브러리를 쉽게 찾아서 사용할 수 있어요 🤩
  • cupertino_icons
    • FlutterCupertino 위젯에 쓰이는 기본 아이콘 에셋을 제공해요.
  • intl
    • 번역, 날짜 포맷팅, 숫자 포맷팅 등 국제화와 현지화 기능을 제공해요.
  • shared_preferences
    • 간단한 데이터를 다루는 기능을 제공해요.
    • iOSmacOS 에서 사용하는 NSUserDefaults, Android 에서 사용하는 SharedPreferences 와 같은 역할을 해요.
  • url_launcher
    • URL 을 다루는 기능을 제공해요.
  • image_picker
    • iOSAndroid 에서 사진 다루는 기능을 제공해요.
    • 예시로 카메라로 사진 찍는 기능이랑 앨범에서 사진 선택하는 기능이 있어요 !
  • firebase_core
    • Firebase 와 연동하는 작업할 때 필요한 핵심 기능을 제공해요.
  • firebase_auth
    • Firebase 인증 API 를 사용하기 위한 기능을 제공해요.
  • google_fonts
    • fonts.google.com 에서 제공하는 폰트를 사용하기 위한 기능을 제공해요.
  • permission_handler
    • iOSAndroid 의 권한을 다루는 기능을 제공해요.
  • custom_lint
    • Lint 규칙을 쉽게 적용할 수 있도록 해주는 기능을 제공해요.
    • Lint ?
      • 어떤 친구인가요 ?
        • 오류가 발생할 수 있는 코드, 코드 스타일에 어긋난 코드, 비효율적이거나 불필요한 코드 등을 찾아내서 경고를 띄워주는 도구
      • 왜 사용하나요 ? 사용하면 뭐가 좋은가요 ?
        • 코드의 품질을 개선할 수 있어요.
        • 코드의 가독성을 향상시킬 수 있어요.
        • 유지보수성 높은 프로젝트를 만들 수 있어요.
  • flutter_svg
    • SVG 를 렌더링하기 위한 기능을 제공해요.
  • cached_network_image
    • 네트워크를 통해 사진을 받아오고, 캐싱하는 기능을 제공해요.
  • flutter_local_notifications
    • 로컬 알림을 다루는 기능 (ex. 알림 표시, 알림 예약) 을 제공해요.
  • path_provider
    • 파일 시스템을 사용하기 위한 기능을 제공해요.
  • geolocator
    • iOSAndroid 에서 위치를 다루기 위한 기능을 제공해요.
  • dio
    • HTTP 네트워크 사용을 위한 기능을 제공해요.
라이브러리 특징
  • 어떤 특징이 있나요 ?
    • as 를 통해 라이브러리에 별칭을 부여할 수 있어요.
      import 'package:http/http.dart' as http;
    • show 를 통해 라이브러리에서 필요한 부분만 선택적으로 가져올 수 있어요.
      import 'package:lib1/lib1.dart' show foo;
    • hide 를 통해 라이브러리의 특정 부분을 제외하고 가져올 수 있어요.
      import 'package:lib2/lib2.dart' hide foo;
    • deferred as 를 통해 라이브러리가 필요한 시점에 로드되도록 할 수 있어요.
      • 지연 로딩 이라고도 불러요 🙂
      • 왜 사용하나요 ? 사용하면 뭐가 좋은가요 ?
        • 필요한 시점에 라이브러리가 로드되기 때문에 초기화하는 시간이 줄어들고, 성능이 향상돼요 👍🏼
      • 어떤 특징이 있나요 ?
        • 모든 플랫폼에서 지원하는 것은 아니고, Web platform 에서만 지원해요 🥹
      • 어떻게 생겼나요 ?
        • 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();
          }
        • 저는 loadLibrary() 를 정의한 적이 없는데, 어떻게 된건가요 ?
          • deferred as [식별자] 를 통해 식별자를 만들어 주는 순간, 그 식별자에 loadLibrary() 가 자동으로 정의된답니다 🤩

실습한 내용

  • 없음

🚨 발생한 문제/에러

  • 없음

📝 코드 스니펫

// 오늘 배운 주요 코드
import 'dart:io';

📚 내일 학습할 내용

  • 개인과제 준비

💭 오늘의 회고

잘한 점 👍

  • 음..

개선할 점 🔨

  • 계획 세우기

배운 점 💡

  • 라이브러리

✏️ 참고 자료

에러 헨들링

· 4 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

오늘의 코딩

정렬된 배열에서 중복 제거

class Solution {
int removeDuplicates(List<int> nums) {
if(nums.isEmpty){return 0;}
int k = 1;

for(int i = 1; i < nums.length ; i++){
if(nums[i] != nums[k-1]){
nums[k] = nums[i];
k++;
}
}
return k;

}
}

문제점

  • 숫자 배열에서 조건에 숫자가 뒤로 갈수록 감소하지 않는다는 것을 파악하지 못함
  • 중복되는 것을 제거해서 ‘_’로 바꿔야 한다는 것을 잘못 이해해서 헛고생을 조금 했다. 매번 문제를 잘 이해하지 못하는 부분이 있는 것 같다.

  • 예외와 오류의 차이
    • 예외는 프로그래밍 로직 문제, 오류는 주로 시스템 문제(메모리 부족)

✍️ 주요 학습 내용

배운 내용

  • 예외 클래스
  • 오류 클래스
  • 예외와 오류의 차이
  • 예외처리

새로 알게된 개념

예외

FormatException

  • 다른 형태의 데이터가 들어갔을 때 예외 발생

IOException

  • 입출력 관련 오류

OSError

  • 운영체제 관련 에러

TimoutException

  • 비동기 처리시 시간이 오버할 때 나오는 에러

throw → 의도적으로 예외를 던지는 것.


예외에 사용하는 키워드

try 의 코드 블록 중에 예외가 발생하면 try 의 코드 블록에 있는 뒷 코드들은 실행되지 않음 → catch 문으로 넘어감

catch (e)

e → 예외객체가 매개변수로 들어옴

on

  • 단독으로 쓸 수 없음
  • 특정 타입의 예외를 다룸
try{

}on FormatException catch(e){}

finally

  • 예외 발생 여부에 상관없이 실행할 코드를 넣는 부분
try{
}catch(e){
}finally{
print('예외 처리 끝!')
}
오류(Error)
  • 오류를 발생하면 프로그램이 종료됨

AssertionError

  • assert(조건문)false 면 오류 발생

RangeError

  • 리스트 길이보다 더 큰 인덱스를 사용할 때
    • RangeError 를 상속받은 IndexError 를 발생

OutOfMemoryError

  • 메모리 부족

StackOverflowError

  • 메모리 영역 중 하나인 스택 영역이 가능한 범위를 넘어가는 현상
  • 스택은 지역 변수나 매개변수를 담는 공간

StateError

  • 객체가 현재 상태로는 특정 동작이 불가능할 때
  • ex) null.first()

UnimplementedError

  • 정의되지 않은 메서드나 기능을 호출했을 때

UnsupportedError

  • 호출은 하는데 동작은 하지 않음

실습한 내용

  • 없음

🚨 발생한 문제/에러

  • 없음

📝 코드 스니펫

// 오늘 배운 주요 코드
try{
}catch(e){
}finally{
}

📚 내일 학습할 내용

  • 종합반 강의 복습

💭 오늘의 회고

잘한 점 👍

  • 목표를 끝까지 지키려고 한 점

개선할 점 🔨

  • 완벽한 상태에서 과제를 하려고 하기보다 미리 시작하고 과제를 먼저 파악하는 게 중요한 것 같음

배운 점 💡

  • 예외를 예측하는 게 쉽지 않은 것 같음

✏️ 참고 자료

쇼핑몰 콘솔 프로그램 트러블 슈팅

· 5 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

오늘은 개인 과제로 - 콘솔로 쇼핑몰 기능을 하는 프로그램을 만드는 것이었다. 간단하게 생각해서 여유부리다가 마지막에 시간에 쫓겨서 도전 기능은 거의 못하고 제출하게 되었다.

나는 사용자가 입력할 수 있는 모든 예외 상황에 대처할 수 있는 프로그램을 만들기 위해서 여러 가지 신경을 썼었는데 해설강의를 들으니까 기본적인 예외만 처리하고 나머지는 프리하게 하는 것을 보면서 내가 너무 어렵게 했나 그런 생각도 들었다. 그래도 확실히 이런 여러 가지 과제들을 하면서 복잡한 로직?을 짜보는 게 중요한 것 같다.

아무래도 코딩을 하다 보면 자기가 익숙한 문법, 코드만을 가지고 계속해서 코딩을 하게 되는데 알고리즘 문제 등을 풀면서 내가 익숙하지 않았던 문법 요소들도 사용을 하게 되고 이 문법이 이렇게 쓰이는구나 라고 깨닫게 되는 것 같다.

✍️ 주요 학습 내용

배운 내용

  • 콘솔 프로그램 제작

새로 알게된 개념

쇼핑몰 과제

tryParse()

  • 성공시 정수 변환 → 실패시 null 반환
  • ?? 연산자로 0을 반환 처리 가능
트러블 슈팅1 : 공백 제거
void addToCart(String productName, int number) {
Product addedProduct =
products.where((product) {
print('product.name: ${product.name} productName: $productName');
print('== ${product.name == productName}');
return product.name == productName;
}).first;
cart.add(addedProduct);
totalPrice += addedProduct.price * number;
print(
'----------------------------------------------------------------------------------------',
);
print('장바구니에 상품이 담겼어요!');
}

// error message
수량 : 2
Unhandled exception:
Bad state: No element
#0 Iterable.first (dart:core/iterable.dart:645:7)
#1 ShoppingMall.addToCart (file:///Users/junseokyang/Desktop/project/flutter/assignment/consoleShoppingMall/consoleShoppingMall.dart:29:66)
#2 main (file:///Users/junseokyang/Desktop/project/flutter/assignment/consoleShoppingMall/consoleShoppingMall.dart:139:24)
#3 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:315:19)
#4 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:194:12)
product.name: 셔츠 productName: 반바지
== false
product.name: 원피스 productName: 반바지
== false
product.name: 반팔티 productName: 반바지
== false
product.name: 반바지 productName: 반바지
== false
  • 장바구니에 상품을 담기 위해서 수량을 입력하면 에러가 나왔다.
  • 원인은 입력한 상품명과 동일한 상품명을 갖고 있는 요소들을 배열로 만들어야 되는데 동일한 상품명이 없어서 빈 배열을 where 을 통해서 반환하게 되고 거기서 first 를 사용해서 첫 번째 요소를 받으려고 하니까 오류가 생겼다.
  • 분명히 상품명을 동일하게 입력했는데도 오류가 나오니까 where 문에 print 를 추가해서 값을 비교했다.
  • 그랬더니 입력을 할 때 양말[공백] 이런 식으로 뒤나 앞에 공백이 있으면 양말과는 일치하지 않는다고 나와서 where 에서 빈 배열을 반환하게 되는 오류였다.
  • 그래서 addToCart() 매개변수로 보내기 전에 productName.trim() 이렇게 trim() 을 사용해 양 옆 공백을 제거해 줌으로써 문제가 해결이 되었다.
해설

stdin.readLineSync();String? 을 반환함

import ‘dart:io’;

  • 입출력을 담당하는 라이브러리
  • std → standard의 준말
  • in → input

stdin.readLineSync(); : 입력요청

stdout.write(’상품명 : ‘); 글자 출력

No Element → Exception 처리

try & catch

switch

default: → 옵션에 없는 값이 나왔을 때

List<Map> cart = [];
cart.add({"product" : currentProduct, "count" : count})
cartItem['product'].name

실습한 내용

  • 콘솔 프로그램 제작

🚨 발생한 문제/에러

  • 위에서 정리를 함. 공백 문제

📝 코드 스니펫

// 오늘 배운 주요 코드
string.trim()

📚 내일 학습할 내용

  • 종합반 복습

💭 오늘의 회고

잘한 점 👍

  • 과제 마무리

개선할 점 🔨

  • 미리미리 과제를 시작할걸..

배운 점 💡

  • dart의 io 입출력에 대해서 배움

✏️ 참고 자료

객체 지향 프로그래밍 배우기

· 20 min read
Junseok Yang
Football Loving Programmer

📚 오늘의 학습 내용

오늘의 코딩

공통된 접두사를 찾아서 반환해라

// 강사님 풀이법
String longestCommonPrefix(List<String> strs){
if(strs.isEmpty){
return ""
}
String prefix = strs.first;

for(var i = 1; i < strs.length; i++){
String str = strs[i];
while(!str.startsWith(prefix)){
prefix = prefix.substring(0, prefix.length - 1);
if(prefix.isEmpty){
return "";
}
}
}
return prefix;

}
// 내 풀이법 str.codeUnits
class Solution {
String longestCommonPrefix(List<String> strs) {
if (strs.isEmpty) {
return solutionStr;
}

String prefix = "";
String solutionStr = "";
List<String> firstStr = strs[0].split("");
for(int i = 0; i < firstStr.length; i++){
prefix = firstStr[i];

if(strs.every((samePrefix) => samePrefix.startsWith(prefix, i))){
solutionStr += prefix;
}else{
break;
}
}
return solutionStr;
}
}

알게 된 점

  1. 빈 배열에 대한 예외 처리
    1. 빈 List가 왔을 때 에러가 나오기 때문에 처음에 isEmpty 로 예외처리해 주기
  2. subString([시작인덱스], [길이])
    1. 문자열에서 원하는 부분을 출력할 때
  • 클래스의 개념에 대해서 배웠다. 속성에서 클래스 변수, 지역 변수, 정적 변수가 있었는데 정적 변수에 대한 개념이 없었는데 정적 변수에 대해서 확실히 배울 수 있었다.
  • 지금까지 메서드와 함수를 같은 개념으로 생각해 왔는데 그렇지 않다는 것을 알게 되었다. 메서드는 클레스에 종속되어 있는 것이고 함수는 클래스와 관계없이 있는 것을 함수라고 하는데 그 차이점을 알게 되었다.
  • 또한 정적 메서드도 클래스에 종속되어 있어서 클래스를 통해서 호출가능한 메서드라는 것을 배울 수 있었다.
  • 클래스 변수인지 객체 변수인지 구분하는 게 중요하다는 것을 알 수 있었음.
  • 클래스 메서드는 객체 변수를 사용할 수 없음!
  • 제네릭 클래스를 활용해서 클래스명 뒤에 <T> 를 사용해서 제네릭 클래스임을 명시해 주고 타입에 T 를 사용해서 유동적인 타입을 줄 수 있음.
  • 부모 클래스자식 클래스 에게 자신의 모든 속성메서드상속 해요.
  • final 을 사용해서 하나의 클래스 로부터 자식 클래스 를 만들 수 없도록 할 수 있음
    • final class [class 명]{}

✍️ 주요 학습 내용

배운 내용

  • 클래스
  • 클래스의 정적 변수
  • 메서드와 함수
  • 제네릭 클래스

새로 알게된 개념

클래스

class [클래스 이름] { … }

class Person {
String name;
int age;

Person(this.name, this.age);

void introduce() {
print('안녕 ? 나는 $age살 $name !');
}
}

속성 (attribute)

  1. 인스턴스 변수(Instance Variable)

    1. 객체에 속해 있는 변수

      class Person {
      String name = '강미래';
      int age = 25;
      }
    2. this 를 통해 접근 가능(this 객체를 의미)

    3. 객체가 존재하는 동안 계속 메모리 상에 존재

  2. 지역 변수 (Local Variable)

    1. 특정 코드 블록 안에 선언된 변수

      class Person {
      String name = '강미래';

      void sayName() {
      String nameSentence = '내 이름은 $name !';
      print(nameSentence);
      }
      }
    2. 변수가 선언된 코드 블록의 실행이 끝나면 메모리 상에서 사라짐

  3. 정적 변수 (Static Variable)

    • 클래스 변수라고 불림
    • 객체에 종속되지 않고 클래스 자체에 속하는 변수
    class Circle {
    static double pi = 3.14159;
    }
    • 클래스 이름을 통해 접근 가능
    class Circle {
    static double pi = 3.14159;
    double radius = 0;
    }

    void main() {
    print(Circle.pi); // 3.14159
    print(Circle.radius); // Error: Member not found: 'radius'.
    }
    • 객체를 통해 접근할 수 없음
    class Circle {
    static double pi = 3.14159;
    double radius = 0;
    }

    void main() {
    Circle circle = Circle();
    print(circle.radius); // 0
    print(circle.pi); // 오류 발생
    }
    • this 를 통해 접근할 수 없음
    • 모든 객체가 서로 값을 공유함
branch 관리

mileStone에서 이슈를 만들어서 이슈명에 맞게 브랜치 명에 맞게 함

pull request 남기기 전에 rebase가 깔끔한 것 같음

메서드
  • 메서드 (Method)
    • 어떤 친구인가요 ?
      • 객체동작 을 정의하는 함수
      • 속성 을 변경하거나 객체 를 가지고 특정 작업을 수행해요.
      • 여기서 잠깐 ! 🧐 함수 (Function) 랑 메서드 (Method) 는 서로 같은 개념일까요 ?
        • 엄밀히 말하면, 완전히 같지는 않아요 !
          • 두 친구 모두 동작을 정의한다는 점에서는 같지만,
          • 메서드클래스 에 의존하고, 함수클래스 에 의존하지 않는다는 차이가 있어요.
            void function() {
            print('저는 함수입니다 !');
            }

            class Class {
            void method() {
            print('저는 메서드입니다 !');
            }
            }

            void main() {
            function(); // 저는 함수입니다 !

            Class object = Class();
            object.method(); // 저는 메서드입니다 !
            }
    • 종류에는 무엇이 있나요 ?
      • 인스턴스 메서드 (Instance Method)
        • 어떤 친구인가요 ?
          • 객체 에 속해 있는 메서드
            class Person {
            String name = '강미래';
            int age = 25;

            void introduce() {
            print('안녕 ? 나는 $age살 $name !');
            }
            }
        • 어떤 특징이 있나요 ?
          • this 를 통해 접근할 수 있어요.
            class Person {
            String name = '강미래';
            int age = 25;

            void printName() {
            print(name);
            }

            void printNameAndAge() {
            this.printName();
            print(age);
            }
            }
          • 클래스 의 모든 곳에서 접근할 수 있어요.
            class Person {
            String name = '강미래';
            int age = 25;

            void printName() {
            print(name);
            }

            void printNameAgain() {
            printName();
            }
            }
      • 정적 메서드 (Static Method)
        • 클래스 메서드 라고도 불러요.
        • 어떤 친구인가요 ?
          • 객체 에 종속되지 않고, 클래스 자체에 속하는 메서드
            class Circle {
            static double pi = 3.14159;

            static void printPi() {
            print('원주율은 $pi !');
            }
            }
        • 어떤 특징이 있나요 ?
          • 클래스 이름을 통해 호출해요.
            • 그래서 객체 를 생성하지 않고도 메서드 를 호출할 수 있답니다 👍🏼
              class Circle {
              static double pi = 3.14159;
              double radius = 0;

              static void printPi() {
              print(pi);
              }

              void printRadius() {
              print(radius);
              }
              }

              void main() {
              Circle.printPi(); // 3.14159
              Circle.printRadius(); // 오류 발생
              }
          • 객체 를 통해 호출할 수 없어요.
            class Circle {
            static double pi = 3.14159;
            double radius = 0;

            static void printPi() {
            print(pi);
            }

            void printRadius() {
            print(radius);
            }
            }

            void main() {
            Circle circle = Circle();
            circle.radius = 5;
            circle.printRadius(); // 5
            circle.printPi(); // 오류 발생
            }
          • this 를 통해 호출할 수 없어요.
            class Circle {
            static double pi = 3.14159;
            double radius = 0;

            static void printPi() {
            print(pi);
            }

            void printPiAgain() {
            this.printPi(); // 오류 발생
            }
            }
          • 코드 블록에서 인스턴스 변수 를 사용할 수 없어요.
            class Circle {
            double pi = 3.14159;
            double radius = 0;

            static void printPi() {
            print(pi); // 오류 발생
            }
            }
            • 그럼 인스턴스 메서드 의 코드 블록에서 정적 변수 를 쓸 수 있을까요 ?
              • Yes !! 완 ~ 전 ~ 가능 🎶
                class Circle {
                static double pi = 3.14159;
                double radius = 0;

                void printArea() {
                print(pi * radius * radius);
                }
                }
          • 객체마다 개별적으로 동작하지 않고, 모두 동일하게 동작한다.
  • 속성메서드클래스 안에 있는 요소라서 클래스멤버 (Member) 라고 부르기도 해요 !
생성자
  • 생성자 (Constructor) 라는 친구인데요 !
    • 어떤 친구인가요 ?
      • 객체 를 생성하고, 초기화하기 위해 사용하는 특수한 메서드
    • 종류에는 어떤 것이 있나요 ?
      • 기본 생성자 (Default Constructor)
        • 어떤 친구인가요 ?
          • 매개변수 를 갖지 않는 생성자
        • 어떻게 생겼나요 ?
          • [클래스 이름]();
            class Car {
            Car();
            }
        • 어떤 특징이 있나요 ?
          • 자동으로 정의되기 때문에 클래스 에 따로 명시하지 않아도 돼요.
            class Car {

            }

            void main() {
            Car car = Car();
            }
            class Car {
            Car();
            }

            void main() {
            Car car = Car();
            }
            class Car {

            }

            void main() {
            Car car = new Car();
            }
          • 인스턴스 변수 들이 모두 초기화되어 있는 상태여야 해요.
            class Car {
            String name = '';
            List<String> models = [];

            Car();
            }
            class Car {
            String name; // Error: Field 'name' should be initialized because its type 'String' doesn't allow null.
            List<String> models; // Error: Field 'models' should be initialized because its type 'List<String>' doesn't allow null.

            Car();
            }
      • 매개변수 생성자 (Parameterized Constructor)
        • 어떤 친구인가요 ?
          • 매개변수 를 갖는 생성자
          • 매개변수 를 통해 외부에서 인스턴스 변수 들의 초기값을 설정해요.
        • 어떻게 생겼나요 ?
          • [클래스 이름](this.변수);
            class Car {
            String name;
            List<String> models;

            Car(this.name, this.models);
            }
          • [클래스 이름]([타입] [매개변수 이름]) : this.변수;
            class Car {
            String name;
            List<String> models;

            Car(String name, List<String> models)
            : this.name = name,
            this.models = models;
            }
          • [클래스 이름]([타입] [매개변수 이름]) { this.변수; }
            class Car {
            String name = '';
            List<String> models = [];

            Car(String name, List<String> models) {
            this.name = name;
            this.models = models;
            }
            }
        • 어떤 특징이 있나요 ?
          • 객체 생성할 때 매개변수 를 넣지 않으면 오류가 나요 🚨
            class Car {
            String name;
            List<String> models;

            Car(this.name, this.models);
            }

            void main() {
            Car car = Car(); // Error: Too few positional arguments: 2 required, 0 given.
            }
      • 네임드 생성자 (Named Constructor)
        • 어떤 친구인가요 ?
          • 클래스 메서드 와 같은 형식으로 호출하는 생성자
        • 어떻게 생겼나요 ?
          • [클래스 이름].[메서드 이름]([타입] [매개변수 이름]) : this.변수;
            class Car {
            String name;
            List<String> models;

            Car.fromList(List values)
            : this.name = values[0],
            this.models = values[1];
            }
        • 어떻게 사용하나요 ?
          class Car {
          String name;
          List<String> models;

          Car.fromList(List values)
          : this.name = values[0],
          this.models = values[1];

          void speakName() {
          print('저희는 $name 입니다 !');
          }

          void speakModels() {
          print('$models 모델을 가지고 있습니다 !');
          }
          }

          void main() {
          Car car = Car.fromList([
          'BMW',
          ['320i', '340i', 'M3']
          ]);
          car.speakName(); // 저희는 BMW 입니다 !
          car.speakModels(); // [320i, 340i, M3] 모델을 가지고 있습니다 !
          }
        • 어떤 특징이 있나요 ?
          • 클래스 에 있는 변수타입 이 맞지 않는 값을 넣으면 오류가 나요 🚨
            class Car {
            String name;
            List<String> models;

            Car.fromList(List values)
            : this.name = values[0],
            this.models = values[1];
            }

            void main() {
            Car car = Car.fromList([
            'BMW',
            [1, 2, 3]
            ]); // TypeError: Instance of 'JSArray<int>': type 'List<int>' is not a subtype of type 'List<String>'
            }
    • 어떤 특징이 있나요 ?
      • 클래스 와 이름이 같아요.
      • 반환값 이 없기 때문에 void 타입이에요.
      • 클래스 를 통해 객체 가 생성될 때 자동으로 호출돼요.
      • 생성할 수 있는 객체 의 수에는 제한이 없어요.
        class Person {
        String name;
        int age;

        Person(this.name, this.age);
        }

        void main() {
        Person paul = Person('Paul', 25);
        Person mark = Person('Mark', 30);
        }
      • 생성한 객체 들은 서로 같지 않은 독립된 개체예요.
        class Person {
        String name;
        int age;

        Person(this.name, this.age);
        }

        void main() {
        Person paul1 = Person('Paul', 25);
        Person paul2 = Person('Paul', 25);
        print(paul1 == paul2); // false
        }
제네릭 클래스
  • 제네릭 클래스 (Generic Class) ?
    • 어떻게 생겼나요 ?
      • [클래스 이름]<타입 파라미터>
        class Box<T> {
        T value;

        Box(this.value);

        T getValue() {
        return value;
        }
        }
    • 왜 사용하나요 ?
      • 제네릭 함수 와 마찬가지로 특정 타입에 의존하지 않고, 여러 타입에 대해 동일한 코드를 적용할 수 있어서 재사용성 높은 코드를 짤 수 있겠죠 👍🏼

        class IntBox {
        int value;

        IntBox(this.value);

        int getValue() {
        return value;
        }
        }

        class StringBox {
        String value;

        StringBox(this.value);

        String getValue() {
        return value;
        }
        }

        void main() {
        var intBox = IntBox(10);
        print(intBox.getValue()); // 10

        var stringBox = StringBox('Hello');
        print(stringBox.getValue()); // Hello
        }
        class Box<T> {
        T value;

        Box(this.value);

        T getValue() {
        return value;
        }
        }

        void main() {
        var intBox = Box<int>(10);
        print(intBox.getValue()); // 10

        var stringBox = Box<String>('Hello');
        print(stringBox.getValue()); // Hello
        }
상속(Inheritance)

상속 (Inheritance)

  • 어떤 친구인가요 ?
    • 기존 클래스의 기능을 확장하여 새로운 클래스를 만드는 것
    • 하나의 클래스 가 다른 클래스속성메서드 를 물려받는 것
      • 물려주는 클래스부모 클래스 (Parent Class, Superclass), 물려받는 클래스자식 클래스 (Child Class, Subclass) 라고도 불러요.
  • 어떻게 생겼나요 ?
    • class [자식 클래스 이름] extends [부모 클래스 이름] { … }
      class Person {
      void eat() {
      print('냠냠 !');
      }
      }

      class Student extends Person {
      void study() {
      print('열공 !');
      }
      }
  • 어떤 특징이 있나요 ?
    • 부모 클래스자식 클래스 에게 자신의 모든 속성메서드상속 해요.
      class Person {
      String name = '';

      void eat() {
      print('냠냠 !');
      }
      }

      class Student extends Person {
      void study() {
      print('열공 !');
      }
      }

      void main() {
      Student student = Student();
      student.name = '강미래';
      student.eat(); // 냠냠 !
      student.study(); // 열공 !
      }
    • 부모 클래스자식 클래스 에 있는 멤버 (속성, 메서드) 를 사용할 수 없어요.
      class Person {
      void eat() {
      print('냠냠 !');
      }
      }

      class Student extends Person {
      void study() {
      print('열공 !');
      }
      }

      void main() {
      Person person = Person();
      person.study(); // Error: The method 'study' isn't defined for the class 'Person'.
      }
    • super 를 통해 자식 클래스부모 클래스속성메서드 를 사용할 수 있어요.
      class Person {
      String name = '강미래';

      void eat() {
      print('냠냠 !');
      }
      }

      class Student extends Person {
      void eatAndIntroduce() {
      super.eat();
      print('맛있게 먹는 ${super.name} ㅋㅋ');
      }
      }

      void main() {
      Student student = Student();
      student.eatAndIntroduce();
      }

      /*
      냠냠 !
      맛있게 먹는 강미래 ㅋㅋ
      */
    • 자식 클래스상속 받은 속성메서드재정의 (Overriding) 하거나 기능을 확장할 수 있어요.
      • 재정의 (Overriding) ?
        • 어떤 친구인가요 ?
          • 자식 클래스부모 클래스 로부터 상속 받은 속성메서드 를 그대로 사용하지 않고, 덮어 씌우는 것을 의미해요.
        • 언제 사용하나요 ?
          • 부모 클래스 에 정의되어 있는 속성 이나 메서드 가 마음에 안 들어서 새로 정의하고 싶을 때 사용해요 🤣
        • 어떻게 생겼나요 ?
          • @override [변수 이름] = [값];
            class Person {
            String name = '강미래';

            void eat() {
            print('냠냠 !');
            }
            }

            class Student extends Person {
            @override
            String name = '여러분';

            void study() {
            print('열공하는 $name !');
            }
            }

            void main() {
            Student student = Student();
            student.study(); // 열공하는 여러분 !
            }
          • @override [반환 타입] [함수 이름]() { … }
            class Person {
            void eat() {
            print('냠냠 !');
            }
            }

            class Student extends Person {
            @override
            void eat() {
            print('쩝쩝 !');
            }
            }

            void main() {
            Student student = Student();
            student.eat(); // 쩝쩝 !
            }
      • 재정의 는 알겠는데요 ~ 기능 확장은 어떻게 해요 ? 🤔
        class Person {
        void eat() {
        print('냠냠 !');
        }
        }

        class Student extends Person {
        @override
        void eat() {
        super.eat();
        print('쩝쩝 !');
        }
        }

        void main() {
        Student student = Student();
        student.eat();
        }

        /*
        냠냠 !
        쩝쩝 !
        */
  • 왜 사용하나요 ?
    • 공통적인 속성메서드부모 클래스 에 정의하고, 공통되지 않는 요소들만 따로 자식 클래스 에 정의해서 중복된 코드를 줄이고, 코드의 재사용성을 높일 수 있어요 👍🏼
  • 근데요 .. 어떤 클래스상속 당하지 (?) 않게 하고 싶을 수도 있잖아요 😅
    • 그 경우에는 final 을 사용하면 돼요 !
    • final ?
      • 어떤 친구인가요 ?
        • 하나의 클래스 로부터 자식 클래스 를 만들 수 없도록 하는 것
        • 상속 받을 수 없도록 만드는 키워드라고 생각하면 돼요 🙂
      • 어떻게 생겼나요 ?
        • final class [클래스 이름] { … }
          final class Person {
          void eat() {
          print('냠냠 !');
          }
          }

          class Student extends Person {
          // Error: The type 'Student' must be 'base', 'final' or 'sealed' because the supertype 'Person' is 'final'.
          }

실습한 내용

  • 쇼핑몰 콘솔 프로그램 제작
    • 다음 글에 포스팅할 예정🙂

🚨 발생한 문제/에러

  • 없음

📝 코드 스니펫

// 오늘 배운 주요 코드
final class NoChildClass{}

📚 내일 학습할 내용

  • 예외처리
  • 라이브러리

💭 오늘의 회고

잘한 점 👍

  • 강의에 집중할 수 있었음

개선할 점 🔨

  • 시간관리 조금 더 디테일하게 하면 좋을듯

배운 점 💡

  • 클래스 개념
  • 메서드와 함수의 차이
  • 상속
  • 객체지향 프로그래밍

✏️ 참고 자료