Menu
CoddyTech

오류 던지기

Coddy Flutter 여정의 데이터와 네트워크 섹션에 포함된 레슨. 27개 중 11번째.

오류는 서버에서만 발생하는 것이 아닙니다. 직접 만든 함수도 실행을 멈출 수 있습니다. 함수가 처리할 수 없는 값을 받으면 예외를 던집니다:

Future<void> saveName(String name) async {
  if (name.isEmpty) {
    throw Exception('The name cannot be empty');
  }
  // 이름을 저장합니다
}

throw는 return처럼 바로 그 지점에서 함수를 멈추지만, 값 대신 오류를 돌려줍니다. Exception('...')은 무엇이 잘못되었는지 알려 주는 메시지가 담긴 오류입니다.

함수를 호출한 쪽에서 try와 catch를 사용해 오류를 처리합니다. 이는 fetch에서 발생한 오류와 정확히 같습니다. 텍스트로 변환하면 Exception은 Exception: 으로 시작하고, 그 뒤에 메시지가 옵니다.

실제 fetch도 이와 같은 방식으로 작동합니다. 서버의 모든 응답에는 상태 코드가 함께 제공됩니다. 200은 정상 응답을, 404는 찾을 수 없음을 의미합니다. 상태 코드가 200이 아니면 코드에서 예외를 던지므로, 화면에 잘못된 응답이 데이터인 것처럼 표시되지 않습니다:

final response = await http.get(Uri.parse(url));
if (response.statusCode != 200) {
  throw Exception('The server answered ${response.statusCode}');
}
return response.body;
challenge icon

챌린지

쉬움

입력란을 비운 채 Save를 누르면 이름 없이 Saved: 라고 표시됩니다. saveName이 빈 이름을 거부하도록 만드세요. 대기 후 name이 비어 있으면 Exception('The name cannot be empty')을 던지세요. save 함수는 이미 예외를 포착하고 메시지를 표시합니다.

직접 해보기

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: NameScreen(),
    );
  }
}

class NameScreen extends StatefulWidget {
  const NameScreen({super.key});

  @override
  State<NameScreen> createState() => _NameScreenState();
}

class _NameScreenState extends State<NameScreen> {
  final controller = TextEditingController();
  String status = '';

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  Future<void> saveName(String name) async {
    await Future.delayed(const Duration(seconds: 1));
  }

  Future<void> save() async {
    try {
      await saveName(controller.text);
      setState(() {
        status = 'Saved: ${controller.text}';
      });
    } catch (e) {
      setState(() {
        status = '$e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: controller,
              decoration: const InputDecoration(labelText: 'Name'),
            ),
            const SizedBox(height: 16),
            ElevatedButton(onPressed: save, child: const Text('Save')),
            const SizedBox(height: 16),
            Text(status, style: const TextStyle(fontSize: 18)),
          ],
        ),
      ),
    );
  }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

데이터와 네트워크의 모든 레슨

직접 연습해 보세요: 온라인 Flutter 컴파일러