1

I come from an Objective C background and I'm normally used to declaring my properties (global variables to the class) inside the init method of a given class i.e. something like this:

-(instancetype) init {
   self = [super init];
   if(self){
      self.viewModel = [[MyViewModel alloc] init:self];
   }
   return self;
}

When self.viewModel is a property and I normally pass the a view controller as a parameter to the view model for callback purposes. I'm currently trying to do the same in swift.

I have a normal a custom view controller class, with the following init method:

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nil, bundle: nil)
        self.viewModel = SearchViewModel(callback: self)
    }

Now with the code above, xcode complains that

self.viewModel has not been initialised

However when I try initialise the viewModel i.e:

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        self.viewModel = SearchViewModel(callback: self)
        super.init(nibName: nil, bundle: nil)
    }

I then get

self used before super.init call

How would I sort this out in Swift?

4
  • Try using the viewDidLoad function. Commented Jun 18, 2016 at 16:28
  • To do that I would have to initialise the viewModel in the init method and then write a setter method to set the callback to the viewModel in the viewDidLoad method. Is this really the only solution? Commented Jun 18, 2016 at 16:30
  • You could / should declare viewModel to be of type SearchViewModel! for example and use the first code alternative. Commented Jun 18, 2016 at 16:31
  • luk2302 this makes the code work. Why is this the case? Commented Jun 18, 2016 at 16:32

2 Answers 2

2

First off: Swift initializers want all properties of self to be set up properly / to have a value before calling a super initializer.

Second off: You mustn't use self before the super.init-call because otherwise the properties that you would set in the super constructor are not yet set meaning whoever receives the non-finished self-instance can not be sure about the state of self.

Solution: Make viewModel of type SearchViewModel! and use the first code alternative.

Explanation: By making viewModel an implicitly unwrapped optional it implicitly contains nil in the beginning, therefore you can now call super.init and set an actual value to viewModel after that.

Sign up to request clarification or add additional context in comments.

Comments

1

The code you've written will never compile in Swift. The reason is that you can't pass self to SearchViewModel until self is fully initialized (i.e. has a value for all of its non-nil properties), but you can't fully initialize self without giving it a view model.

This is most likely a reference cycle, and you'll leak memory.

To fix this, make either the callback property of SearchViewModel optional, or the the viewModel property of your view controller optional. This permits you to fully initialize either without providing a reference until after the object is fully initialized, and allows you to make the reference weak, thereby preventing the reference cycle.

So you'd write weak var viewModel: SearchViewModel?, or weak var viewModel: SearchViewModel!, if you believe that SearchViewModel will never be nil when you dereference it, and are willing to run the risk of crashing.

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.