升级MvvmCross 7.0.0后Xamarin iOS应用无法启动首页面
Xamarin iOS升级MvvmCross 7.0后启动页卡死,ViewDidLoad未执行
将Xamarin iOS应用的MvvmCross升级至7.0.0版本后,应用卡在启动页,无法正常加载首个视图控制器。排查后发现:
- AppDelegate和Setup文件无明显异常
- 视图控制器构造函数及ViewModel均被触发,但ViewDidLoad方法完全未执行
- 调整代码后偶尔出现ViewModel未绑定到视图(DataContext为空)或
set.Apply()报错的情况 - 即便无报错,LoginView始终无法显示,应用持续停留在启动页
相关代码
AppDelegate代码
[Register("AppDelegate")] [assembly: Preserve(typeof(MvxIosSetup<App>))] public partial class AppDelegate : MvxApplicationDelegate<MvxIosSetup<App>, App> { /// <summary> /// UIApplicationDelegate.Window doesn't really exist / work. It was added by Xamarin.iOS templates /// </summary> public new virtual UIWindow Window { get; set; } public AppDelegate() : base() { RegisterSetup(); } public override void WillEnterForeground(UIApplication application) { FireLifetimeChanged(MvxLifetimeEvent.ActivatedFromMemory); } public override void DidEnterBackground(UIApplication application) { FireLifetimeChanged(MvxLifetimeEvent.Deactivated); } public override void WillTerminate(UIApplication application) { FireLifetimeChanged(MvxLifetimeEvent.Closing); } public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) { Window = new UIWindow(UIScreen.MainScreen.Bounds); var setup = new Setup(); setup.InitializePrimary(); setup.InitializeSecondary(); setup.PlatformInitialize(this, Window); var myFirstViewController = new LoginView(); Window.RootViewController = myFirstViewController; var startup = Mvx.IoCProvider.Resolve<IMvxAppStart>(); startup.Start(); Window.MakeKeyAndVisible(); SetupUiStyles(); return true; } private void FireLifetimeChanged(MvxLifetimeEvent which) { var handler = LifetimeChanged; handler?.Invoke(this, new MvxLifetimeEventArgs(which)); } public event EventHandler<MvxLifetimeEventArgs> LifetimeChanged; private void SetupUiStyles() { UINavigationBar.Appearance.TintColor = UIColor.Black; UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.Default; if (UIDevice.CurrentDevice.CheckSystemVersion(15, 0)) { var appearance = new UINavigationBarAppearance() { BackgroundColor = UIColor.FromRGB(99, 183, 105), TitleTextAttributes = new UIStringAttributes() { ForegroundColor = UIColor.White } }; UINavigationBar.Appearance.StandardAppearance = appearance; UINavigationBar.Appearance.CompactAppearance = appearance; UINavigationBar.Appearance.ScrollEdgeAppearance = appearance; } UIApplication.CheckForEventAndDelegateMismatches = false; } }
Setup类代码
public class Setup : MvxIosSetup<App> { public Setup() { } protected override IMvxApplication CreateApp() { return new App(); } protected override IMvxIosViewPresenter CreateViewPresenter() { return new MvxIosViewPresenter(ApplicationDelegate, Window); } protected override void InitializeFirstChance() { base.InitializeFirstChance(); } public override void InitializeSecondary() { Mvx.IoCProvider.RegisterType<LoginViewModel, LoginViewModel>(); InitializeViewModelTypeFinder(); base.InitializeSecondary(); } protected override IMvxNameMapping InitializeViewModelTypeFinder() { var viewModelByNameRegistry = CreateViewModelByNameRegistry(); var viewModelAssemblies = GetViewModelAssemblies(); foreach(var assemly in viewModelAssemblies) { viewModelByNameRegistry.AddAll(assemly); } var nameMapping = CreateViewToViewModelNaming(); Mvx.IoCProvider.RegisterSingleton(nameMapping); return nameMapping; } }
BaseView基类代码
public class BaseView<T> : MvxViewController where T : MvxViewModel { protected BaseView(string name, NSBundle bundle = null) { } public new T ViewModel { get { return base.ViewModel as T; } set { base.ViewModel = value; } } public override void ViewDidLoad() { base.ViewDidLoad(); } }
LoginView代码
[MvxRootPresentation] public partial class LoginView : BaseView<LoginViewModel>, IBaseView { public LoginView() : base("LoginView", null) { // being hit } public override void ViewDidLoad() { base.ViewDidLoad(); //not being hit } }
问题根源与修复方案
1. 修复AppDelegate启动流程
MvvmCross 7.0已自动处理Setup初始化,手动实例化Setup并调用初始化会导致重复初始化,破坏视图展示逻辑。修改FinishedLaunching方法:
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) { Window = new UIWindow(UIScreen.MainScreen.Bounds); // 移除手动初始化Setup的代码,交由Mvx框架自动处理 var result = base.FinishedLaunching(application, launchOptions); // 无需手动创建LoginView,交由IMvxAppStart导航到根视图 Window.MakeKeyAndVisible(); SetupUiStyles(); return result; }
同时移除AppDelegate构造函数中冗余的RegisterSetup()调用:
public AppDelegate() : base() { // 移除RegisterSetup(); }
2. 简化Setup类
MvvmCross 7.0自动处理ViewModel注册和视图映射,无需手动重写InitializeSecondary和InitializeViewModelTypeFinder,简化后的Setup类:
public class Setup : MvxIosSetup<App> { protected override IMvxApplication CreateApp() { return new App(); } protected override IMvxIosViewPresenter CreateViewPresenter() { return new MvxIosViewPresenter(ApplicationDelegate, Window); } }
3. 配置App启动导航
确保App类中正确配置IMvxAppStart,指定启动时导航到LoginViewModel:
public class App : MvxApplication { public override void Initialize() { RegisterCustomAppStart<LoginViewModel>(); } }
4. 修复BaseView构造函数
MvxViewController需要正确初始化视图,修改BaseView确保调用基类正确构造方法:
public class BaseView<T> : MvxViewController<T> where T : MvxViewModel { protected BaseView(string nibName, NSBundle bundle) : base(nibName, bundle) { } // 支持Storyboard加载的构造函数 protected BaseView(IntPtr handle) : base(handle) { } public override void ViewDidLoad() { base.ViewDidLoad(); } }
对应的LoginView更新构造函数:
[MvxRootPresentation] public partial class LoginView : BaseView<LoginViewModel>, IBaseView { public LoginView() : base("LoginView", null) { } public LoginView(IntPtr handle) : base(handle) { } public override void ViewDidLoad() { base.ViewDidLoad(); // 现在会被执行 } }
内容的提问来源于stack exchange,提问作者Projetinho
相关产品推荐
相关产品推荐

