반응형

다트는 동기/비동기 프로그래밍을 지원한다.

동기 : 요청을 하고 나서 응답이 올 때까지 기다렸다가 응답.

비동기 : 요청을 하고 나서 응답을 받지 않아도 다음 코드를 진행. 추후에 응답이 오면 처리.

 

Future

- Future 클래스 : 미래에 제너릭으로 값을 받아옴.

// 일정 시간 후 콜백 함수 실행.
// Future.delayed

void main() {
  print("실행 시작");
  Future.delayed(Duration(seconds: 3), (){
    print('3초 후 실행합니다.');
  });
  print("실행 완료?");
}

// 실행 결과(비동기로 동작)
실행 시작
실행 완료?
3초 후 실행합니다.

 

async, await

- 코드를 순서대로 실행시키기 위해 사용

void main() {
  addNumbers(1, 1);
}

// async 키워드는 함수 매개변수 정의와 바디 사이에 입력.
void addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  // await는 대기하고 싶은 비동기 함수 앞에 입력.
  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

// 실행 결과
1 + 1 계산 시작!
1 + 1 = 2
1 + 1 코드 실행 끝

 

비동기적으로 동작하는 지 확인

void main() {
  addNumbers(1, 1);
  addNumbers(2, 2);
}

Future<void> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

// 실행 결과
1 + 1 계산 시작!
2 + 2 계산 시작!
1 + 1 = 2
1 + 1 코드 실행 끝
2 + 2 = 4
2 + 2 코드 실행 끝

 

두 함수를 순차적으로 실행하고 싶다면...

// main 함수에 async, await 사용.
void main() async {
  await addNumbers(1, 1);
  await addNumbers(2, 2);
}

Future<void> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

// 실행 결과
1 + 1 계산 시작!
1 + 1 = 2
1 + 1 코드 실행 끝
2 + 2 계산 시작!
2 + 2 = 4
2 + 2 코드 실행 끝

 

결과 값을 비동기로 리턴 받고 싶다면...

void main() async {
  final result = await addNumbers(1, 1);
  print('결과값 $result');  // 일반 함수와 동일하게 반환값을 받을 수 있음
  final result2 = await addNumbers(2, 2);
  print('결과값 $result2');
}

Future<int> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');

  return number1 + number2;
}

//
1 + 1 계산 시작!
1 + 1 = 2
1 + 1 코드 실행 끝
결과값 2
2 + 2 계산 시작!
2 + 2 = 4
2 + 2 코드 실행 끝
결과값 4

 

 

Stream

- Future 는 결과값을 한번 리턴.

- 지속적으로 리턴받고 싶을 때는 Stream 을 사용.

- Stream 은 한번 Listen 하면 지속적으로 값을 받아온다.

import 'dart:async';

void main() {
  final controller = StreamController();  // StreamController 선언
  final stream = controller.stream;  // Stream 가져오기

  // Stream에 listen() 함수를 실행하면 값이 주입될 때마다 콜백 함수를 실행
  final streamListener1 = stream.listen((val) {
    print(val);
  });

  // Stream에 값을 주입할 때는 sink.add() 함수를 실행
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
  controller.sink.add(4);
}

// 실행 결과
1
2
3
4

 

Broadcasting

- Stream 을 여러번 Listen 하기

import 'dart:async';

void main() {
  final controller = StreamController();

  // 여러 번 listen할 수 있는 Broadcast Stream 객체 생성
  final stream = controller.stream.asBroadcastStream();

  // listen() 함수
  final streamListener1 = stream.listen((val) {
    print('listening 1');
    print(val);
  });

  // listen() 함수 추갸.
  final streamListener2 = stream.listen((val) {
    print('listening 2');
    print(val);
  });

  // add()를 실행할 때마다 listen()하는 모든 콜백 함수에 값이 주입
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);

}

// 실행 결과.
listening 1
1
listening 2
1
listening 1
2
listening 2
2
listening 1
3
listening 2
3

 

함수로 Stream 반환하기

- 이건 잘 모르겠음. --;;

import 'dart:async';

// Stream을 반환하는 함수는 async*로 선언합니다.
Stream<String> calculate() async* {
  for (int i = 0; i < 5; i++) {
    // StreamController의 add()처럼 yield 키워드를 이용해서 값 반환
    yield 'i = $i';
    await Future.delayed(Duration(seconds: 1));
  }
}

void playStream() {
  // StreamController와 마찬가지로 listen() 함수로 콜백 함수 입력
  calculate().listen((val) {
    print(val);
  });
}

void main() {
  playStream();
}

// 실행 결과(1초에 한줄씩 출력)
i = 0
i = 1
i = 2
i = 3
i = 4

 

이번에는 비동기 프로그래밍에 대해서 알아봤다.

점점 어려워지는구만..ㅋㅋ

반응형
반응형

다트 언어는 객체지향 프로그래밍을 지원한다.

 

클래스

// class 정의.
class Person {

	// class 종속 변수
	String name = '이름';
    
    // class 종속 함수 = 메소드
    // 내부 속성을 사용할 때 this 키워드 사용.
    void sayName() {
    	print('My name is ${this.name}');
    }
    
}

 

인스턴스 생성

void main() {
	// 인스턴스 생성
	Person person = Person();
    
    // 메소드 실행.
    person.sayName();
}

 

생성자

class Person {
	// 생성자에서 입력 받는 변수들은 일반적으로 final 키워드 사용.
	final String name;
    
    // 생성자 선언. class 와 같은 이름.
    // 매개변수 지정
    Person(String name) : this.name = name;
    
    // this 를 사용할 경우.
    // 해당되는 변수에 자동을 매개변수가 저장.
    Person(this.name);
    
    void sayName() {
    	print('My name is ${this.name}');
    }
    
}

void main() {
	Persion person = Person('홍길동');
}

 

네임드 생성자

class Person {
	final String name;
    final int age;
    
    // 1개 이상의 변수를 저장할때는 , 기호로 연결.
    Person(String name, int age)
    	: this.name = name,
          this.age = age;
    
    // 네임드 생성자
    Person.fromMap(Map<String, dynamic> map)
    	: this.name = map['name'],
          this.age = map['age'];
    
    void sayName() {
    	print('My name is ${this.name}');
    }
    
}

void main() {
	Persion person = Person('홍길동', 20);
    Persion hong = Person.fromMap({
    	'name' : '홍길동',
        'age' : 20,
    });
}

 

private 변수

class Person {
	// '_' 로 시작하면 private 변수 선언.
	String _name;
    
    Person(this._name);
    
    void sayName() {
    	print('My name is ${this._name}');
    }
    
}

void main() {
	Persion person = Person('홍길동');
    print(person._name); // 같은 파일에서는 에러가 발생하지 않지만 다른 파일에서 사용시 에러 발생.
}

 

Getter / Setter

class Person {
	String _name = 'hong';
    
    // get 키워드를 사용하여 getter 명시
    // 매개변수를 받지 않음.
    String get name {
    	return this._name;
    }
    
    // set 키워드를 사용하여 setter 명시
    // 매개변수로 하나의 변수를 받음.
    set name(String name) {
    	this._name = name;
    }
    
}

void main() {
	Persion person = Person();
    person.name = '홍길동'; // setter
    print(person.name); // getter
}

 

상속

class Person {
	final String name;
    
    Person(this.name);
    
    void sayName() {
    	print('My name is ${name}.');
    }
}

// 상속
class Man extends Person {
	// 상속 받은 생성자
    // super 는 부모 클래스를 의미한다.
	Man(String name) : super(name);
    
    void sayMan() {
    	print('I am a man');
    }
}

void main() {
	Man man = Man('홍길동');
	print(man.sayName()); // 부모한테 물려받은 메소드
    print(man.sayMan()); // 자식이 추가한 메소드
}

 

오버라이드

class Person {
	final String name;
    
    Person(this.name);
    
    void sayName() {
    	print('My name is ${name}.');
    }
}

class Girl extends Person {
    // super 키워드를 직접 사용할 수 있음.
	Girl(super.name);
    
    @override
    void sayName() {
    	print('My name is ${name} and I am a girl');
    }
}

void main() {
	Girl girl = Girl('영희');
	print(girl.sayName()); // override 된 메소드
}

 

인터페이스

// implements 키워드를 사용하면 클래스를 인터페이스로 사용할 수 있다.
class Girl implements Person {
    final String name;
    
	Girl(super.name);
    
    // 인터페이스로 사용할 때는 모든 메소드를 재정의 해야한다.
    void sayName() {
    	print('My name is ${name}');
    }
}

void main() {
	Girl girl = Girl('영희');
	print(girl.sayName());
}

 

믹스인???

 - 이건 잘 모르겠다... --;;;

 

추상 클래스

 - 인스턴스화 할 필요가 없을 경우에 사용

// abstract 키워드를 사용하여 추상 클래스 정의.
abstract class Person {
	final String name;
    
    // 생성자 선언
    Person(this.name);
    
    // 추상 메소드 선언.
    void sayName();
}

// implements 키워드를 사용하여 추상 클래스를 구현.
// 생성자를 비롯하여 모든 메소드를 정의해야 한다.
class Girl implements Person {
	final String name;

    // super 키워드를 직접 사용할 수 있음.
	Girl(this.name);
    
    void sayName() {
    	print('My name is ${name} and I am a girl');
    }
}

void main() {
	Girl girl = Girl('영희');
    print(girl.sayName());
}

 

제너릭

// 제너릭
// 특정 변수의 타입을 제한하고 싶지 않을 때 사용.
// 인스턴스화 할 때 입력받을 타입을 T 로 지정.
class Generate<T> {
	// 데이터 타입을 인스턴스화 할 때 지정한 타입으로 사용.
	final T data;
    
    Generate({
    	required this.data,
    });
}

void main() {
	// 제너릭에 입력된 값을 통해 data 변수의 타입이 자동으로 유추.
	final gen = Generate<List<int>> (data : [1, 2, 3]);
    print(gen.data.reduce((v,e) => v + e); // 6
}

 

static

class Count {
	// static 은 클래스 자체에 귀속
	static int i = 0;
    
    // 생성자가 호출될때 마다 i 증가.
    Count() {
    	i++;
        print(i);
    }
}

void main() {
	Count c1 = Count(); // 1
    Count c2 = Count(); // 2
    Count c3 = Count(); // 3
}

 

Cascade

class Person {
	final String name;
    final int age;
    
    Person(this.name, this.age);
    
    void sayName() {
    	print('My name is ${this.name}');
    }
    
    void sayAge() {
    	print('My age is ${this.age}');
    }
}

void main() {
	// cascade 연산자 ..
    // 인스턴스의 속성이나 메소드를 연속해서 사용하는 것.
	Person person = Person('홍길동', 20)
    	..sayName()
        ..sayAge();
}

 

오늘은 다트의 객체지향 프로그래밍에 대해서 공부했다!!

 

반응형
반응형

플러터는 다트(Dart) 언어를 사용합니다.

다트를 알아야 플러터로 앱 개발이 가능하므로 다트를 공부해야합니다.

다트는 구글에서 개발한 프로그래밍 언어입니다.

다트는 모바일이나 데스크탑 기기를 타겟으로 하는 네이티브 플랫폼과 웹을 타켓으로 하는 웹 플랫폼으로 컴파일 할 수 있습니다.

다트 공부하기

1. 다트패드에서 공부하기

다트패드 홈페이지에서 코드 작성 및 실행 가능합니다.
 

DartPad

 

dartpad.dev

코드 작성 후 Run 버튼을 클릭하여 실행 결과를 확인 할 수 있다.

 

2. 안드로이드 스튜디오에서 공부하기

File -> New -> New Flutter Project ... 메뉴를 클릭하여 플러터 프로젝트를 생성한다.

lib/main.dart 파일에 코드를 작성 후 안드로이드 스튜디오 하단의 터미널 탭에서 dart lib/main.dart 명령어를 실행한다.

 

 

기초 문법

메인 함수

void main() {
	// 한줄 주석
    
    /* 시작기호, 끝 기호 */
    /* 여러 줄 주석
    * 
    *
    * */
    
    /// 슬래시 세 개를 사용하면 문서 주석을 작성할 수 있습니다.
    
}

 

변수 선언

// 변수 타입
String(문자열), int(정수형), double(실수형), bool(불리언 true/false)
String s = '';
int i = 1;
double d = 1.0;
bool b = true;

// 자동으로 타입을 추론. 한번 추론된 타입은 고정됨.
var name = '이름';

// 추후에 타입이 바뀌면 에러
name = 1; // 에러

// dynamic 키워드를 사용하면 변수 타입을 고정하지 않고 사용 가능.
dynamic d_name = '다이내믹';
d_name = 1;

// final, const 는 처음 선언 후 값 변경이 불가하다.
final String f_str = 'final string';
f_str = 'new string'; // 에러 발생

const String c_str = 'const string';
c_str = 'new const'; // 에러 발생

// final 은 런타임, const 는 빌드타임 상수이다.
// DateTime.now() 는 실행되는 순간(런타임 시) 값이 정해진다.
final DateTime f_now = DateTime.now();
const DateTime c_now = DateTime.now(); // 에러 발생

// 컬렉션
// List
List<String> list = ['s1', 's2', 's3'];
print(list[3]); // s3
list.add('s4');
final list_where = list.where((str) => str == 's1' || str == 's4'); // Iterable (s1, s4)
print(list_where.toList()); // [s1, s4]
final list_map = list.map((str) => 'new $str'); // Iterable (new s1, new s2, new s3, new s4);
final list_reduce = list.reduce((v, e) => v + ', ' + e); // (반환 타입이 String) s1, s2, s3, s4
final list_fold = list.fold(0, (v, e) => v + e.length); // (반환 타입 아무거나 가능) 8

// Map
Map<String, String> map = {
	'a' : 'a1',
    'b' : 'b2',
    'c' : 'c3',
};
print(map['b']); // b2
print(map.keys); // Iterable (a, b, c)
print(map.values); // Iterable (a1, b2, c3)

// Set
Set set = {'s1', 's2', 's3'};
set.contain('s2'); // true
set.toList(); // Set to List
Set.from(list); // Set from List

// enum
enum Status {
	ready,
    play,
    done,
}

Status status = Status.ready;
print(status); // Status.ready

 

연산자

// 사칙연산
+
-
*
/ // 몫
% // 나머지
++
--
+=
-=
*=
/=


// null 관련 연산자
// nallable
double? number1 = 1;

// not null
double number2 = null; // 에러 발생

// null 로 초기화
double? number;

// null 이면 할당.
number ??= 3; // 3

// not null 이면 할당하지 않음.
number ??= 4; // 3


// 값 비교
>
<
>=
<=
==
!=


// 타입 비교
print(number is int); // false
print(number is double); // true
print(number is! int); // true
print(number is! double); // false


// 논리 연산자
&&
||

 

제어문

if
else if
else

switch() {
	case 1 :
    	print();
    	break;
    default:
    	print();
}

for(int i=0; i < 10; i++) {
	print(i);
}

List<int> list = [1,2,3];
for(int n in list) {
	print(n);
}

while() {
}

do {
} while()

 

함수와 typedef

void main() {
	// 고정된 매개변수(포지셔널 파라미터)
      print(addTwoNumbers1(2, 3));

      // 이름이 있는 매개변수(네임드 파라미터)
      print(addTwoNumbers2(a:2, b:3));

      // 고정된 매개변수 기본값 지정
      print(addTwoNumbers3(2));
      print(addTwoNumbers3(2, 1));

      // 이름이 있는 매개변수 기본값 지정
      print(addTwoNumbers4(a:2));
      print(addTwoNumbers4(a:2, b:1));


      // typedef 는 일반적인 변수의 type 처럼 사용.
      Operation oper = add;
      oper(1, 2);

      oper = subtract;
      subtract(5, 2);

      calculate(3, 4, add);
}

// 함수의 시그니처 정의.
typedef Operation = void Function(int x, int y);

void add(int x, int y) {
  print('Add Result = ${x + y}');
}

void subtract(int x, int y) {
  print('Subtract Result = ${x - y}');
}

// dart 에서 함수는 일급 객체(일급 시민)이므로 함수를 값처럼 사용 가능.
// typedef 으로 선언한 함수를 매개변수로 사용 가능.
void calculate(int x, int y, Operation oper) {
  oper(x, y);
}

int addTwoNumbers1(int a, int b) {
  return a + b;
}

int addTwoNumbers2({required int a, required int b}) {
  return a + b;
}

int addTwoNumbers3(int a, [int b=3]) {
  return a + b;
}

int addTwoNumbers4({required int a, int b=3}) {
  return a + b;
}

 

기본 문법은 이정도로 정리하겠다.^^

반응형
반응형

본격적인 개발을 위한 도구인 안드로이드 스튜디오를 설치해보자.

공식 사이트에서 다운로드 한다.
 

Android 개발자  |  Android Developers

Android 앱 개발자를 위한 공식 사이트입니다. Android SDK 도구 및 API 문서를 제공합니다.

developer.android.com

 

그 다음 Flutter 플러그인을 설치한다.

File -> Settings 메뉴에서 Plugins 에서 flutter 검색 후 install 한다.

 

이제 개발을 위한 준비를 마쳤다.

본격적으로~~ 개발을 해보자!!

 

반응형
반응형

안드로이드와 iOS 앱을 만들수 있는 플러터를 알아보기로 했다.

먼저, 설치 부터 시작!

공식 사이트에서 Get Started 클릭.
※ 한글 사이트도 제공하고 있으니 참고하면 좋을 것 같다.
자신의 OS에 맞게 다운로드 한다.(Windows)


SDK 를 다운받아 원하는 위치에 압축을 풀면 된다.

현재 버전은 3.7.10

 

플러터 명령어를 실행하기 위해 환경 변수 설정!

윈도우 -> 설정
윈도우 - 설정



설정 창에서 "시스템 환경 변수" 검색



시스템 속성 창에서 "환경 변수" 클릭



시스템 환경 변수 추가
환경 변수 창에서 "시스템 변수"의 Path 편집 클릭
환경 변수 편집 창에서 "새로 만들기" 클릭하여 "플러터 SDK 압축 푼 디렉토리\bin" 추가 


cmd 창에서 설치 버전 확인

 

반응형

+ Recent posts