Search code examples
swiftlazy-initializationcomputed-propertiesdidsetproperty-observer

Swift can lazy, get and didSet together


Can we do get and didSet together with lazy keyword. I have an array it fetch data from database (get) and another thing when that array will modify i will call delegate to reload data in didSet.

Its not working and not complain of any error.

  class CoreDataManager {
        func fetchUsers() -> [UserEntity] {
            var users: [UserEntity] = []
            do {
                users = try! context.fetch(UserEntity.fetchRequest())
            }catch {
                print("Fetch user Error,", error)
            }
            return users
        }
    }


    protocol UserControllerToViewModel: AnyObject {
        func reloadData()
    }


    class UserViewModel {
                
        private var manager = CoreDataManager()
        weak var delegate: UserControllerToViewModel?
// Here I want to get users and didset together with lazy keyword but its not working
        lazy var users: [UserEntity] = manager.fetchUsers() {
            didSet {
                delegate?.reloadData()
            }
        }
        
    }

Demo GitHub Project link: https://github.com/YogeshPateliOS/TableView_MVVM.git


Solution

  • As @EmilioPelaez said, the first time you access the lazy property you will be initialising it so the didSet won't be called.

    This can be demonstrated by the following simplification of your example code:

    func getData() -> [Int] {
       [1,2,3,4,5]
    }
    
    class UserViewModel {
       
       lazy var users = getData() {
          didSet {
             print("didSetting")
          }
       }
    }
    
    let vm = UserViewModel()
    
    print(vm.users)
    
    vm.users = [5,6,7,8]
    
    print(vm.users)
    

    This gives the output:

    [1, 2, 3, 4, 5]
    didSetting
    [5, 6, 7, 8]
    

    demonstrating that the didSet is only called when the property is being modified and not when being initialised.

    EDIT:

    To demonstrate that where the method that initialises the lazy var exists is irrelevant. Replace the above code with the below and the output is exactly the same; didSet won't be run on the first initialisation.

    class Manager {
       func getData() -> [Int] {
          [1,2,3,4,5]
       }
    }
    
    class UserViewModel {
       let manager = Manager()
       lazy var users = manager.getData() {
          didSet {
             print("didSetting")
          }
       }
    }
    
    let vm = UserViewModel()
    print(vm.users)
    vm.users = [5,6,7,8]
    print(vm.users)