Add `print` statements to reproduce the issue
This commit is contained in:
parent
eeddfe9e4b
commit
63e4f84bd0
|
@ -80,7 +80,9 @@ final class MountedCompositeView<R: Renderer>: MountedCompositeElement<R> {
|
|||
}
|
||||
|
||||
override func update(with reconciler: StackReconciler<R>) {
|
||||
print("C.render")
|
||||
let element = reconciler.render(compositeView: self)
|
||||
print("C.recon")
|
||||
reconciler.reconcile(
|
||||
self,
|
||||
with: element,
|
||||
|
@ -91,5 +93,6 @@ final class MountedCompositeView<R: Renderer>: MountedCompositeElement<R> {
|
|||
},
|
||||
mountChild: { $0.makeMountedView(parentTarget, environmentValues, self) }
|
||||
)
|
||||
print("C.done")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ public class MountedElement<R: Renderer> {
|
|||
case .view:
|
||||
environmentValues.inject(into: &view.view, type)
|
||||
}
|
||||
print("updateEnvironment done")
|
||||
}
|
||||
|
||||
func mount(
|
||||
|
@ -160,10 +161,12 @@ public class MountedElement<R: Renderer> {
|
|||
|
||||
extension EnvironmentValues {
|
||||
mutating func inject(into element: inout Any, _ type: Any.Type) {
|
||||
print("Inj.typeInfo")
|
||||
guard let info = typeInfo(of: type) else { return }
|
||||
|
||||
// Extract the view from the AnyView for modification, apply Environment changes:
|
||||
if let container = element as? ModifierContainer {
|
||||
print("Inj.container")
|
||||
container.environmentModifier?.modifyEnvironment(&self)
|
||||
}
|
||||
|
||||
|
@ -174,19 +177,26 @@ extension EnvironmentValues {
|
|||
for dynamicProp in info.properties.filter({ $0.type is DynamicProperty.Type }) {
|
||||
guard let propInfo = typeInfo(of: dynamicProp.type) else { return }
|
||||
var propWrapper = dynamicProp.get(from: element) as! DynamicProperty
|
||||
print("Inj.prop.pi \(propInfo.properties.count)")
|
||||
for prop in propInfo.properties.filter({ $0.type is EnvironmentReader.Type }) {
|
||||
var wrapper = prop.get(from: propWrapper) as! EnvironmentReader
|
||||
print("*****Inj.prop.pi.prop.setC *****")
|
||||
wrapper.setContent(from: self)
|
||||
print("*****Inj.prop.pi.prop.set *****")
|
||||
prop.set(value: wrapper, on: &propWrapper)
|
||||
}
|
||||
print("***** Inj.prop.dynamic.set \(dynamicProp.type) *****")
|
||||
dynamicProp.set(value: propWrapper, on: &element)
|
||||
}
|
||||
for prop in info.properties.filter({ $0.type is EnvironmentReader.Type }) {
|
||||
var wrapper = prop.get(from: element) as! EnvironmentReader
|
||||
print("***** Inj.prop.env.setC \(wrapper) *****")
|
||||
wrapper.setContent(from: self)
|
||||
print("***** Inj.prop.env.set \(prop.type) *****")
|
||||
prop.set(value: wrapper, on: &element)
|
||||
}
|
||||
// swiftlint:enable force_cast
|
||||
print("Inj.done")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,15 +83,25 @@ public final class MountedHostView<R: Renderer>: MountedElement<R> {
|
|||
}
|
||||
}
|
||||
|
||||
private var __mountedChild = 0
|
||||
|
||||
override func update(with reconciler: StackReconciler<R>) {
|
||||
guard let target = target else { return }
|
||||
|
||||
let myStack = __stack
|
||||
__stack += 1
|
||||
|
||||
print("Host.upEnv")
|
||||
updateEnvironment()
|
||||
target.view = view
|
||||
print(
|
||||
"Host.renderer?.update \(reconciler.renderer == nil ? "nil" : "\(Swift.type(of: reconciler.renderer!))")"
|
||||
)
|
||||
reconciler.renderer?.update(target: target, with: self)
|
||||
|
||||
var childrenViews = view.children
|
||||
|
||||
print("Host(\(mountedChildren.isEmpty),\(childrenViews.isEmpty)")
|
||||
switch (mountedChildren.isEmpty, childrenViews.isEmpty) {
|
||||
// if existing children present and new children array is empty
|
||||
// then unmount all existing children
|
||||
|
@ -113,10 +123,17 @@ public final class MountedHostView<R: Renderer>: MountedElement<R> {
|
|||
// run simple update
|
||||
while let mountedChild = mountedChildren.first, let childView = childrenViews.first {
|
||||
let newChild: MountedElement<R>
|
||||
print(
|
||||
"BEGIN todo: \(myStack).\(mountedChildren.count) \(childView.typeConstructorName == mountedChildren[0].view.typeConstructorName ? "a - \(childView.typeConstructorName)" : "b")"
|
||||
)
|
||||
__mountedChild += 1
|
||||
if childView.typeConstructorName == mountedChildren[0].view.typeConstructorName {
|
||||
mountedChild.environmentValues = environmentValues
|
||||
mountedChild.view = childView
|
||||
mountedChild.updateEnvironment()
|
||||
print(
|
||||
"update -> \(Swift.type(of: mountedChild)), recon -> \(Swift.type(of: reconciler)))"
|
||||
)
|
||||
mountedChild.update(with: reconciler)
|
||||
newChild = mountedChild
|
||||
} else {
|
||||
|
@ -131,6 +148,8 @@ public final class MountedHostView<R: Renderer>: MountedElement<R> {
|
|||
newChildren.append(newChild)
|
||||
mountedChildren.removeFirst()
|
||||
childrenViews.removeFirst()
|
||||
|
||||
print("END mountedChild todo: \(myStack).\(mountedChildren.count)")
|
||||
}
|
||||
|
||||
// more mounted views left than views were to be rendered:
|
||||
|
@ -150,6 +169,7 @@ public final class MountedHostView<R: Renderer>: MountedElement<R> {
|
|||
}
|
||||
}
|
||||
|
||||
__stack -= 1
|
||||
mountedChildren = newChildren
|
||||
|
||||
// both arrays are empty, nothing to reconcile
|
||||
|
@ -157,3 +177,5 @@ public final class MountedHostView<R: Renderer>: MountedElement<R> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var __stack = 0
|
||||
|
|
|
@ -50,8 +50,12 @@ public struct TypeInfo {
|
|||
|
||||
public func typeInfo(of type: Any.Type) -> TypeInfo? {
|
||||
guard Kind(type: type) == .struct else {
|
||||
print("TypeInfo: nil")
|
||||
return nil
|
||||
}
|
||||
|
||||
return StructMetadata(type: type).toTypeInfo()
|
||||
print("TypeInfo: \(type)")
|
||||
let result = StructMetadata(type: type).toTypeInfo()
|
||||
print("TypeInfo.done")
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -206,27 +206,35 @@ public final class StackReconciler<R: Renderer> {
|
|||
body bodyKeypath: ReferenceWritableKeyPath<MountedCompositeElement<R>, Any>,
|
||||
result: KeyPath<MountedCompositeElement<R>, (Any) -> T>
|
||||
) -> T {
|
||||
print("SR.env")
|
||||
compositeElement.updateEnvironment()
|
||||
print("SR.type")
|
||||
if let info = typeInfo(of: compositeElement.type) {
|
||||
var stateIdx = 0
|
||||
print("SR.dynamicProps")
|
||||
let dynamicProps = info.dynamicProperties(
|
||||
&compositeElement.environmentValues,
|
||||
source: &compositeElement[keyPath: bodyKeypath]
|
||||
)
|
||||
print("SR.dynamicProps.done")
|
||||
|
||||
compositeElement.transientSubscriptions = []
|
||||
for property in dynamicProps {
|
||||
print("SR.begin")
|
||||
// Setup state/subscriptions
|
||||
if property.type is ValueStorage.Type {
|
||||
print("SR.setup storage")
|
||||
setupStorage(id: stateIdx, for: property, of: compositeElement, body: bodyKeypath)
|
||||
stateIdx += 1
|
||||
}
|
||||
if property.type is ObservedProperty.Type {
|
||||
print("SR.setup sub")
|
||||
setupTransientSubscription(for: property, of: compositeElement, body: bodyKeypath)
|
||||
}
|
||||
print("SR.done")
|
||||
}
|
||||
}
|
||||
|
||||
print("SR.type.done")
|
||||
return compositeElement[keyPath: result](compositeElement[keyPath: bodyKeypath])
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +1,27 @@
|
|||
// Copyright 2020 Tokamak contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import TokamakShim
|
||||
|
||||
@available(OSX 10.16, iOS 14.0, *)
|
||||
struct CustomScene: Scene {
|
||||
@Environment(\.scenePhase) private var scenePhase
|
||||
|
||||
struct TokamakApp: App {
|
||||
var body: some Scene {
|
||||
print("In CustomScene.body scenePhase is \(scenePhase)")
|
||||
return WindowGroup("Tokamak Demo") {
|
||||
TokamakDemoView()
|
||||
WindowGroup("Spooky Hanger") {
|
||||
NavigationView {
|
||||
List {
|
||||
ForEach(["Section"], id: \.self) { section in
|
||||
Section(header: Text(section).font(.headline)) {
|
||||
ForEach(["Item 1"], id: \.self) { childRow in
|
||||
NavigationLink(
|
||||
destination: Text(childRow).padding([.leading, .trailing])
|
||||
) {
|
||||
Text(childRow)
|
||||
}
|
||||
.padding(.leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(SidebarListStyle())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(OSX 10.16, iOS 14.0, *)
|
||||
struct TokamakDemoApp: App {
|
||||
var body: some Scene {
|
||||
CustomScene()
|
||||
}
|
||||
}
|
||||
|
||||
// If @main was supported for executable Swift Packages,
|
||||
// this would match SwiftUI 100%
|
||||
if #available(OSX 10.16, iOS 14.0, *) {
|
||||
TokamakDemoApp.main()
|
||||
}
|
||||
TokamakApp.main()
|
||||
|
|
Loading…
Reference in New Issue