jsonEncode
타입을 `String`으로 변환하는 함수.
`import 'dart:convert';`라이브러리를 통해 사용할 수 있다.
import 'dart:convert';
void main() {
Map<String, dynamic> myInfo = {
"name": "Mark",
"age": 20
};
// Map -> String
String jsonString = jsonEncode(myInfo);
print(jsonString); // {"name":"Mark","age":20}
print(jsonString.runtimeType); // String
// List -> String
List list = [myInfo, myInfo];
String listJsonString = jsonEncode(list);
print(listJsonString); // [{"name":"Mark","age":20},{"name":"Mark","age":20}]
print(listJsonString.runtimeType); // String
}
jsonDecode
Map형태의 `String`타입이나 List형태의 `String`타입을 각 형태의 맞는 타입으로 변환하는 함수.
`import 'dart:convert';` 라이브러리를 통해 사용할 수 있다.
import 'dart:convert';
void main() {
// 여러줄의 문자열, 따옴표 등을 편하게 사용할 수 있는 트리플 쿼트 """, '''
String jsonString = """
{
"name": "Mark",
"age": 20
}
""";
// jsonDecode 리턴 타입이 dynamic 이니까 var를 사용해도 됨
// Map형태의 String 타입 -> Map 타입
var result = jsonDecode(jsonString);
print(result); // {name: 'Mark', age: 20}
print(result.runtimeType); // Map<String, dynamic>
}
import 'dart:convert';
void main() {
String jsonString = """
[
{
"name": "Mark",
"age": 20
},
{
"name": "kai",
"age": 7
}
]
""";
// List구조의 String 타입 -> List 타입
var result = jsonDecode(jsonString);
print(result); // [{name: Mark, age: 20}, {name: kai, age: 7}]
print(result.runtimeType); // List<dynamic>
}
클래스 적용
jsonDecode의 값으로 네임드 생성자 만들기 - 생성자.fromJson
jsonDecode의 값으로 클래스에 적용할 수 있다.
적용하는 이유는 `Map`에서 값을 사용하기 위해서는 대괄호를 사용해야하고 어떤 키값이 있는지 자동완성이 되지 않지만 `클래스를 이용한 인스턴스는 점(.)을 이용할 때 자동완성이 되어 어떤 속성이 있는지 파악할 수 있어 좋다.`
`fromJson이라는 명칭은 개발자들 사이에서의 컨벤션이라 볼 수 있다.`
import 'dart:convert';
class User {
String name;
int age;
User({
required this.name,
required this.age
});
// this 생략 가능
User.fromJson(Map<String, dynamic> map)
: this.name = map['name'],
this.age = map['age'];
// 위 방법 말고 이렇게 사용할 수도 있음
// 네임드 생성자 호출시 기본 생성자를 호출한다는 뜻
User.fromJson2(Map<String, dynamic> map)
: this(name: map['name'], age: map['age']);
}
void main() {
String jsonString = """
{
"name": "Mark",
"age": 20
}
""";
// 'Map형태의 String 타입 -> Map 타입' 변환
var jsonMap = jsonDecode(jsonString);
// 네임드 생성자인 fromJson을 만들어 'Map 타입 -> 인스턴스' 변환
User user = User.fromJson(jsonMap);
print(user.name); // Mark
print(user.age); // 20
}
toJson 만들기
json형태로 만들기 위해서는 `Map`, `List`여야 한다.
그래서 `toJson`메서드를 만들어 타입을 변경하여 반환한다.
`toJson이라는 명칭은 개발자들 사이에서의 컨벤션이라 볼 수 있다.`
import 'dart:convert';
void main() {
String jsonString = """
{
"name": "Mark",
"age": 20
}
""";
// 'Map형태의 String 타입 -> Map 타입' 변환
var jsonMap = jsonDecode(jsonString);
// 네임드 생성자인 fromJson을 만들어 'Map 타입 -> 인스턴스' 변환
User user = User.fromJson(jsonMap);
// toJson 메서드를 만들어 '인스턴스 -> Map 타입' 변환
Map<String, dynamic> userMap = user.toJson();
print(userMap['name']); // Mark
print(userMap['age']); // 20
}
class User {
String name;
int age;
User({required this.name, required this.age});
// this 생략 가능
User.fromJson(Map<String, dynamic> map)
: this.name = map['name'],
this.age = map['age'];
// 위 방법 말고 이렇게 사용할 수도 있음
// 네임드 생성자 호출시 기본 생성자를 호출한다는 뜻
User.fromJson2(Map<String, dynamic> map)
: this(name: map['name'], age: map['age']);
// 클래스의 인스턴스를 다시 json으로 만들기 위해
// Map타입으로 변경하는 메서드를 정의
Map<String, dynamic> toJson() {
return {"name": name, "age": age};
}
}
중첩된 형태의 데이터일 경우
import 'dart:convert';
void main() {
String jsonString = """
{
"name": "Mark",
"age": 20,
"isMale" : true,
"favorite_foods" : ["삼겹살", "팥빙수", "샤인머스켓"],
"contact": {
"mobile": "010-0000-0000",
"email": null
}
}
""";
// 2. Map<String, dynamic>으로 변환해서 map이라는 이름의 변수에 담기
Map<String, dynamic> map = jsonDecode(jsonString);
// 3. jsonString 을 Map 으로 변환 후 User class로 변환 후 출력해서 변수에 담기!
User user = User.fromJson(map);
// 4. print 문으로 Pet 클래스의 toJson 메서드를 호출해서 출력
print(user.toJson());
}
/*
* 1. 아래에서 클래스 정의 Contact, User
*/
class User {
final String name;
final int age;
final bool isMale;
final List<dynamic> favoriteFoods;
final Contact contact;
User({
required this.name,
required this.age,
required this.isMale,
required this.favoriteFoods,
required this.contact,
});
User.fromJson(Map<String, dynamic> json)
: this(
name: json["name"],
age: json["age"],
isMale: json["isMale"],
// 5. List를 참조가 아닌 복사를 위해 List.from 사용
favoriteFoods: List.from(json["favorite_foods"]),
// 6. 새로운 인스턴스로 만들었으니 참조가 될 수 없음
contact: Contact.fromJson(json["contact"]),
);
Map<String, dynamic> toJson() {
return {
"name": name,
"age": age,
"isMale": isMale,
"favorite_foods": favoriteFoods,
"contact": contact.toJson(),
};
}
}
class Contact {
String mobile;
String? email;
Contact({required this.mobile, required this.email});
Contact.fromJson(Map<String, dynamic> json)
: this(mobile: json["mobile"], email: json["email"]);
Map<String, dynamic> toJson() {
return {"mobile": mobile, "email": email};
}
}
1. `jsonDecode`로 인해 `Map`타입이 되었는데 값에 `Map`타입이 또 있으면 내부에 있는 값에 대한 클래스를 먼저 정의하고, 전체를 포함하는 클래스를 나중에 정의하는 것이 편하다.
5. `map['favorite_foods']`를 복사하기 위해 `List.from`을 사용. 제네릭 `List<String>.from`을 사용하여 `map['favorite_foods']`의 타입인 `List<dynamic>`타입을 `List<String>`타입으로 변경하여 복사할 수도 있다.
6. `Contact.fromJson`으로 새로운 인스턴스를 만들었으므로 참조가 될 수 없다.
느낀 점
`fromJson`은 생성자로 사용하고, `toJson`은 메서드로 사용하는 이유가 뭘까 생각해봤다.
생성자는 `인스턴스`를 반환하기 위한 메서드이므로 `fromJson`을 네임드 생성자로 사용하는 것 같다.
반면에, `toJson`은 인스턴스가 아닌 `Map`을 반환하기 때문에 생성자라는 역할 보다는 메서드라는 역할이 더 잘 어울리는 것 같다.
'TIL(Today I Learned)' 카테고리의 다른 글
[TIL-025] Flutter 위젯 파헤치기 - TextField (0) | 2025.04.14 |
---|---|
[TIL-024] Flutter 상태관리 라이브러리 - Riverpod (0) | 2025.04.14 |
[TIL-022] Flutter 도대체 버튼 스타일링 어떻게 해야 하는거야? (0) | 2025.04.02 |
[TIL-021] Flutter 위젯 파헤치기 - Builder (0) | 2025.04.02 |
[TIL-020] Flutter로 기차 좌석 예매 어플 만들기-2 (0) | 2025.04.01 |