NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

SOLVED: How to initialize variables that depend on other variables in views?

Forums > SwiftUI

Hi folks,

I'm trying to create something like the following:

struct someView: View {
   @FetchRequest(sortDescriptors: [SortDescriptor(\.date)]) var books: FetchedResults<Book>
   let bookCategories = BookCategories.booksByDate(books: books)

   var body: some View {
       // ...
     }
}

The problem is that bookCategories line returns the following error.

Cannot use instance member 'todos' within property initializer; property initializers run before 'self' is available

It works successfully if I place let bookCategories = inside the body, but somehow that seems...inelegant(?) Is that the done way?

Similarly, I can get it working by creating an initializer, but I have to:

  • Initialize the fetchrequest inside the init too
  • Assign a default value to bookCategories
  • Therefore, change bookCategories from let to var

All of which seems clumsy.

So I guess the short version of this question is: how do you elegantly initialize variables that rely on other variables?

   

You can't use variables of property wrappers inside init of a View. Explanation is here.

What you can do is: Fill the variables with the .onAppear modifier.

   

Hi @Hatsushira - thanks for the response. I like the idea, but moving the let bookCategories... to a .onAppear on the list gives a "cannot find bookCategories in scope" error when referencing it?

   

@Bnerd  

Hello @baggage, Hatsuhira didn't say to place the "let bookCategories" in the .onAppear, what he meant is

change your let into a var (keep it in the main struct not in the body)

var bookCategories: BookCategories

and in the .onAppear add

bookCategories = BookCategories.booksByDate(books: books)
// or
bookCategories = .booksBydate(books: books)

That's the best I can guess with the code you presented :)

   

hi @baggage,

i don't know exactly the context of your view or your app, but the bookCategories property depends on the books array ... and because this books array, being defined by a FetchRequest, may change over time (when changes to any of its elements are made elsewhere in your view, or even elsewhere in you app while the view is on screen), you probably don't want to use a let to define bookCategories.

also, you won't be able to set a variable defined by let or var in an .onAppear ... you can only manipulate @State variables after the view is initialized.

a better choice would be to use a computed variable:

var bookCategories: TheTypeReturnedByThisExpression { 
  BookCategories.booksByDate(books: books) 
}

where TheTypeReturnedByThisExpression is whatever type is returned by the booksByDate function defined on BookCategories. i am guessing this is some sort of array type.

hope that helps,

DMG

   

@delawaremathguy Ach - can't believe I didn't think of that! You're right of course. Many thanks, much appreciated!

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.