Home > Back-end >  New list still references old list after being cloned
New list still references old list after being cloned

Time:05-30

I have a list of maps which are initialized as follow

  List<dynamic> _people = [];
  Map<String, dynamic> _person = {
    'image' : null,
    'name': null,
    'age': null
  };

On one of the methods inside the program I intend to copy the value inside _people to a new List variable so I can make changes to it.

List _peopleCopy = List.from(_people);
for (var i=0; i < _people.length; i  ) {
  if (_people[i]['image'] != null) {
    List<num> img = new List.from(_people[i]['image'].readAsBytesSync());
    _peopleCopy[i]['image'] = img;
  }
}

Now the problem here is that everytime I assign the value of img to _peopleCopy, it would change the respective value on _people list as well even though I did List.from() method to clone it. Obviously, I wanted to preserve the original content of _people list. What did I do wrong here?

CodePudding user response:

You have successfully created a new list. But the list contains the references to the same maps. So changing a map will change it in both lists since it's the same element.

You need to copy the elements, too.

Since your map also contains a dynamic type that you probably want to deep copy, I would suggest to just jsonEncode/jsonDecode your whole structure. Serializing and Deserializing is not the most efficient way, but it will create a deep copy of whatever structure is in there.

That said, Dart is a real programming language. It helps a lot to use it that way. If you use actual types, instead of dynamic, it becomes less guessing, praying and duct-typing and more solid, fact based programming. Since this seem to be JSON structures, use model classes. Then you can have your own deep copy methods and have compiler support that you just don't get when you use dynamic.

CodePudding user response:

For such case what I do is, I store the originalJson of the object inside a variable in the object class like below,

class People {
  int? age;
  String? image;
  String? name;
  Map<String, dynamic> originalJson = {};

  People({this.age, this.image, this.name});

  People.fromJson(Map<String, dynamic> json) {
    originalJson = json;
    age = json['age']?.toInt();
    image = json['image']?.toInt();
    name = json['name']?.toString();
  }

  Map<String, dynamic> toJson() {
    'age' = age;
    'image' = image;
    'name' = name;
  }
}

So when you are parsing the http reponse, now all you have to do is,

People.fromJson(json.decode(response.body));

This way you can preserve the json and while cloning the list of People, all you have to do is,

  // With the following line _people will now be new list with new objects but with mutated _people data
  _people = _people.map((e) => People.fromJson(e.toJson())).toList();
  // With the following line _people will now be new list with new objects but with data which we have recieved from the API call
  _people = _people.map((e) => People.fromJson(e.originalJson)).toList();

This way of maintaining the class should for sure help you out..

  • Related