I am trying to invoke a mutating method in my View before render, how can I do that?
struct MyView : View {
mutating func update() { ... } // do something here
var body : some View {
self.update() // error, `self` is immutable
...
}
}
Related
SwiftUI errors like this appear frequently on StackOverflow:
Thread 1: Fatal error: No ObservableObject of type Foo found. A View.environmentObject(_:) for Foo may be missing as an ancestor of this view.
The answer is always to pass a Foo instance to a view's environmentObject() function. However, this does not appear to work when passing a subclass of Foo to environmentObject().
Foo.swift
class Foo: ObservableObject {
func doSomething() { ... }
}
Bar.swift
class Bar: Foo {
override func doSomething() { ... }
}
Views.swift
struct BrokenView: View {
#EnvironmentObject var foo: Foo
var body: some View { ... }
}
struct WorkingView: View {
#EnvironmentObject var foo: Bar
var body: some View { ... }
}
struct ParentView: View {
var body: some View {
BrokenView().environmentObject(Bar()) // No ObservableObject of type Foo found...
WorkingView().environmentObject(Bar()) // OK
}
}
Is there any way to use ObservableObject subclasses as environment objects?
Here is a solution (tested with Xcode 12.1 / iOS 14.1) - EnvironmentObject matches injection by explicit type.
var body: some View {
BrokenView().environmentObject(Bar() as Foo) // OK
WorkingView().environmentObject(Bar()) // OK
}
I would like to override a computed property with the type 'some View' in my subclass to return a different View but I'm getting this odd error:
open class A {
open var oneView: some View { ...
}
public class B : A {
public override var oneView: some View { ...
}
Property with type 'some View' cannot override a property with type
'some View'
How is it done properly?
You can wrap each one in AnyView. It works like so:
open class A {
open var oneView: AnyView {
AnyView(Text("A"))
}
}
public class B: A {
public override var oneView: AnyView {
AnyView(Text("B"))
}
}
If you want to have a VStack inside the view body for example, you just need to make sure to wrap it in AnyView.
I have the following classes shown below, legacy code. The goal I want to achieve is to ensure that the delegate method processUser is called with the user data passed. Second, I also want to ensure that the passed in Registration object's doRegister is called. My attemot is shown below for the delegate, but the test does not pass as it says, Too few invocations. I am using Groovy spock for testing version 1.2
class Invoker {
Delegate delegate;
Invoker(Delegate delegate) {
this.delegate = delegate;
}
void invoke(UserData user) {
delegate.processUser(user);
}
}
class Delegate {
private RegistrationService service;
Delegate (RegistrationService r) {
this.service = r;
}
void processUser(UserData data) {
service.doRegistration(data);
}
}
class DelegateSpec extends Specification {
Delegate delegate
RegistrationService registration
Invoker invoker
def setup() {
registration = Mock()
delegate = new Delegate(registration)
Invoker invoker = new Invoker(delegate)
}
def "Invoker should invoke delegate passed to it"() {
given:
UserData u = ....
when:
invoker.invoke(u)
then:
1* delegate.processUser(u)
}
}
First let me provide a fully consistent set of classes in order to be able to compile the application code:
package de.scrum_master.stackoverflow.q59366025;
public class UserData {}
package de.scrum_master.stackoverflow.q59366025;
public class RegistrationService {
public void doRegistration(UserData data) {}
}
package de.scrum_master.stackoverflow.q59366025;
class Delegate {
private RegistrationService service;
Delegate (RegistrationService r) {
this.service = r;
}
void processUser(UserData data) {
service.doRegistration(data);
}
}
package de.scrum_master.stackoverflow.q59366025;
class Invoker {
Delegate delegate;
Invoker(Delegate delegate) {
this.delegate = delegate;
}
void invoke(UserData user) {
delegate.processUser(user);
}
}
Now as for your test, you are making it more complicated than necessary and there is also a logical error:
If the Delegate is not mock or spy, you cannot check interactions like 1 * on it.
So just make it a mock, then you also do not need to inject its RegistrationService dependency anymore - which is the whole point of creating a mock.
package de.scrum_master.stackoverflow.q59366025
import spock.lang.Specification
class DelegateSpec extends Specification {
def delegate = Mock(Delegate)
def invoker = new Invoker(delegate)
def "Invoker should invoke delegate passed to it"() {
given:
def userData = new UserData()
when:
invoker.invoke(userData)
then:
1 * delegate.processUser(userData)
}
}
When I set up notification in Swift 3, I can declare the selector with or without the class prefix. In both cases, the method is an instance method. What's the difference between prefixing the class vs not? What if the selector should be pointing a class method instead?
class Test : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(fresh), name: .refresh, object: nil)
}
func refresh() {
}
}
vs
class Test : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(Test.fresh), name: .refresh, object: nil)
}
func refresh() {
}
}
I am pretty new to MVVM and C++ (managed), and am trying to access my viewmodel object outside of the MainPage constructor.
MainPage::MainPage()
{
InitializeComponent();
//Create ViewModel object
ViewModel ^myViewModel;
myViewModel = ref new ViewModel;
}
ref class ViewModel
{
ViewModel::ViewModel() //Constructor
{
//Create array
const size_t SIZE = 6;
Point arr[SIZE];
}
void ViewModel::doDraw()
{
}
void profileDisplay::MainPage::myButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
myViewModel->doDraw();
}
}
Visual Studio Intellisense reports that my myViewModel under my _Click event is undefined. This seems like it would be a basic problem, but I seem to be hung up on it. Any help is much appreciated!