Never give up

Flutter - Call by reference 본문

해왔던 삽질..

Flutter - Call by reference

대기만성 개발자 2020. 12. 13. 15:38
반응형

먼저 call by value와 call by reference를 비교해보면

 

call by value는 말 그대로 값을 복사해서 저장합니다

 

call by reference는 값의 주소값을 저장합니다

 

그리고 필자는 List와 Map 같은 collection을 사용 할 때 값을 초기화 하는 부분에서

 

= 을 사용하면 call by value방식으로 저장될줄 알았었는데.. 아니었습니다

 

< 뭐야 이게!? >

예를 들어

    List<int> a = [0, 1 ,2];
    List<int> b = a;
    List<int> c = a;
    
    print('a: $a\nb: $b\nc: $c');
    
    c.clear();
    print('a: $a\nb: $b\nc: $c');

해당 코드를 보면 c만 clear될 줄 알았는데 실제 찍힌 로그는

a: [0, 1, 2]
b: [0, 1, 2]
c: [0, 1, 2]
a: []
b: []
c: []

다음과 같습니다

 

메소드나 클래스를 사용하면 조금 다르지 않을까 해서 해봤는데..

 

메소드 실험

void main(){
    List<int> a = [0, 1, 2];
    test(a);
    
    print('a : $a');
}

void test(List<int> list){
    List<int> b = list;
    print('b : $b');
    
    b.clear();
    print('b : $b');
}

로그

b : [0, 1, 2]
b : []
a : []

 

클래스 실험

void main(){
    List<int> a = [0, 1, 2];
    A aa = A(a);
    aa.test();
    
    print('a : $a');
}

class A{
    final List<int> b;
    
    A(this.b);
    
    void test(){
        print('b : $b');
        
        b.clear();
        print('b : $b');
    }
}

로그

b : [0, 1, 2]
b : []
a : []

 

혹시나 해서 Map도 해봤는데 역시 동일했습니다

    Map<int, String> a = {0 : 'a', 1 : 'b', 2 : 'c'};
    Map<int, String> b = a;
    Map<int, String> c = a;
    
    print('a: $a\nb: $b\nc: $c');
    
    c.clear();
    print('a: $a\nb: $b\nc: $c');

로그

a: {0: a, 1: b, 2: c}
b: {0: a, 1: b, 2: c}
c: {0: a, 1: b, 2: c}
a: {}
b: {}
c: {}

 

여기서 추측해볼 수 있는건 collection을 초기화 시킬 때 저런식으로 사용하면

 

value가 아니라 reference가 복사됩니다

 

해당 코드에서는 [0, 1, 2]가 저장된 메모리 주소를 참조한다는 얘기가 되죠

 

이걸 방지하려면 다음과 같이 초기화를 하면 되는데

    List<int> a = [0, 1 ,2];
    List<int> b = [];
    List<int> c = [];
    b.addAll(a);
    c.addAll(a);
    
    print('a: $a\nb: $b\nc: $c');
    
    c.clear();
    print('a: $a\nb: $b\nc: $c');

혹은 다음과 같이 of를 사용하거나 또 다른 방법 등을 사용하시면 됩니다

    List<int> a = [0, 1 ,2];
    List<int> b = List.of(a);
    List<int> c = List.of(a);
    
    print('a: $a\nb: $b\nc: $c');
    
    c.clear();
    print('a: $a\nb: $b\nc: $c');

로그

a: [0, 1, 2]
b: [0, 1, 2]
c: [0, 1, 2]
a: [0, 1, 2]
b: [0, 1, 2]
c: []

 

그런데 좀 더 복잡한 데이터를 넘길때에는 생각을 조금 해봐야될거 같습니다

 

예를들면 Map<key, data> 여기서 data 안에 collection이 들어가는 경우죠

 

현재 필자가 개발중인 앱의 data type은 다음과 같은데

  List<String> a;
  Uint8List b;
  String c, d, e, f;
  Map<String, int> g = {};
  DateTime h;
  List<data> i;
//data = String 2, DateTime 1

Map에서 값을 저장하는것까지는 완료가 되는데 다른 화면에 전달해서 출력을 해보니

 

i값은 제대로 출력되지만 a값은 제대로 출력이 안됐습니다

 

각각 값 저장방식은

 

a

void method1() {
    a.add(value);
    notifyListeners();
  }
 
void method2(){
    map[key] = data(value); //value안에 a값이 들어갑니다
    notifyListeners();
    initData(); //<= 잡았다 요놈!
}

i

@override
  void method2() {
    if (null 체크) {
      map[key].i.add(value);

      notifyListeners();
    }
  }

이걸 해결하기 위해 정말 나쁜짓(?)을 했습니다 a를 String으로 변환해서 처리해버린거죠..

 

즉 jsonEncode(List)를 사용해서 String값으로 저장하고 jsonDecode(String)로 List형태로 출력을 했었는데

 

dart의 collection에 저장 방식이 call by reference라는것을 알았다면 이런 삽질은 안했을것입니다...

(닉네임을 삽질하는 개발자로 바꿔야되나 심각하게 고민중입니다..)

 

< 필자의 심정 >

 

반응형
Comments