안녕하세요 오늘은 이전 디자인 시스템 개발 작업에서 적용했던 부분 중에 잘못된 부분이 있어 리팩토링 하였습니다.
이 트러블 슈팅을 어떻게 해결하였는지 작성해보겠습니다.
이전에는 AppColorsTheme().gfBlackColor를 사용하여 색을 정해주었는데 이 객체가 같은 주소를 참조하는 객체가 아니 다른 주소를 참조하는 객체를 계속 생성하여 사용했던 문제였습니다.
객체를 복사하여 사용
리팩토링 되기 전 코드에서는 AppColorsTheme()를 사용하여 AppColorsTheme()안에 있는 색을 사용했습니다.
HomeView UI와 NoticeView UI가 그려질 때 마다 주소값을 출력해보겠습니다.
final appColor = AppColorsTheme();
final appColor2 = AppColorsTheme();
print("home appcolor: ${appColor.hashCode}");
print("home appcolo2r: ${appColor2.hashCode}");
final appColor = AppColorsTheme();
final appColor2 = AppColorsTheme();
print("notice appcolor: ${appColor.hashCode}");
print("notice appcolo2r: ${appColor2.hashCode}");
hashCode는 객체의 내용을 기반으로 생성된 정수 값입니다.
일반적으로 같은 내용의 객체는 같은 hashCode를 반환합니다.
아래 출력 로그를 보시면 hashCode가 다른 것을 확인할 수 있습니다.
물론 이 객체가 사이즈가 엄청 작은 객체이어 큰 영향을 주지 않지만 좋지 않은 개발입니다.
그림으로 그려보면 View를 그릴때 만약 View 하나를 그릴 때 AppColorsTheme()를 16번 사용하였다고 가정한다면 View가 한 번 그려질때 16개의 객체가 생성되는 것입니다.
그러면 View를 10번 그리면 160개의 객체가 생성됩니다.
그러면 필요하지도 않는 객체를 계속 생성하여 불필요한 메모리 사용을 하고 있는 상황입니다.
방법 1. const만 사용하여 같은 객체를 참조하자.
출력은 위에 상황과 똑같습니다. 변경된 코드는 AppColorsTheme의 프로퍼티들을 모두 const로 지정하였습니다.
class AppColorsTheme {
final Color gfMainColor = const Color(0xFF02542D); // 02542D
final Color gfMainBackGroundColor = const Color(0xFFE2EAE8); // 02542D with 10% opacity
final Color gfWarningBackGroundColor = const Color(0xFFFBECEE); // FF6A69 with 10% opacity
final Color gfWarningYellowColor = const Color(0xFFFFC35A); // FFC35A
final Color gfWarningYellowBackGroundColor = const Color(0xFFFBF2E4); // FFC35A with 10% opacity
final Color gfWarningColor = const Color(0xFFFF6A69); // FF6A69
final Color gfBlueColor = const Color(0xFF007AFF); // 007AFF
final Color gfWhiteColor = const Color(0xFFFBFBFD); // FBFDFD
final Color gfBackGroundColor = const Color(0xFFF4F4F9); // F4F4F9
final Color gfGray100Color = const Color(0xFFF3F4F6); // F3F4F6
final Color gfGray300Color = const Color(0xFFDBDEE2); // DBDEE2
final Color gfGray400Color = const Color(0xFF8B95A1); // 8B95A1
final Color gfGray800Color = const Color(0xFF535961); // 535961
final Color gfBlackColor = const Color(0xFF000000); // 000000
const AppColorsTheme();
}
Dart에서는 const로 지정된 값은 컴파일 타임 상수로 간주되며, 동일한 const 인스턴스는 애플리케이션 전체에서 재사용됩니다. 즉, const로 생성된 객체는 불변(immutable)이며, 메모리에서 동일한 인스턴스를 공유하게 됩니다.
아래 출력 로그를 보면 모든 같은 hashcode를 가진 것을 볼 수 있습니다.
즉 1000번의 View를 그려도 단 하나의 객체만 생성되고 그 객체를 이용하는 것입니다.
이 방법은 간단하고 직관적이지만,, 필요한 로직이 있을때 관리하기가 어렵습니다.
그래서 범용성 부분에서 아쉬운 모습이 있습니다. 🧐
방법 2. Theme를 이용하자.
Flutter에서는 Theme의 여러 속성에 값을 넣어 사용할 수 있습니다.
그렇다면 Extension을 사용해서 Theme에 제가 사용할 디자인 시스템을 추가하는 것입니다.
ThemeData를 extension 하여 appColors와 appTexts를 사용할 수 있게 합니다.
그리고 MaterialApp에 theme에다가 넣어주어 직접 사용할 수 있도록 합니다.
아래 코드를 보시면 이해하기 쉽습니다.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return. MaterialApp.router(
routerConfig: router,
theme: Theme.of(context).copyWith(
extensions: [
AppColorsTheme.main(),
AppTextsTheme.main(),
]
)
);
}
}
extension ThemeDataExtended on ThemeData {
AppColorsTheme get appColors => extension<AppColorsTheme>()!;
AppTextsTheme get appTexts => extension<AppTextsTheme>()!;
}
이렇게 Theme 설정을 하였다면 Theme.of(context).appColors를 사용하여 색을 지정해주면 됩니다. Theme.of(context).appColors안에 제가 지정해둔 모든 색이 담겨있기 때문에 편리하게 가져와서 사용하면됩니다. 이렇게 사용하는 방식도 같은 객체를 사용하는 지 확인해보겠습니다. 출력할 코드는 Home과 Recruit에 넣어보겠습니다.
final appColor = Theme.of(context).appColors;
final appColor2 = Theme.of(context).appColors;
print("home appcolor: ${appColor.hashCode}");
print("home appcolo2r: ${appColor2.hashCode}");
final appColor = Theme.of(context).appColors;
final appColor2 = Theme.of(context).appColors;
print("recruit appcolor: ${appColor.hashCode}");
print("recruit appcolo2r: ${appColor2.hashCode}");
결론
이렇게 지금까지 직접 테스트 해보며 같은 인스턴스를 사용하여 효율적인 메모리 사용을 하게 디자인 시스템을 리팩토링 하였습니다.
저는 개발의 편의성을 위해서 Theme를 사용했지만 더 좋은 코드가 있다고 생각합니다.
전체 코드를 보시고 싶다면 아래 주소에서 확인할 수 있습니다.
https://github.com/bulmang/green_field
'Flutter' 카테고리의 다른 글
[Flutter] [Firbase] 간편 로그인 구현하기(kakao💬) (1) | 2024.12.19 |
---|---|
[Flutter] URL Navigation(with Go_router) 개발 정리 (1) | 2024.12.05 |
[Flutter] DynamicTabBar 트러블 슈팅 (1) | 2024.11.27 |
[Flutter] Dynamic TabBar on ScrollView & NaverMap URL Scheme 사용 방법 (0) | 2024.11.22 |
[Flutter] WhiteScreen 해결(iPhone 무선빌드) & Load Sequence Flutter UI (3) | 2024.11.21 |