[Flutter] 스나이퍼팩토리 Flutter 기초과정 (16)

GONG·2023년 4월 13일
0
post-thumbnail

16일차 과제 링크 👉 16일차 과제

NULL

  • 데이터가 존재하지 않음

Null safety

NPE (Null Point Exception)

  • 객체가 특정 값이 아닌 null을 가리켜서 발생하는 오류
  • 컴파일러가 걸러내지 못하고 프로그램 실행 중에 발생하므로 치명적일 수 있음

Null safety(널 안정성)

  • NPE를 프로그램 실행하기 전 코드를 작성하는 시점에서 점검하는 것

Nullable, NonNull

  • Dart에서 변수는 기본적으로 NonNull로 선언됨
  • Nullable로 선언하려면 타입 뒤에 물음표 붙이기
    int a1 = 10;
    int? a2 = 10; // null 허용
    
    a1 = null;  // 오류
    a2 = null;

! : null인지 점검

  • 변숫값이 null일 때 런타임에러 발생
    int? a1 = 20;
    a1!;
    a1 = null;
    a1!;    // 런타임에러
  • 변수 이외에 함수 호출같은 구문에서도 사용 가능
    int? some(arg) {
      if(arg == 10) {
        return 0;
      } else {
        return null;
      }
    }
    
    main() {
      int a = some(10)!;
      print('a : $a');    // a : 0
      int b = some(20)!;
      print('b : $b');    // some() 함수가 null을 반환하므로 런타임에러
    }

?. ?[] : 멤버에 접근

?.

  • 객체가 null이 아닐 때만 속성과 메소드에 접근
  • null이면 접근할 수 없고 null을 반환
    int? no1 = 10;
    bool? res1 = no1?.isEven;
    print('result1 : $res1'); // true
    
    no1 = null;
    bool? res2 = no1?.isEven;
    print('result2 : $res2'); // null

?[]

  • null 허용 List의 데이터를 인덱스로 접근할 때 사용
  • List 객체가 null이 아닐 때 데이터에 접근할 수 있음
  • null이면 null 반환
    List<int>? list = [10, 20, 30];
    print('list[0] : ${list?[0]}'); // 10
    
    list = null;
    print('list[0] : ${list?[0]}'); // null

??= : 값 대입

  • null 허용 변수에 null이 아닌 값만 대입
  • 오른쪽의 대입할 값이 null이 아닐 때만 대입
  • null이면 대입하지 않음
    int? d3;
    d3 ??= 10;
    print('data3: $d3');  // 10
    d3 ??= null;
    print('data3: $d3');  // 10

?? : 값 대체

  • null 허용 변수가 null일 때 대체할 값을 지정
  • null일 때 오른쪽에 지정한 값을 대입한다
    Map<String, dynamic> mapData = {
      'myAge': 99,
      'myName': 'asdf'
    };
    print(mapData['myAge']);
    print(mapData['myHeight'] ?? '존재하지 않는 데이터입니다');
  • 35% 확률로 null 데이터 반환하는 url로 null 처리 연습ㅎㅐ보기
    var dio = Dio();
    var url = 'https://sniperfactory.com/sfac/http_randomly_null';
    String? result = '';
    
    var res = await dio.get(url);
    print(res.data);
    
    var item = res.data['item'];
    result = item['name'] ?? 'null임';  // 35% 확률로 null
    
    print(result);

예외 처리

  • 개발자가 예기치못한 예외의 발생에 미리 대처하는 코드를 작성하는 것

try - catch

  • 예외 발생 시 프로그램이 중단되지 않고 catch 구문을 실행
    try {
        // 예외가 발생할 가능성이 있는 코드
    } catch(e) {
        // 예외처리를 위한 코드
    } finally {
    		// 예외 발생 여부에 관계 없이 실행
    }
    try {
      List items = ['a', 'b', 'c'];
      print(items[3]);
    } catch(e) {
      print('어라 에러낫네 $e');  // 어라 에러낫네 RangeError (index): Invalid value: Not in inclusive range 0..2: 3
    } finally {
    	print('메롱');    // 에러 나든 안나든 출력됨
    }

on

  • 특정 예외 타입을 처리
    try {
      // 예외가 발생할 가능성이 있는 코드
    } on RangeError {
      // 특정 예외에 대한 처리
    } catch (e) {
      // 기타 예외 처리
    } finally {
      // 예외 발생 여부에 관계없이 실행되는 코드
    }
    try {
      List items = ['a','b','c'];
      print(items[3]);
    } on RangeError catch (e) {
      print('범위에러가 났다.: $e');
    } catch (e) {
      print('예외 발생: $e');
    } finally {
      print('finally 블록 실행');
    }
  • 65% 확률로 서버에러 발생하는 url 예외처리
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      Dio dio = Dio();
      String result = '';
    
      void getData() async {
        result = '';
        setState(() {});
        try {
          var url = 'https://sniperfactory.com/sfac/http_randomly';
          var res = await dio.get(url);
          result = res.data['item']['name'];
        } on DioError catch (e) {
          print('에러가 낫다니');
          result = e.message!;
        } finally {
          setState(() {});
        }
      }
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text(result),
                  TextButton(
                    onPressed: (){
                      getData();
                    },
                    child: Text('메세지 가져오기')
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }

FutureBuilder 위젯

  • 비동기 작업에서 Future 객체를 사용하여 UI를 구축할 때 유용한 위젯
  • 스스로 상태를 업데이트 할 수 있다
  • Future를 대신 실행할 수 있음
  • Future를 실행하는 도중에 일어나는 상태를 계속 우리한테 보고함
  • ConnectionState라는 값을 통해 알려준다
    • ConnectionState.done : 데이터 확인 가능
    • ConnectionState.waiting : 데이터가 들어오길 기다리는 중
FutureBuilder<String>(
  future: Future.delayed(Duration(seconds: 3) => 'hello!'),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      // 데이터를 기다리는 동안 표시할 로딩 화면
      return CircularProgressIndicator();
    } else {
      // 데이터가 준비된 경우
      if (snapshot.hasError) {
        // 데이터 로드 중 오류가 발생한 경우
        return Text('오류 발생: ${snapshot.error}');
      } else {
        // 데이터 로드 완료된 경우
        return Text('결과: ${snapshot.data}');
      }
    }
  },
);
  • FutureBuilder에 dio로 데이터 받아와서 보여주기
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      var dio = Dio();
      var url = 'https://sniperfactory.com/sfac/http_test';
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text('sniper factory'),
                  FutureBuilder(
                    future: dio.get('https://sniperfactory.com/sfac/http_test'),
                    builder: (context, snapshot) {
                      print(snapshot.connectionState);
                      if (snapshot.connectionState == ConnectionState.done) {
                        // 현재 futureBuilder 의 상태가 끝났을 때
                        return Text(snapshot.data!.data['result']);
                      }
                      return Container(
                        width: 20,
                        height: 20,
                        color: Colors.red,
                      );
                    }
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }

로딩 아이콘

  • **CircularProgressIndicator**
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      var dio = Dio();
      var url = 'https://sniperfactory.com/sfac/http_test';
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text('sniper factory'),
                  FutureBuilder(
                    future: Future.delayed(Duration(seconds: 3), () => dio.get('https://sniperfactory.com/sfac/http_test')),
                    builder: (context, snapshot) {
                      print(snapshot.connectionState);
                      if (snapshot.connectionState == ConnectionState.done) {
                        // 현재 futureBuilder 의 상태가 끝났을 때
                        return Text(snapshot.data!.data['result']);
                      }
                      return CircularProgressIndicator();
                    }
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }

16일차 끝

내용이 슬슬 어려워지고 있다.................

15일차부터

재밋는듯?
아닌가...
아닌거같기도하고
재밋는듯?!
아닌가...
재밋는데?!
아닌가.......

를 무한반복 중

재.재..재미.재밋.재.재밋다.....

profile
우와재밋다

1개의 댓글

comment-user-thumbnail
2023년 7월 25일

답안지 감사히 잘 보겠습니다!

답글 달기