24

At the line, dateFormatter.string(from: date), the compiler says:

Cannot use mutating getter on immutable value: 'self' is immutable
Mark method 'mutating' to make 'self' mutable

struct viewModel {
    
    private lazy var dateFormatter = { () -> DateFormatter in
        let formatter = DateFormatter()
        formatter.dateFormat = "MM/dd/yyyy"
        return formatter
    }()
    
    var labelText: String? {
        let date = Date()
        return dateFormatter.string(from: date)
    }
}

I understand what is written in this link, but the above situation is probably different.

Does anyone know how to get around this problem?

6
  • 3
    Why is it lazy in the first place? Do you really need lazy for creating a date formatter? Commented May 24, 2017 at 17:05
  • 1
    Lets just say my struct has many more properties and as creating DateFormatter is an expensive operation I want it to be lazy. Commented May 24, 2017 at 17:06
  • @AnandKumar Is it, though? Commented May 24, 2017 at 17:08
  • 1
    @Alexander Creating NSDateFormatter did used to be expensive. chibicode.org/?p=41 Commented May 24, 2017 at 17:11
  • @AnandKumar Now imagine a more realistic situation where creating the date formatter is say, 5% of the work, then all of a sudden you'll notice that the relative time increase will be tiny Commented May 24, 2017 at 17:17

2 Answers 2

30

You need a mutating get in order to perform mutations on self (such as accessing a lazy variable).

struct ViewModel {
    private lazy var dateFormatter = { () -> DateFormatter in
        let formatter = DateFormatter()
        formatter.dateFormat = "MM/dd/yyyy"
        return formatter
    }()

    var labelText: String? {
        mutating get {
            let date = Date()
            return dateFormatter.string(from: date)
        }
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

That is clever (I upvoted :-)), unfortunately, all 'instances' of such a struct have to be mutable, which could be counterproductive. In this case, I would prefer to define ViewModel as a class
@user3441734 I would do that too, if I had to use lazy vars. But this case really has no need for lazy vars at all.
Xcoode offers a fix if you already have a get (which is optional). The explanation was obscure, which brought me here. Upvoted for the clear "such as accessing lazy variable" - Of course! it's modifying self when lazy becomes instantiated.
@TonytheTech Happy to help :)
13

Accessing a lazy property on a struct mutates the struct to save the new property value on the struct, same as if you were changing a var variable on that property.

So you are not allowed to use lazy var in any circumstance where re-assigning the var after init would not be allowed.

This is rather unintuitive, as using lazy var doesn't "feel" like it is mutating the struct after assignment. But when you think about it, that's exactly what's happening.

Comments

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.