BuildできるのにPreviewがクラッシュする

# 環境
- Xcode 15.2
- Swift 5.9

# 条件

以下4要素
- `親View`
- `子View`
- `ObservableObjectなprotocol`
- `protocolに準拠したclass`

が次のような構成になっているとき
- `親View`は`ObservableObjectに準拠するprotocolのGeneric型`を受け取る
- `親View`は`GenericなViewを受け取る子View`を内部で宣言する
- 親Viewは自身のbodyを構成するのに子Viewを使う

（ややこしい）


# 失敗例

``` Preview失敗.swift
protocol Presentation: ObservableObject {
  var text: String { get }
}

class MockPresenter: Presentation {
  var text = "aaa"
}

struct TestView<P: Presentation>: View {
  @StateObject var presenter: P
  var body: some View {
    WrapView {
      Text(presenter.text)
    }
  }

  struct WrapView<C: View>: View { // `GenericなViewを受け取る子View`が親Viewにネストされている
    let content: () -> C
    init(content: @escaping () -> C) {
      self.content = content
    }
    var body: some View {
      content()
    }
  }
}

#Preview {
  TestView(presenter: MockPresenter())
}
```

<img width="200" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/bd6707f3-6135-64f8-15df-79f33fefd7c8.png">


# 成功例

```Preview成功.swift
protocol Presentation: ObservableObject {
  var text: String { get }
}

class MockPresenter: Presentation {
  var text = "aaa"
}

struct TestView<P: Presentation>: View {
  @StateObject var presenter: P
  var body: some View {
    WrapView {
      Text(presenter.text)
    }
  }
}

struct WrapView<C: View>: View { // 子Viewの宣言を親Viewの外に移動しただけ
  let content: () -> C
  init(content: @escaping () -> C) {
    self.content = content
  }
  var body: some View {
    content()
  }
}

#Preview {
  TestView(presenter: MockPresenter())
}
```

<img width="200" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/639141c7-8e3b-1145-c583-5bcdc4c32a4f.png">

# 原因
調べたけれどよくわかりませんでした。いかがでしたか？
（ありがちなキュレーションサイトみたいになってしまいすみません。とりあえず似た状態になった人の役にたてるかも、と問題の共有のために本記事を公開します。）
PreviewのためのBuildは通常のBuildとは異なる過程を経るとどこかで聞いた気もするので関係がありそうです。

なお、SlackOverflowやApple Developper Forumにも同様な例は見当たりませんでした。
Previewのクラッシュは`environmentObject`や`CoreData`, `SwiftData`あたりではよく発生するようですね。
何かご存知の方がいらっしゃいましたらぜひご共有いただきたいです。


# 追記

またGenericsが関わっていそうなBuildはできてもPreviewできないパターンを見つけました。
ログを見ると
`error: cannot find 'WrapView' in scope`
とのエラーが出ていました。

これに関しては次の記事が同様の指摘をしています。

https://forums.developer.apple.com/forums/thread/739814

「SwiftにNameSpaceはないんだ！（だからViewをネストするな）」という意見と、「buildが通って実際に動くのにpreviewだけ動かないなら、それはpreviewのバグだ」という意見で対立しているようです。

```swift
import SwiftUI

enum NameSpace {
    struct TestView: View {
        var body: some View {
            WrapView {
                Text("a")
            }
        }
    }

    struct WrapView<C: View>: View {
        let content: () -> C
        init(content: @escaping () -> C) {
            self.content = content
        }
        var body: some View {
            content()
        }
    }
}

#Preview {
    NameSpace.TestView()
}

```

次のようにView protocol以外のprotocolでも同様にpreviewできません。

```swift
    struct WrapView<T: Equatable>: View {
        let a: T
        let b: T
        var body: some View {
            Text("\({a == b}().description)")
        }
    }
```

以下ならPreviewできる。
```diff_swift
    struct TestView: View {
        var body: some View {
-           WrapView {
+           NameSpace.WrapView {
                Text("a")
            }
        }
    }
```

あるいは`WrapView`を`TestView`にネストしてもPreviewできます。

---

子ViewがGenericな型を受け取らない場合は、親viewで呼び出すときに`NameSpace.`と指定しなくても問題なくpreviewできます。
```swift
import SwiftUI

enum NameSpace {
    struct TestView: View {
        var body: some View {
            WrapView() // NameSpace.WrapView()としなくてもpreviewできる
        }
    }

    struct WrapView: View {
        var body: some View {
            Text("a")
        }
    }
}

#Preview {
    NameSpace.TestView()
}
```