flutter에서 api를 사용하다보면 json형태의 값을 많이 접하게 된다.
다음은 json데이터를 가져와 생성자를 통해 값을 넣는 코드다
class WebtoonModel {
final String title, thumb, id;
WebtoonModel.fromJson(Map<String, dynamic> json)
: title = json['title'],
thumb = json['thumb'],
id = json['id'];
}
위 방식은 생성자 초기화 방식이다.
이는 모든 정보를 파라미터로 넘기지 않더라도 생성자에서 값을 초기화하는 방법이다.
매개변수를 선택적으로 받을 수 있다. 콜론(:)을 사용한다
class WebtoonModel {
late final String title, thumb, id;
WebtoonModel(Map<String, dynamic> json) {
title = json['title'];
thumb = json['thumb'];
id = json['id'];
}
}
이 코드는 선택적으로 매개변수를 받을 수 없고, 모두 받아야한다.
우리는 final을 사용하고 있기 때문에 반드시 선언or생성자에서 초기화가 이루어져야 한다. 하지만 위 예시는 초기화 되지 않고 있어 에러가 발생한다.
에러가 발생하는 이유는 뭘까?
현재 json형태는 title, thumb, id이다.
근데 만약 특정 값이 title, id로만 이루어져있다면 thumb이 null이기 때문에 final로 선언된 변수는 에러를 발생하게 된다.
이에 대한 해결책은 아래와 같다.
final을 제거 후 null허용(String? 변수명)
late 사용
late를 사용하면 final을 유지하면서 json의 property가 null이더라도 초기화를 미룰 수 있다. 하지만, 언젠가는 반드시 초기화 해주어야 한다.
만약 초기화하지 않고 사용하면 LateInitializationError가 발생한다.
일반적으로 생성자로 초기화되는 변수는 final을 사용하는 이유 ?
인스턴스화 이후의 불변성 보장 ( 프로그램의 안정성이 높아진다.)
이러한 이유들로 final을 유지하면서 late를 사용하지 않는 생성자 초기화 방식이 적절하다.
api 요청코드에 static을 붙여보자
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:navertoon/models/webtoon_model.dart';
class ApiService {
static const String baseUrl =
"https://webtoon-crawler.nomadcoders.workers.dev";
static const String today = "today";
static Future<List<WebtoonModel>> getTodaysToons() async {
List<WebtoonModel> webtoonInstances = [];
final url = Uri.parse('$baseUrl/$today');
final response = await http.get(url);
if (response.statusCode == 200) {
final List<dynamic> webtoons = jsonDecode(response.body);
for (var webtoon in webtoons) {
webtoonInstances.add(WebtoonModel.fromJson(webtoon));
}
return webtoonInstances;
}
throw Error();
}
}
이전에는 인스턴스가 멤버에 대한 권한을 가졌다면, static 이후에는 클래스 자체가 권한을 가지게 된다.
따라서 객체를 생성하지 않아도 ApiService.메서드명(); 으로 사용할 수 있다.
변수 선언할 때 final 대신 const 가능? 둘 다 불변아님?
const constructor라는 것이 있는데 생성자를 const로 선언하는 것임
변경할 수 없는 객체를 만듦으로써 프로그램 성능을 향상시키는 것
class Point {
final int x;
final int y;
const Point(this.x, this.y);
}
void main() {
// p1 and p2 has the same hash code.
Point p1 = const Point(1, 2);
print("The p1 hash code is: ${p1.hashCode}");
Point p2 = const Point(1, 2);
print("The p2 hash code is: ${p2.hashCode}");
// without using const
// this has different hash code.
Point p3 = Point(2, 2);
print("The p3 hash code is: ${p3.hashCode}");
Point p4 = Point(2, 2);
print("The p4 hash code is: ${p4.hashCode}");
}
The p1 hash code is: 918939239
The p2 hash code is: 918939239
The p3 hash code is: 745146896
The p4 hash code is: 225789186
p1, p2는 const 객체이므로 같은 해시코드를 가지지만, p3, p4는 다른 해시코드를 가진다. p3,p4는 런타임에 계산되기 때문에 둘은 다른 객체다.