Last active
February 18, 2020 09:03
-
-
Save DevAndArtist/053ac16082442cae14a911a5ec6c9d0b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SOME OBSERVATIONS: | |
// * In Xcode 11.3.1 `V_Struct_Representable_ObservedObject` won't update | |
// which is clearly a bug. This bug is fixed in Xcode 11.4 beta 1. | |
// | |
// * `V_Struct` and `V_Struct_Representable` both never update because | |
// they shouldn't as the framework internal raw-diffing likely won't | |
// identify any change. (EXPECTED BEHAVIOR) | |
// | |
// * `V_Class` and `V_Class_ObservedObject` both produce a runtime crash, | |
// which might be a bug as well. `View` conforming types shouldn't be | |
// classes, yet both `UIViewRepresentable` and | |
// `UIViewControllerRepresentable` can be classes and they don't crash. | |
// Therefore this seems like another bug. | |
// | |
import Combine | |
import SwiftUI | |
import UIKit | |
// Helper | |
func createUILabel() -> UILabel { | |
let label = UILabel() | |
label.textAlignment = .center | |
return label | |
} | |
func log<T>(_ t: T, function: StaticString = #function) { | |
print("\(function) πΈ \(type(of: t))") | |
} | |
func log<T>(_ t: T, function: StaticString = #function) where T: AnyObject { | |
print("\(function) πΉ \(type(of: t)) πΉ \(ObjectIdentifier(t))") | |
} | |
protocol P: View { | |
init(model: Model) | |
} | |
class VC: UIViewController { | |
let label = createUILabel() | |
override func loadView() { | |
view = label | |
} | |
} | |
// Model | |
class Model: ObservableObject { | |
let objectWillChange = ObservableObjectPublisher() | |
var count = 0 { | |
willSet { | |
objectWillChange.send() | |
} | |
} | |
var _timer: Timer? | |
init() { | |
self._timer = Timer.scheduledTimer( | |
timeInterval: 2, | |
target: self, | |
selector: #selector(_countUp), | |
userInfo: nil, | |
repeats: true | |
) | |
} | |
@objc | |
func _countUp() { | |
count += 1 | |
} | |
} | |
// Different view structs | |
struct V_Struct: View, P { | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
var body: some View { | |
log(self) | |
return Text("\(model.count)") | |
} | |
} | |
struct V_Struct_ObservedObject: View, P { | |
@ObservedObject | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
var body: some View { | |
log(self) | |
return Text("\(model.count)") | |
} | |
} | |
struct V_Struct_Representable: UIViewRepresentable, P { | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
func makeUIView(context: Context) -> UILabel { | |
log(self) | |
return createUILabel() | |
} | |
func updateUIView(_ uiView: UILabel, context: Context) { | |
log(self) | |
uiView.text = "\(model.count)" | |
} | |
} | |
struct V_Struct_Representable_ObservedObject: UIViewRepresentable, P { | |
@ObservedObject | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
func makeUIView(context: Context) -> UILabel { | |
log(self) | |
return createUILabel() | |
} | |
func updateUIView(_ uiView: UILabel, context: Context) { | |
log(self) | |
uiView.text = "\(model.count)" | |
} | |
} | |
// Different view classes | |
final class V_Class: View, P { | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
deinit { | |
log(self) | |
} | |
var body: some View { | |
log(self) | |
return Text("\(model.count)") | |
} | |
} | |
final class V_Class_ObservedObject: View, P { | |
@ObservedObject | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
deinit { | |
log(self) | |
} | |
var body: some View { | |
log(self) | |
return Text("\(model.count)") | |
} | |
} | |
final class V_Class_Representable: UIViewRepresentable, P { | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
deinit { | |
log(self) | |
} | |
func makeUIView(context: Context) -> UILabel { | |
log(self) | |
return createUILabel() | |
} | |
func updateUIView(_ uiView: UILabel, context: Context) { | |
log(self) | |
uiView.text = "\(model.count)" | |
} | |
} | |
final class V_Class_Representable_ObservedObject: UIViewRepresentable, P { | |
@ObservedObject | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
deinit { | |
log(self) | |
} | |
func makeUIView(context: Context) -> UILabel { | |
log(self) | |
return createUILabel() | |
} | |
func updateUIView(_ uiView: UILabel, context: Context) { | |
log(self) | |
uiView.text = "\(model.count)" | |
} | |
} | |
final class VC_Class_Representable: UIViewControllerRepresentable, P { | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
deinit { | |
log(self) | |
} | |
func makeUIViewController(context: Context) -> VC { | |
log(self) | |
return VC() | |
} | |
func updateUIViewController(_ uiViewController: VC, context: Context) { | |
log(self) | |
uiViewController.label.text = "\(model.count)" | |
} | |
} | |
final class VC_Class_Representable_ObservedObject: | |
UIViewControllerRepresentable, | |
P | |
{ | |
@ObservedObject | |
var model: Model | |
init(model: Model) { | |
self.model = model | |
log(self) | |
} | |
deinit { | |
log(self) | |
} | |
func makeUIViewController(context: Context) -> VC { | |
log(self) | |
return VC() | |
} | |
func updateUIViewController(_ uiViewController: VC, context: Context) { | |
log(self) | |
uiViewController.label.text = "\(model.count)" | |
} | |
} | |
// Test | |
struct ContentView: View { | |
@ObservedObject | |
var model: Model = Model() | |
func create<T>(_ tType: T.Type) -> some View where T: P { | |
VStack | |
.init { | |
Text(String(describing: tType)).font(.system(size: 10)) | |
tType.init(model: model).frame(width: 100, height: 20) | |
} | |
.border(Color.red) | |
.fixedSize() | |
} | |
var body: some View { | |
print("\nπ’", #function, type(of: self), "\n") | |
return VStack { | |
Group { | |
Text("value views") | |
create(V_Struct.self) | |
create(V_Struct_ObservedObject.self) | |
create(V_Struct_Representable.self) | |
create(V_Struct_Representable_ObservedObject.self) | |
} | |
Group { | |
Text("object views") | |
// Runtime crash: EXC_BAD_INSTRUCTION | |
// create(V_Class.self) | |
// create(V_Class_ObservedObject.self) | |
create(V_Class_Representable.self) | |
create(V_Class_Representable_ObservedObject.self) | |
create(VC_Class_Representable.self) | |
create(VC_Class_Representable_ObservedObject.self) | |
} | |
} | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
ContentView() | |
} | |
} | |
/* SOME CYCLES IN XCODE 11.3.1: | |
π’ body ContentView | |
init(model:) πΈ V_Struct | |
init(model:) πΈ V_Struct_ObservedObject | |
init(model:) πΈ V_Struct_Representable | |
init(model:) πΈ V_Struct_Representable_ObservedObject | |
init(model:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x000060000025fba0) | |
init(model:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238660) | |
init(model:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238760) | |
init(model:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x00006000002382a0) | |
body πΈ V_Struct | |
body πΈ V_Struct_ObservedObject | |
makeUIView(context:) πΈ V_Struct_Representable | |
updateUIView(_:context:) πΈ V_Struct_Representable | |
makeUIView(context:) πΈ V_Struct_Representable_ObservedObject | |
updateUIView(_:context:) πΈ V_Struct_Representable_ObservedObject | |
makeUIView(context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x000060000025fba0) | |
updateUIView(_:context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x000060000025fba0) | |
makeUIView(context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238660) | |
updateUIView(_:context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238660) | |
makeUIViewController(context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238760) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238760) | |
makeUIViewController(context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x00006000002382a0) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x00006000002382a0) | |
π’ body ContentView | |
init(model:) πΈ V_Struct | |
init(model:) πΈ V_Struct_ObservedObject | |
init(model:) πΈ V_Struct_Representable | |
init(model:) πΈ V_Struct_Representable_ObservedObject | |
init(model:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600000238da0) | |
init(model:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238f20) | |
init(model:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238f40) | |
init(model:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238f80) | |
body πΈ V_Struct_ObservedObject | |
updateUIView(_:context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600000238da0) | |
updateUIView(_:context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238f20) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238f40) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238f80) | |
deinit πΉ V_Class_Representable πΉ ObjectIdentifier(0x000060000025fba0) | |
deinit πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238660) | |
deinit πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238760) | |
deinit πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x00006000002382a0) | |
π’ body ContentView | |
init(model:) πΈ V_Struct | |
init(model:) πΈ V_Struct_ObservedObject | |
init(model:) πΈ V_Struct_Representable | |
init(model:) πΈ V_Struct_Representable_ObservedObject | |
init(model:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600000238660) | |
init(model:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000239540) | |
init(model:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238760) | |
init(model:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x00006000002384c0) | |
body πΈ V_Struct_ObservedObject | |
updateUIView(_:context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600000238660) | |
updateUIView(_:context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000239540) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238760) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x00006000002384c0) | |
deinit πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600000238da0) | |
deinit πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238f20) | |
deinit πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600000238f40) | |
deinit πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600000238f80) | |
*/ | |
/* SOME CYCLES IN XCODE 11.4 beta 1: | |
π’ body ContentView | |
init(model:) πΈ V_Struct | |
init(model:) πΈ V_Struct_ObservedObject | |
init(model:) πΈ V_Struct_Representable | |
init(model:) πΈ V_Struct_Representable_ObservedObject | |
init(model:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ecc0) | |
init(model:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ec40) | |
init(model:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ed00) | |
init(model:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ece0) | |
body πΈ V_Struct | |
body πΈ V_Struct_ObservedObject | |
makeUIView(context:) πΈ V_Struct_Representable | |
updateUIView(_:context:) πΈ V_Struct_Representable | |
makeUIView(context:) πΈ V_Struct_Representable_ObservedObject | |
updateUIView(_:context:) πΈ V_Struct_Representable_ObservedObject | |
makeUIView(context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ecc0) | |
updateUIView(_:context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ecc0) | |
makeUIView(context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ec40) | |
updateUIView(_:context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ec40) | |
makeUIViewController(context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ed00) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ed00) | |
makeUIViewController(context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ece0) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ece0) | |
π’ body ContentView | |
init(model:) πΈ V_Struct | |
init(model:) πΈ V_Struct_ObservedObject | |
init(model:) πΈ V_Struct_Representable | |
init(model:) πΈ V_Struct_Representable_ObservedObject | |
init(model:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d94340) | |
init(model:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d94300) | |
init(model:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d94440) | |
init(model:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d943a0) | |
body πΈ V_Struct_ObservedObject | |
updateUIView(_:context:) πΈ V_Struct_Representable_ObservedObject | |
updateUIView(_:context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d94340) | |
updateUIView(_:context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d94300) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d94440) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d943a0) | |
deinit πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ecc0) | |
deinit πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ec40) | |
deinit πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d8ed00) | |
deinit πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d8ece0) | |
π’ body ContentView | |
init(model:) πΈ V_Struct | |
init(model:) πΈ V_Struct_ObservedObject | |
init(model:) πΈ V_Struct_Representable | |
init(model:) πΈ V_Struct_Representable_ObservedObject | |
init(model:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d94800) | |
init(model:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d94480) | |
init(model:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d948a0) | |
init(model:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d948c0) | |
body πΈ V_Struct_ObservedObject | |
updateUIView(_:context:) πΈ V_Struct_Representable_ObservedObject | |
updateUIView(_:context:) πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d94800) | |
updateUIView(_:context:) πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d94480) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d948a0) | |
updateUIViewController(_:context:) πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d948c0) | |
deinit πΉ V_Class_Representable πΉ ObjectIdentifier(0x0000600002d94340) | |
deinit πΉ V_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d94300) | |
deinit πΉ VC_Class_Representable πΉ ObjectIdentifier(0x0000600002d94440) | |
deinit πΉ VC_Class_Representable_ObservedObject πΉ ObjectIdentifier(0x0000600002d943a0) | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment