Force view that conforms to protocol to have a property wrapper in SwiftUI
Here are possible variants:
a) use stored property the same as in protocol (drawback: access via wrappedValue
)
struct MyView: DismissableView {
var isPresented: Binding<Bool>
var body: some View {
Text(isPresented.wrappedValue ? "Presented" : "Not")
}
}
- use internal variable with wrapper to conform to protocol (drawback: needed wrapper in each confirmed view)
struct MyView: DismissableView {
var isPresented: Binding<Bool> {
get { _presented }
set { _presented = newValue }
}
@Binding var presented: Bool
// optional init if needed to have MyView(isPresented: Binding<Bool>) interface
// init(isPresented: Binding<Bool>) {
// self._presented = isPresented
// }
var body: some View {
Text(presented ? "Presented" : "Not")
}
}
External usage in both cases is same.
Note: the @Binding var isPresented: Bool
property wrapper being unwrapped creates two properties (see below) that is why you cannot confirm it directly
var isPresented: Bool
var _isPresented: Binding<Bool>
How to define a protocol as a type for a @ObservedObject property?
Wrappers and stored properties are not allowed in swift protocols and extensions, at least for now. So I would go with the following approach mixing protocols, generics and classes... (all compilable and tested with Xcode 11.2 / iOS 13.2)
// base model protocol
protocol ItemViewModel: ObservableObject {
var title: String { get set }
func save()
func delete()
}
// generic view based on protocol
struct ItemView<Model>: View where Model: ItemViewModel {
@ObservedObject var viewModel: Model
var body: some View {
VStack {
TextField("Item Title", text: $viewModel.title)
Button("Save") { self.viewModel.save() }
}
}
}
// extension with default implementations
extension ItemViewModel {
var title: String {
get { "Some default Title" }
set { }
}
func save() {
// some default behaviour
}
func delete() {
// some default behaviour
}
}
// concrete implementor
class SomeItemModel: ItemViewModel {
@Published var title: String
init(_ title: String) {
self.title = title
}
}
// testing view
struct TestItemView: View {
var body: some View {
ItemView(viewModel: SomeItemModel("test"))
}
}
Swift - How to use KVO's 'observe' method on protocol
You can declare a function and apply the generic constraint to it.
In Swift 5.7 you can simply do:
func observeViewController(_ vc: some MyProtocol) {
vc.observe(\.observeMe, options: [.old, .new], changeHandler: { object, change in
})
}
Then you can call it:
let viewController = UIViewController()
if let observableViewController = viewController as? MyProtocol {
observeViewController(viewController)
}
Prior to Swift 5.7, some MyProtocol
is not supported and you need to use type erasure:
class AnyMyProtocol: MyProtocol & UIViewController {
var observeMe: Bool
private var base: MyProtocol
init(_ base: MyProtocol) {
self.base = base
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
func observeViewController(_ vc: MyProtocol) {
vc.observe(\.observeMe, options: [.old, .new], changeHandler: { object, change in
})
}
And call it like so:
let viewController = UIViewController()
observeViewController(vc: AnyMyProtocol(base: observableViewController))
By the way, you will receive a warning reading:
Passing reference to non-'@objc dynamic' property 'observeMe' to KVO method 'observe(_:options:changeHandler:)' may lead to unexpected behavior or runtime trap
But in your case you can't declare it as @objc
because an @objc
protocol can't inherit from a non-protocol type.
Related Topics
How to Make List with Single Selection with Swiftui
Sum Values of Properties Inside Array of Custom Objects Using Reduce
Swiftui .Rotationeffect() Framing and Offsetting
How to Resolve This Build Issue - Cannot Assign to Property: 'Date' Is a Get Only Property
Swift Difference Between Final Var and Non-Final Var | Final Let and Non-Final Let
How to Create Text File for Writing
Ycombinator Not Working in Swift
How Does Anyobject Conform to Nsobjectprotocol
Able to Write/Read File But Unable to Delete File Swift
Scene Created in Sprite Kit Level Editor Is Not Working
Propertywrappers and Protocol Declaration
Rxswift/Rxcocoa: Prevent Uitextfield from Having More Than ... Characters
Translucent Status Bar with No Navigation Bar
Xcode 8.2.1 Not Showing Documentation Description on Autocomplete