StoryBoard.InstantiateViewController giving "Unknown class testController in Interface Builder file" - ios

I am working on a Xamarin IOS/monotouch project.
I have been stuck with this error since some time. These are the lines of code
var prfc = this.Storyboard.InstantiateViewController ("testController") as testController;
if (prfc != null) {
this.PresentViewController(prfc,false,null);}
I tried renaming viewcontroller, cleaning and building solution, deleting viewcontroller and adding a new one with another name
I have ensured that all spellings are correct, i have same Viewcontroller name, StoryBoardID, and Restoration ID. This is how I have registered my viewcontroller in Designer partial class
[Register ("testController")]
partial class testController
Here is my appdelegate.cs code `[Register ("AppDelegate")] public partial class AppDelegate : UIApplicationDelegate { // class-level declarations UIWindow window; public static UIStoryboard Storyboard = UIStoryboard.FromName ("MainStoryboard", null); public static UIViewController initialViewController; public override UIWindow Window { get; set; }
`[Register ("AppDelegate")] public partial class AppDelegate : UIApplicationDelegate { // class-level declarations UIWindow window; public static UIStoryboard Storyboard = UIStoryboard.FromName ("MainStoryboard", null); public static UIViewController initialViewController; public override UIWindow Window { get; set; }
// This method is invoked when the application is about to move from active to inactive state.
// OpenGL applications should use this method to pause.
public override void OnResignActivation (UIApplication application)
{
}
// This method should be used to release shared resources and it should store the application state.
// If your application supports background exection this method is called instead of WillTerminate
// when the user quits.
public override void DidEnterBackground (UIApplication application)
{
}
// This method is called as part of the transiton from background to active state.
public override void WillEnterForeground (UIApplication application)
{
}
// This method is called when the application is about to terminate. Save data, if needed.
public override void WillTerminate (UIApplication application)
{
}
public override void FinishedLaunching (UIApplication application)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
initialViewController = Storyboard.InstantiateInitialViewController () as UIViewController;
window.RootViewController = initialViewController;
window.MakeKeyAndVisible ();
return ;
}
}`
I have tried out every possibility but can't fix this. This error is occuring for every new viewcontroller that I add to Storyboard. I am getting a null when I call InstantiateViewController. I have tried cleaning and rebuilding. It works on simulator, but not on device

The issue was as pointed out by #orkenstein. I was targeting 7.1 whereas was testing on a 7.0 device

Related

Difficulty with TabBarControllers intermixed with NavigationControllers

I have a Xamarin.iOS app where I have the following structure:
NavController (root: Login)
--> TabBarController (Home) - (Search) - (Profile)
------> NavController (root: Home)
------------->TableController
----------------->DetailController
------>NavController (root: Search)
...etc
I am currently having difficulties working with the navigation items, specifically the back button item.
I never want to go back to the login page via the back button, so in my HomeController, I hide the back button by saying
TabBarController.NavigationItem.HidesBackButton = true;
When I go to the next screen (TableController) I want to see the back button that goes back to the HomeController, however my current approach has a back button to the Login Controller
this.TabBarController.NavigationItem.HidesBackButton = false;
Thanks for any help
For the effect you want, I suggest you create an object(I use "RootController" as an example) to manage the app's Window.RootController.
I don't know if you have some experience for change window's RootController, so just follow my step:
At first create a new project, remove the storyboard and Viewcontroller.cs.(Don't forget remove the bundle for storyboard in the info.plist)
Then rewrite your AppDelegate.cs, like this:
[Register ("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
UIWindow window;
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// create a new window instance based on the screen size
window = new UIWindow (UIScreen.MainScreen.Bounds);
window.RootViewController = RootController.Instance.LoginController;
window.MakeKeyAndVisible ();
return true;
}
public override void OnResignActivation (UIApplication application)
{
// Invoked when the application is about to move from active to inactive state.
// This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message)
// or when the user quits the application and it begins the transition to the background state.
// Games should use this method to pause the game.
}
public override void DidEnterBackground (UIApplication application)
{
// Use this method to release shared resources, save user data, invalidate timers and store the application state.
// If your application supports background exection this method is called instead of WillTerminate when the user quits.
}
public override void WillEnterForeground (UIApplication application)
{
// Called as part of the transiton from background to active state.
// Here you can undo many of the changes made on entering the background.
}
public override void OnActivated (UIApplication application)
{
// Restart any tasks that were paused (or not yet started) while the application was inactive.
// If the application was previously in the background, optionally refresh the user interface.
}
public override void WillTerminate (UIApplication application)
{
// Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground.
}
}
And this is RootController.cs which include a UINavigationController and a UITabBarController(Home - Search - Profile):
public class RootController
{
private static RootController instance;
public static RootController Instance {
get {
if (instance == null)
instance = new RootController ();
return instance;
}
}
private static UINavigationController loginController;
public UINavigationController LoginController {
get {
if (loginController == null)
InitLoginController ();
return loginController;
}
}
private void InitLoginController()
{
UIViewController loginViewController = new UIViewController (){ Title = "LoginController" };
loginViewController.View.Frame = UIScreen.MainScreen.Bounds;
loginViewController.View.BackgroundColor = UIColor.Red;
loginViewController.NavigationItem.SetRightBarButtonItem (new UIBarButtonItem ("MainTab",UIBarButtonItemStyle.Done, delegate {
UIApplication.SharedApplication.KeyWindow.RootViewController = RootController.Instance.MainTabController;
}),true);
loginController = new UINavigationController (loginViewController);
}
private static UITabBarController mainTabController;
public UITabBarController MainTabController {
get {
if (mainTabController == null)
InitMainTabController ();
return mainTabController;
}
set {
mainTabController = value;
}
}
private void InitMainTabController ()
{
mainTabController = new UITabBarController ();
mainTabController.ViewControllers = new UIViewController [] {
new UINavigationController(new HomeViewController() {
TabBarItem = new UITabBarItem (UITabBarSystemItem.Favorites,0)
}),
new UINavigationController (new UIViewController ()
{
Title = "SearchController",
TabBarItem = new UITabBarItem (UITabBarSystemItem.Search,1)
}),
new UINavigationController (new UIViewController ()
{
Title = "ProfileController",
TabBarItem = new UITabBarItem (UITabBarSystemItem.More,2)
})
};
mainTabController.SelectedIndex = 0;
}
}
And this is HomeController.cs which can push an UITableViewController as you wish and also has a button to return to LoginController if you needed:
public class HomeViewController : UIViewController
{
public HomeViewController ()
{
Title = "HomeController";
this.View.Frame = UIScreen.MainScreen.Bounds;
this.View.BackgroundColor = UIColor.Green;
//Set a button to return to loginController
this.NavigationItem.SetLeftBarButtonItem (new UIBarButtonItem ("LoginC",UIBarButtonItemStyle.Done, delegate {
UIApplication.SharedApplication.KeyWindow.RootViewController = RootController.Instance.LoginController;
}),true);
//Set a button to go to tableController
UITableViewController tableViewController = new UITableViewController (){ Title = "TableViewController" };
tableViewController.View.Frame = UIScreen.MainScreen.Bounds;
tableViewController.View.BackgroundColor = UIColor.White;
tableViewController.HidesBottomBarWhenPushed = true;//To make tabbar disappear
this.NavigationItem.SetRightBarButtonItem (new UIBarButtonItem ("TableView",UIBarButtonItemStyle.Done, delegate {
this.NavigationController.PushViewController(tableViewController,true);
}),true);
}
}
You can add your own ViewController in RootController.cs instead of my sample controllers.
If you still have some problems, just leave it here, I'll check it latter.
Hope it can help you.

Mixing a CocosSharp game with UIViewControllers

I'm creating a CocosSharp game with several additional native screens which I'm going to implement using native iOS UIViewController. The flow is the following:
On app startup I'm creating UINavigationViewController and initial view with my custom main menu:
public override void FinishedLaunching(UIApplication app)
{
MainWindow = new UIWindow(UIScreen.MainScreen.Bounds);
var rootViewStoryboard = UIStoryboard.FromName("GameMenu", null);
var rootView = rootViewStoryboard.InstantiateViewController("GameMenu");
var navigationController = new UINavigationController(rootView);
MainWindow.RootViewController = navigationController;
MainWindow.MakeKeyAndVisible();
}
public partial class GameMenu : UIViewController
{
public GameMenu(IntPtr handle)
: base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
btnStartGame.TouchUpInside += (sender, e) => NavigationController.PresentViewController(new GameScene(), false);
}
}
One of the actions leads to another UIViewController (modal) where CocosSharp game is created:
public partial class GameScene : UIViewController
{
public GameScene()
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
_application = new CCApplication();
_application.ApplicationDelegate = new GameAppDelegate();
_application.StartGame();
_application.MainWindow.DisplayStats = true;
OnStopGame();
}
}
Finally on certain event (in my case in 5 sec) I'm trying to finish a game and return back to the main menu:
public async Task OnStopGame()
{
await Task.Delay(5000);
_application.ExitGame();
NavigationController.DismissViewController(false, null);
}
As a result I get empty black screen, background music continue to run, no main menu is displayed.
How should I properly navigate from CocosSharp game to a native controller and back? Can they live in parallel?

ViewModel is null during ViewDidLoad

I am getting started with MvvmCross in iOS.
public class MainView : MvxTabBarViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
var vm = (MainViewModel)this.ViewModel;
if (vm == null)
return;
}
}
Setting a breakpoint to the line where access the ViewModel, shows me, that ViewModel is null.
I can workaround this by calling ViewDidLoad() in the constructor. Then, ViewModel is null during the constructor call, but valid in the default ViewDidLoad call. But that looks like a workaround. can anybody help?
I'm guessing here the problem here will be specific to the way that TabBarViewController is constructed.
ViewDidLoad is a virtual method and it is called the first time the View is accessed.
In the case of TabBarViewController this happens during the iOS base View constructor - i.e. it occurs before the class itself has had its constructor called.
The only way around this I've found is to add a check against the situation in ViewDidLoad, and to make a second call to ViewDidLoad during the class constructor.
You can see this in action N-25 - https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/976ede3aafd3a7c6e06717ee48a9a45f08eedcd0/N-25-Tabbed/Tabbed.Touch/Views/FirstView.cs#L17
Something like:
public class MainView : MvxTabBarViewController
{
private bool _constructed;
public MainView()
{
_constructed = true;
// need this additional call to ViewDidLoad because UIkit creates the view before the C# hierarchy has been constructed
ViewDidLoad();
}
public override void ViewDidLoad()
{
if (!_constructed)
return;
base.ViewDidLoad();
var vm = (MainViewModel)this.ViewModel;
if (vm == null)
return;
}
}

Custom URL Handling iOS xamarin

I'm trying to set up my application so that I can add an NSUrl attribute to specified substrings of a textview, and when that NSUrl is touched, it pushes a new view rather than open a new url.
I am ovverriding OpenURL in my AppDelegate.cs class, and sending a notification with the url
public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
NSNotificationCenter.DefaultCenter.PostNotification (NSNotification.FromName ("ArtistDetail", url));
return true;
}
Then in my class that contains the the text view, I add the observer in the constructor
NSNotificationCenter.DefaultCenter.AddObserver ("ArtistDetail", delegate{artistDetail(null);});
And have my method
public void artistDetail (NSNotification notification)
{
//push view based on info in notification.object
}
I'm not having any luck. I found this article Can't push view controller after overriding openURL where someone did it in objective C the same way. One problem - I'm putting breakpoints and log notes in my OpenURL override, and they're not getting hit. When you click/tap an NSSUrl, does it by default call OpenUrl? If so, why isn't my override getting hit?
I've been researching how to do this for 6 hours. Of course, 20 minutes after I post the question on SO, I figure out the answer.
I had to implement a UIApplication subclass, override the method there, register it, and launch it as the UIApplication in my Main.cs.
UIApplicationMain.cs
[Register ("UIApplicationMain")]
public class UIApplicationMain : UIApplication
{
public UIApplicationMain ()
{
}
public override bool OpenUrl (NSUrl url)
{
NSNotificationCenter.DefaultCenter.PostNotification (NSNotification.FromName ("ArtistDetail", url));
return true;
}
}
Main.cs
public class Application
{
// This is the main entry point of the application.
static void Main (string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main (args, "UIApplicationMain", "AppDelegate");
}
}
View Controller where the hyperlinks are displayed, and should be handled dynamically to push the view controller you want
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
NSNotificationCenter.DefaultCenter.AddObserver ("ArtistDetail", artistDetail);
}
public void artistDetail (NSNotification notification)
{
NSUrl artistName = (NSUrl)notification.Object;
String name = artistName.AbsoluteString;
this.NavigationController.PushViewController (new ArtistDetailViewController (name), true);
}
For anyone trying to solve the problem of "How to put a button within your UITextView"
(like twitter does with #hastags and #users) - this is it! Put the text in an NSAttributedString, apply the link attribute to the text you want to act as a button, and handle accordingly.

Custom UIViewController not receiving orientation change notifications on device rotation

So, I have a custom UIWindow, a custom UIViewController, and a custom UIImageView.
private class CoachingWindow : UIWindow
{
public CoachingWindow(...)
{
RootViewController = new CoachingOverlayViewController(...);
}
private class CoachingOverlayViewController : UIViewController
{
public CoachingOverlayViewController(...)
{
View = new CoachingOverlayView(...);
}
public override void DidRotate (UIInterfaceOrientation fromInterfaceOrientation)
{
...
}
public override bool ShouldAutorotate()
{
return true;
}
private class CoachingOverlayView : UIImageView
{
public CoachingOverlayView(...)
{
...
}
}
}
}
The window, view controller, and view all display properly when first called: the custom UIWindow appears as an overlay over the rest of the existing UIWindows, the view controller is properly assigned as the RootViewController, the view is assigned to the View property of the view controller. So, it all renders correctly.
However, the overridden DidRotate() and ShouldAutorotate() methods never get get called when I physically rotate the device or simulator.
I'm thinking it may have something do with the fact that I'm using a custom UIWindow. Perhaps the window isn;t receiving notifications of orientation change from iOS? Or does iOS send these notifications directly to view controllers? Maybe I have to somehow make the view controller subscribe to these events because it's a custom view controller???
I'm using MonoTouch and iOS 6.
Any suggestions would be great. I'm beating my head against the wall here.
in iOS 6 you can use
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
{ ... }
Figured it out. I had override ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation) instead of ShouldAutorotate(). But this is actually deprecated in iOS6. Still have to figure out how to do it the iOS6 way, but this will do for now.
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
...
}

Resources