Add `print` statements to reproduce the issue

This commit is contained in:
Max Desiatov 2021-02-05 17:57:56 +00:00
parent eeddfe9e4b
commit 63e4f84bd0
No known key found for this signature in database
GPG Key ID: FE08EBF9CF58CBA2
6 changed files with 69 additions and 35 deletions

View File

@ -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")
}
}

View File

@ -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")
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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])
}

View File

@ -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()