Xamarin.iOS issue after update

twt_msetwt_mse Member ✭✭
edited October 10 in Xamarin.iOS

Hi,

I have an issue with an iOS project after updating Visual Studio and Xcode to the following Versions:

  • Visual Studio Community 2019 for Mac: Version 8.3.2 (build 32)
  • Xamarin.iOS: Version: 13.2.0.47 (Visual Studio Community)
  • xCode: 11.0

The actual issue:

Two ViewController „A“ and „B“ are set up in the storyboard of the app, with a segue from „A“ to „B“.
„B“ is loaded in the ViewDidLoad of „A“ with the following line:

PerformSegue(„SegueToB“, Self);

Then two instances of ViewController „B“ are created. This causes follow up errors, because the second instance is not initialized correctly. But why is it even there? Putting a breakpoint in the constructor of „B“ shows the following stack trace:

1. instance:

MyApp.iOS.ViewController_B..ctor(System.IntPtr handle) in /Users/xx/myapp/myapp.iOS/ViewController/ViewController_B:13

ObjCRuntime.Messaging.void_objc_msgSendSuper_IntPtr_IntPtr() in
UIKit.UIViewController.PerformSegue(string identifier, Foundation.NSObject sender) in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.2.0.47/src/Xamarin.iOS/UIViewController.g.cs:669
MyApp.ViewController_A.ViewDidLoad() in /Users/xx/myapp/myapp.iOS/ViewController/ViewController_A.cs:72

2. instance:

MyApp.iOS.ViewController_B..ctor(System.IntPtr handle) in /Users/xx/myapp/myapp.iOS/ViewController/ViewController_B:13
System.Reflection.RuntimeConstructorInfo.InternalInvoke() in
System.Reflection.RuntimeConstructorInfo.InternalInvoke(object obj, object[] parameters, bool wrapExceptions) in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:936
System.Reflection.RuntimeConstructorInfo.DoInvoke(object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object[] parameters, System.Globalization.CultureInfo culture) in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:926
ObjCRuntime.Runtime.ConstructNSObject<Foundation.NSObject>(System.IntPtr ptr, System.Type type, ObjCRuntime.Runtime.MissingCtorResolution missingCtorResolution) in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.2.0.47/src/Xamarin.iOS/ObjCRuntime/Runtime.cs
ObjCRuntime.Runtime.ConstructNSObject(System.IntPtr ptr, System.IntPtr klass, ObjCRuntime.Runtime.MissingCtorResolution missingCtorResolution) in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.2.0.47/src/Xamarin.iOS/ObjCRuntime/Runtime.cs:1108
ObjCRuntime.Runtime.GetNSObject(System.IntPtr ptr, ObjCRuntime.Runtime.MissingCtorResolution missingCtorResolution, bool evenInFinalizerQueue) in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.2.0.47/src/Xamarin.iOS/ObjCRuntime/Runtime.cs:1241
ObjCRuntime.Runtime.TryGetOrConstructNSObjectWrapped(System.IntPtr ptr) in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.2.0.47/src/Xamarin.iOS/ObjCRuntime/Runtime.cs:682
ObjCRuntime.Runtime.try_get_or_construct_nsobject(System.IntPtr obj, int exception_gchandle) in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/runtime/Delegates.generated.cs:314
UIKit.UIApplication.UIApplicationMain() in
UIKit.UIApplication.Main(string[] args, System.IntPtr principal, System.IntPtr delegate) in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.2.0.47/src/Xamarin.iOS/UIKit/UIApplication.cs:86
UIKit.UIApplication.Main(string[] args, string principalClassName, string delegateClassName) in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.2.0.47/src/Xamarin.iOS/UIKit/UIApplication.cs:65
MyApp.iOS.Application.Main(string[] args) in /Users/xx/myapp/myapp.iOS/App/Main.cs:13

The first instance is obviously created by my method call. But what about the second one?

Does anyone have a clue what is happening?
Especially as this code worked before updating Visual Studio and xCode.

Thanks in advance.

Best Regards,
Mario

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    It seems PerformSegue(„SegueToB“, Self); is not a correct c# grammar. We now use the code below in Xamarin:

    PerformSegue("SegueToB", null);
    

    And I've tried it on my side with Xamarin.iOS Version 13.2.0.47 and XCode 11.0 the B controller won't be initialized twice. Could you please share your sample here? We need it to reproduce this issue.

  • twt_msetwt_mse Member ✭✭

    Thanks for your response.

    I have tried your suggestion, but the problem still occurs.

    The issue currently appears in a bigger project, that I can't easily share.
    But I will try to reproduce the issue in a small sample project and share it here when I am done.

  • LandLuLandLu Member, Xamarin Team Xamurai

    We don't need the whole project. You'd better create a sample to make sure this is caused by PerformSegue.
    Maybe, the second view controller is created by other codes and ignored by you.

  • twt_msetwt_mse Member ✭✭

    It looks like you are right. PerformSegue is not actually causing the issue.

    With further investigation of the project I saw, that ViewController "B" is probably created from a SplitViewController in the storyboard. Looks like this case is not handled correctly.

  • LandLuLandLu Member, Xamarin Team Xamurai

    Have you corrected this operation now?

  • twt_msetwt_mse Member ✭✭
    edited October 11

    I am still at it, but i found the issue. I'll try to explain it:

    // ViewController_A
    public override void ViewDidLoad() {
        base.ViewDidLoad();
        PerformSegue("SegueToB", Self);
    }
    
    // ViewController_A
    public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender) {
        base.PrepareForSegue(segue, sender);
    
        var vc = (ViewController_B)segue.DestinationViewController;
        vc.data = new Data();
    }
    

    PerformSegue was called in the ViewDidLoad() of ViewController A. Then in PrepareForSegue the data for B was initialized. That didn't work well with the SplitViewController, that itself created the ViewController A and B, which lead to the second instance of B.

    I think the above code "accidentally" worked previously. But from what I have read now, it is generally not a good idea to call PerformSegue from ViewDidLoad. I am currently rewriting this code to use ViewWillAppear instead of ViewDidLoad.

  • LandLuLandLu Member, Xamarin Team Xamurai

    It depends.
    If ViewController B has been embedded in your SplitViewController as the detail view controller it will definitely create an instance of B. And then if you want to navigate to a new B controller the other instance should be created.
    However, it relies on your project's specific architecture.
    We are willing to help you analyze the issues if you can share the sample here.

Sign In or Register to comment.