0

I'm trying to make a deep copy of a list of the following objects:

struct Book {
    var title: String
    var author: String
    var pages: Int
}

struct BookShelf {
    var number: Int
}

class BookShelfViewModel {
    var bookShelf: BookShelf

    var number: Int
    var books: [BookViewModel]?

    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf

        self.number = bookShelf.number
    }

    required init(original: BookShelfViewModel) {
        self.bookShelf = original.bookShelf

        self.number = original.number
    }
}

class BookViewModel {
    var book: Book

    var title: String
    var author: String
    var pages: Int

    init(book: Book) {
        self.book = book

        self.title = book.title
        self.author = book.author
        self.pages = book.pages
    }

    required init(original: BookViewModel) {
        self.book = original.book

        self.title = original.title
        self.author = original.author
        self.pages = original.pages
    }
}

Books for BookShelf is fetched in the BookShelfViewModel.

If I go like:

var copiedArray = originalArray

for bs in copiedArray {
   bs.books = bs.books.filter { $0.title == "SampleTitle" }
}

The above filter both the copiedArray and the originalArray, and I obviously just want the copiedArray altered.

When I clone the array like this:

var originalArray = [BookShelfViewModel]()
... // Fill the array
var clonedArray = originalArray.clone()

clonedArray is cloned, but clonedArray.books is empty.

I've created the extension and followed this gist. How do I clone the array in the objects in the array?

I've done a quick playground to visualize the problem, hopefully it helps understand what I'm talking about.

enter image description here

7
  • Array is a value type. Your implementation of clone is completely unnecessary. simply let array2 = array1 makes a unique array. Commented Oct 14, 2018 at 1:10
  • 1
    You show us your implementation of BookShelfViewModel and BookViewModel, but then ask why BookShelf isn't properly copying its books... How about showing us your implementation of BookShelf instead of these view model objects? Commented Oct 14, 2018 at 1:26
  • Woops, my bad. I've changed it. Commented Oct 14, 2018 at 1:41
  • @Alexander Are you sure about that? I've added some testcode to my post. Commented Oct 14, 2018 at 2:11
  • 1
    It would help if you would show all of the necessary code that actually compiles; We don't have the Book or Bookshelf definitions and you show originalArray as a let, so you can't add objects to it. Is Book a class or a struct? See how to create a minimal reproducible example. Why does your BookViewModel extract the Book properties? Why not make those properties computed variables that access the underlying Book's properties? Commented Oct 14, 2018 at 2:23

1 Answer 1

1

In your copying initialiser in BookShelfViewModel you don't actually clone the books array. You need to add self.books = original.books?.clone() to required init(original: BookShelfViewModel)

class BookShelfViewModel: Copying {
    var bookShelf: BookShelf

    var number: Int
    var books: [BookViewModel]?

    init(bookShelf: BookShelf) {
        self.bookShelf = bookShelf

        self.number = bookShelf.number
    }

    required init(original: BookShelfViewModel) {
        self.bookShelf = original.bookShelf
        self.books = original.books?.clone()
        self.number = original.number
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Because I fetch the bookshelf from an API (I don't have any control over the API), and afterwards I fetch the Books from the API, based on the number on the bookshelf. And I like my models to match the API's.
Your answer did the job btw! Thanks!
Ok, I get that, but then there is probably no reason to keep the original BookShelf object in the BookShelfViewModel, nor the original Book in the BookViewModel; those are just temporary objects that you use to get from the JSON to your model.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.