개요
자바 개발을 할 때 개발의 편의성의 도움을 주는 탑티어 라이브러리가 뭐냐고 묻는다면 나는 Lombok이라고 말해주고 싶다. Flutter에서 Lombok급 개발의 편의성에서 도움을 주는 라이브러리가 오늘 내용을 정리해 볼 Freezed 라이브러리가 아닐까 생각이 된다.
https://pub.dev/packages/freezed Freezed 라이브러리 공식문서이다.
본문
Package 설정
# Freezed 설정 시작
flutter pub add freezed_annotation
flutter pub add --dev build_runner
flutter pub add --dev freezed
# Freezed 설정 끝
# 아래 정의는 데이터클래스 Json Serialization, Deserialization에 대한 설정이다.
flutter pub add json_annotation
flutter pub add --dev json_serializable
Terminal을 열고 Freezed 설정 추가 명령을 하나씩 실행한다. 그러면 pubspec.yaml에 최신 버전으로 자동으로 설정이 된다. 참고로 명령에 대한 오류가 발생한다면 [Flutter] zsh: command not found 이 글을 읽고 환경변수 설정을 진행해야한다.
추가로 Json 직렬화 관련 설정인데 기본적으로 API 통신하는 앱이면 무조건 해야 된다. 이것도 추가하자. 모두 완료되었으면 아래와 같이 pubspec.yaml에 설정이 추가되어 있을 것이다.
클래스 설정
import 'package:freezed_annotation/freezed_annotation.dart';
part 'AppLaunchConfig.freezed.dart';
part 'AppLaunchConfig.g.dart';
@freezed
class AppLaunchConfig with _$AppLaunchConfig {
factory AppLaunchConfig({
String? noticeMessage,
String? latestVersion,
bool? hasUpdate,
bool? hasForcedUpdate,
}) = _AppLaunchConfig;
factory AppLaunchConfig.fromJson(Map<String, dynamic> json) => _$AppLaunchConfigFromJson(json);
}
- 데이터 클래스에 @freezed 어노테이션을 추가한다.
- 클래스 명 옆에 with _${클래스명} 추가 정의한다.
- factory 키워드로 생성자를 만들고 = _{클래스명} 추가한다.
- part '{클래스명}.freezed.dart'; 를 추가하여 제너레이션 되는 파일을 선언한다.
여기까지가 Freezed에 대한 기본 설정이고 아래는 Json 직렬화 관련 제너레이션 파일을 생성하기 위한 설정이다.
- factory 키워드로 {클래스명}.fromJson() => _${클래스명}FromJson(json); 을 정의한다.
- part '{클래스명}.g.dart'; 를 추가하여 제너레이션 되는 파일을 선언한다.
모두 설정 완료되었어도 클래스에 에러가 발생되고 있을 것이다. 파일을 제너레이션 하지 않았기 때문이다
flutter pub run build_runner build
터미널에서 위의 명령어를 수행하자.
클래스 파일 package 위치에 freezed.dart 파일과 g.dart 파일이 생성되었을 것이다. 프로젝트를 개발하면서 많은 모델들이 생성이 될 텐데 같은 패키지 안에 freezed와 g 파일들이 생성된다면 파일 수가 많아져서 보기가 힘들어질 것이다. 그래서 File Nesting을 설정해보자
프로젝트 설정 > File Nesting > .dart의 Child File 에 .freezed.dart; .g.dart; 추가하자.
클래스 파일 하위에 정렬이 되므로 보기 편해졌다. 참고하자. 개발을 진행하다가 데이터 클래스에 대해서 정상적으로 제너레이션 파일이 생성되지 않았을 때 아래와 같은 명령어를 수행해보자.
flutter pub run build_runner build --delete-conflicting-outputs
Freezed 주요 기능
1. toString() Overriding
final data = AppLaunchConfig(latestVersion: '1.0.0', noticeMessage : 'message', hasForcedUpdate: false, hasUpdate: false);
print(data.toString());
// 출력
AppLaunchConfig(noticeMessage: message, latestVersion: 1.0.0, hasUpdate: false, hasForcedUpdate: false)
일반적으로 클래스 toString() 요청하면 인스턴스 정보만 나온다. 어떠한 값을 가지고 있는지를 볼 수 없어서 toString()을 매번 오버라이딩을 해야 하는데 Freezed를 사용하면 클래스 데이터 정보 값들을 모두 볼 수 있다.
2. Json 변환
final data = AppLaunchConfig(latestVersion: '1.0.0', noticeMessage : 'message', hasForcedUpdate: false, hasUpdate: false);
print(data.toJson());
// 출력
{noticeMessage: message, latestVersion: 1.0.0, hasUpdate: false, hasForcedUpdate: false}
클래스 toJson()을 하면 클래스 데이터가 Json 형태로 변환하게 된다.
3. 클래스 비교
final data1 = AppLaunchConfig(latestVersion: '1.0.0', noticeMessage : 'message', hasForcedUpdate: false, hasUpdate: false);
final data2 = AppLaunchConfig(latestVersion: '1.0.0', noticeMessage : 'message', hasForcedUpdate: false, hasUpdate: false);
print(data1 == data2); // true
데이터 클래스를 비교하고 싶을 때 클래스 안에 데이터가 모두 같으면 같다고 판단하고자 하는 것이 99%이다. 하지만 실제로는 클래스 비교할 때 값은 같아도 다른 객체라고 판단하게 된다. Freezed는 equles와 hashcode도 모두 자동으로 오버라이딩 해준다.
4. 변수 Validation 정의
@Assert('noticeMessage.length < 10', 'message 길이는 10보다 작아야한다.')
factory AppLaunchConfig({
String? noticeMessage,
String? latestVersion,
bool? hasUpdate,
bool? hasForcedUpdate,
}) = _AppLaunchConfig;
@Assert 어노테이션으로 변수의 조건에 대해 검증할 수 있는 기능을 제공해준다. noticeMessage 길이 10글자 넘어가면 'message 길이는 10보다 작아야 한다.' 에러가 발생된다.
5. 클래스 카피
final data1 = AppLaunchConfig(latestVersion: '1.0.0', noticeMessage : 'message', hasForcedUpdate: false, hasUpdate: false);
final data2 = data1.copyWith();
print(data2.toString()); // AppLaunchConfig(noticeMessage: message, latestVersion: 1.0.0, hasUpdate: false, hasForcedUpdate: false)
final data3 = data1.copyWith(noticeMessage: 'message2');
print(data3.toString()); // AppLaunchConfig(noticeMessage: message2, latestVersion: 1.0.0, hasUpdate: false, hasForcedUpdate: false)
생성된 클래스를 copyWith() 메소드를 통해서 데이터 값들이 그대로 복사된 클래스를 생성할 수 있고 data1.copyWith(noticeMessage: 'message2'); 변경하고 싶은 변수만 변경해서 복사도 가능하다. 이 카피 기능인 Deep copy라서 정말 편하다.
클래스가 하위 오브젝트를 가지고 있으며 제일 마지막 오브젝트 값만 변경해서 클래스를 카피하고 싶을 경우
data1.{객체}.{객체}.{객체}({변수 값 변경}); <-- 이런 식으로 도 간단하게 하위 객체만 변경해서 카피가 가능하다.
이외에도 많은 기능들이 제공해주고 관리하는 것 같은데 나도 다 사용해보지는 않았다. 사용해본 것 중에 괜찮은 기능들만 요약해봤다. 추가적인 내용은 freezed document를 참고해보자.
※ 참고사항 ※
@freezed
class AppLaunchConfig with _$AppLaunchConfig {
factory AppLaunchConfig({
String? noticeMessage,
String? latestVersion,
bool? hasUpdate,
bool? hasForcedUpdate,
}) = _AppLaunchConfig;
factory AppLaunchConfig.fromJson(Map<String, dynamic> json) => _$AppLaunchConfigFromJson(json);
AppLaunchConfig._(); // 생성자 추가 정의
void appPrint() {
print('test');
}
}
클래스 안에 메소드를 정의하여 사용할 수도 있는데 이때는 생성자가 하나 더 필요하다 {클래스명}._();
freezed 클래스가 변경이 될 때마다 새롭게 제너레이트 빌드를 해줘야 한다.
마무리
개발할때 생산성을 장점을 많이 제공을 해주니 정신적으로나 육체적으로 편하고자 한다면 무조건 사용해야 되는 라이브러리라 생각된다.
'Flutter' 카테고리의 다른 글
[Flutter] GetX - 상태관리 (0) | 2022.12.19 |
---|---|
[Flutter] Firebase 안드로이드 SMS 인증 (1) | 2022.12.18 |
[Flutter] Firebase 안드로이드, IOS 설정 (0) | 2022.12.17 |
[Flutter] zsh: command not found (0) | 2022.12.01 |
[Flutter] 안드로이드 스튜디오를 이용하여 프로젝트 생성 (0) | 2022.11.29 |
댓글