简体   繁体   English

为什么我的 SwiftUI 结构不能在视图外初始化?

[英]why can't my SwiftUI struct be initialised outside the View?

I couldn't get my the below struct to initialise until I moved it into the body of the View.在将下面的结构移入视图主体之前,我无法对其进行初始化。 Can someone explain that to me please?有人可以向我解释一下吗? Thanks!谢谢!

This didn't work:这没有用:

struct ContentView: View {
    var sampleText = "This is sample text"
    var booksArray = ["Book 1", "Book 2", "Book 3"]
    let aBook = Book(passage: sampleText, books: booksArray)
    
    var body: some View {
        ScrollView(.vertical, showsIndicators: false, content: {
            VStack {
                Text(aBook.passage)
                    .frame(width: 350, height: .infinity, alignment: .center)
                    .kerning(1)
            }
        })
    }
}

But this did work:但这确实有效:

struct ContentView: View {
    var sampleText = "This is sample text"
    var booksArray = ["Book 1", "Book 2", "Book 3"]
    
    var body: some View {
        let aBook = Book(passage: sampleText, books: booksArray)
        ScrollView(.vertical, showsIndicators: false, content: {
            VStack {
                Text(aBook.passage)
                    .frame(width: 350, height: .infinity, alignment: .center)
                    .kerning(1)
            }
        })
    }
}

The error you got from this code reads:您从这段代码中得到的错误是:

cannot use instance member 'sampleText' within property initializer;不能在属性初始值设定项中使用实例成员“sampleText”; property initializers run before 'self' is available属性初始值设定项在“self”可用之前运行

which in plain English means that when aBook is being assigned, self , which is the ContentView is not yet available, so you cannot use sampleText and booksArray to initialize aBook (because it requires all the properties to be initialized - to hold a value).用简单的英语来说,这意味着当aBook被分配时, self ,即ContentView尚不可用,因此您不能使用sampleTextbooksArray来初始化aBook (因为它需要初始化所有属性 - 以保存一个值)。

You might think, ok then I will use lazy to initialize aBook , which means that the assignment of the property will happen after ContentView has finished the initialization - at first access.你可能会想,好吧,那么我将使用lazy来初始化aBook ,这意味着属性的分配将在ContentView完成初始化之后发生——在第一次访问时。

lazy var aBook = Book(passage: sampleText, books: booksArray)

but then a new error appears:但随后出现了一个新错误:

Text(aBook.passage) <= cannot use mutating getter on immutable value: 'self' is immutable Text(aBook.passage) <= 不能对不可变值使用可变 getter:'self' 是不可变的

wait, what?等等,什么? But I'm not trying to mutate it you might say.但你可能会说,我并不是要改变它。

The reality though is that you do mutate ContentView by accessing aBook .但现实情况是,您确实通过访问aBook来改变ContentView Let's illustrate this:让我们来说明一下:

  1. sampleText is assigned a value sampleText被赋值
  2. booksArray is assigned a value booksArray被分配了一个值
  3. aBook is not assigned since is lazy . aBook没有分配,因为它很lazy Waits for access in order to be assigned a value.等待访问以分配一个值。
  4. ContentView is initalized ContentView已初始化
  5. You access aBook in the body您在正文中访问aBook
  6. aBook tries to assign a value, but because ContentView is a struct (value type - immutable) it needs to make a copy of the whole thing. aBook尝试分配一个值,但是因为ContentView是一个结构(值类型 - 不可变),所以它需要复制整个东西。 Which is why you get the error这就是你得到错误的原因

So, long story short you got a few options:所以,长话短说,你有几个选择:

  1. let aBook = Book(passage: sampleText, books: booksArray) in the body (as you already mention) let aBook = Book(passage: sampleText, books: booksArray)在正文中(正如您已经提到的)

  2. A computed property:计算属性:

    var aBook: Book { Book(passage: sampleText, books: booksArray) }

or a custom initializer:或自定义初始化程序:

init(sampleText: String, booksArray: [String]) {
    self.sampleText = sampleText
    self.booksArray = booksArray
    self.aBook      = Book(passage: sampleText, books: booksArray)
}

or even:甚至:

let sampleText = "This is sample text"
let booksArray = ["Book 1", "Book 2", "Book 3"]
let aBook: Book

init() {
    self.aBook = Book(passage: sampleText, books: booksArray)
}

I hope that this makes sense.我希望这是有道理的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM