App Crashing trying to reach storyboard - xcode

I'm getting an error connecting to my storyboard. I have a navigation controller connected to my view controller as a root. Everytime I play the application, it crashes. I get this error:
Unknown class ViewController in Interface Builder file.
(lldb)
scene is unreachable due to lack of entry points and does not have an identifier for runtime access via -instantiateViewControllerWithIdentifier-
What's this even mean?
My view controller is defined right under the normal code.
import UIKit
class ViewController: UIViewController {
//some code here

It sounds like one of the scenes in your Storyboard is (a) referencing a class, AboutMeViewController, which you haven't defined.
It further sounds like this scene also doesn't have any segues pointing to it, nor does it have a unique identifier. Thus there's no way to load it.
Select each scene in your storyboard in turn, select the outermost view controller object, and use the identity inspector to see the class of that view controller.

Since I transferred the storyboard from another project, it was linked to another project. I refreshed the "Custom Class"/"File Owner". Usually it's hidden and it confuses people but it's there. To locate it find the newspaper looking like icon and press on it. It'll be the first option all the way at the top.

Related

When an element is dragged from Storyboard to ViewController, where is it linked programmatically?

As I understand it, each element such as a button or label is linked from Storyboard to ViewController. This is done graphically in XCode by dragging. Where is the code that states this pairing in the XCode environment?
There is no code that states this. In fact, there is no actual connection being made at all. It's just an illusion.
There are two separate things being configured when you do that:
In the nib (the storyboard), an outlet is configured. It is just a name, a string
In the code, there is a property with the same name.
The connection between them happens, if it is going to happen at all, when the app actually runs and at some point the nib is loaded. At that moment, the nib has an owner, and key-value coding is used to look for a property of that owner with the same name as the outlet. If it's there, the object instantiated from the nib is assigned as the value of that property, and thus the connection is made.
So you see, there is no real connection in Xcode. There are two separate things that will need to try to connect while the app actually runs, at nib-loading time. It's a fragile and risky business. That is why, if there is no such property, your app crashes at that moment.
Basically #IBOutlet is not part of Swift, and that's what lets Xcode figure out that outlet property inside a controller is linked to some UIView (or subclass, such as UILabel) on the Storyboard.
Also, if you right-click the Storyboard, and Open As > Source Code, you should see a lot of the generated UI/XML code. If your label is called myLabel, you should see something like this:
<connections>
<outlet property="myLabel" destination="zLp-2i-ru4" id="Zda-UD-1h6"/>
</connections>
inside one of the Scene Nodes.

performSegueWithIdentifier throws unknown exception

I'm trying to refactor one of my ViewControllers, by splitting it up.
This is for an app which will do card manipulations. I had a controller which could edit multiple types of shuffles but now I'm splitting it into separate controllers for each individual shuffle type.
There is another story board which allows you to pick moves, it is set up to have segues from hidden buttons. The segues point to storyboard references. Originally I made the scenes for the segues in the dispatch story board, and then refactored them using Xcode's Editor>Refactor to Storyboard menu item.
I then made a new storyboard for the FaroEditor view controller. Then I tried to figure out how to add a reference to this storyboard. I finally found the 'Storyboard reference' in the object gallery.
I put this in the dispatch storyboard, and set it to point to the FaroEditor storyboard:
I did a bit of photoshopping to put the storyboard, the storyboard reference attributes, and the segue attributes in a single image.
When I run and trigger the segue, I get an exception thrown with no info as to what it is:
Again, I used photoshop to copy and paste the three top stack frames into a single image.
I'm at a bit of a loss about how to diagnose and fix this. Any ideas?
You need to add a 'storyboard ID' on the view you are referencing and then add that same ID to the Referenced ID in the Attributes Inspector
UI operations should be done in main thread
DispatchQueue.main.async {
self.performSegue(withIdentifier: "someSegue", sender: self)
}
Important
Use UIKit classes only from your app’s main thread or main dispatch queue, unless otherwise indicated. This restriction particularly applies to classes derived from UIResponder or that involve manipulating your app’s user interface in any way.
developer.apple.com/documentation/uikit

Why can't I connect my menu to my view controller IBAction?

I have a document based application. I have just created menu items in the storyboard and IBActions in my view controller. However the usual way I connect an action to a target doesn't work
-(IBAction) markAsHidden:(id)sender;
-(IBAction) markAsVisible:(id)sender;
-(IBAction) toggleHidden:(id)sender;
Here is what I see when from my menu item I press Ctrl and mouse click from menu to View Controller. It does not show my IBActions.
Any idea ? My 2 cents guess is that it has to do with the app being document based but... not really sure
Connect the menu items to the application scene's First Responder. When you connect to the application scene's First Responder, your view controller's IBActions should appear in the HUD's list of available actions instead of the action segues shown in your screenshot's HUD.
Why can't I connect my menu to my view controller IBAction?
Because your menu items and view controller are in different scenes in the storyboard. You can think of a scene as an independent graph of objects that are instantiated when the scene is loaded from the storyboard. Objects in different scenes can't be connected together in the storyboard because they're not loaded at the same time.
Just for fun, try creating an instance of your view controller in the Application Scene in your storyboard. To do that, you'll probably need to drag a plain old NSObject instance into the scene and then set its type. Once you do that, you'll find that you can drag a connection from a menu item to that view controller just as you'd expect, but you can't drag a connection to a different object of the very same type in a different scene.
Note: Once you've played around enough to convince yourself that it works, remember to delete the view controller that you added. A view controller without a view is like a duck without a quack, and a view controller and its view hierarchy should be in their own scene.
My 2 cents guess is that it has to do with the app being document based
No, it doesn't have anything to do with that. You'd have the same problem in an app that's not document-based. You'd also have the same problem if your app were .xib-based instead of using storyboards, since the controller you'd be trying to connect to would be in a completely different .xib file.
The easy solution, as Mark already described, is to use the responder chain. The First Responder proxy object is part of every scene, so you can always make connections to it. When you connect a menu item to First Responder its target will be nil, which tells NSMenu to walk the responder chain until it finds an object that responds to the menu item's action message. It then sends the message to that object.
If you are converting a project from objective C to Swift, do not make my mistake. When writing your IBAction write like this:
#IBAction func someAction(_ sender:AnyObject) {
// this will work
}
Do not omit the underscore before sender or the Interface Builder won't be able to connect to your action as in here:
#IBAction func someAction(sender:AnyObject) {
// this won't work and IB won't connect to this action
// because sender will be part of the symbol name
}

Swift class to interact with Interface Builder via IBOutlet

Good evening all,
I'm slowly working through my first OS X app. I have been having a hard time getting my Swift class to interact with an NSPopUpButton. Just to make sure I was doing it right, I created a new project and successfully erased all entries and entered text into the NSPopUpButton via AppDelegate. However, as soon as I try to move the same functionality to my own class, I can't even get the IBOutlet connection across to the new class.
Is a particular subclass type required of a new class to work properly with interface builder?
Here is a screenshot of the class I have created, as well as AppDelegate where I am trying to call the function belonging to this class.
Finally, here is the IB element in question, should I be able to select my own class under the 'Custom Class' inspector?
I am an iOS developer, but I would imagine the same principles would apply to your situation.
A ViewController class and an interface created in interface builder are two seperate things. While it may appear that they are connected via an iboutlet, they are actually independent and one can be instantiated without the other.
Currently, you are only creating an instance of your ViewController class in your App Delegate - and that's all. The system has no idea that your xib even exists! The outlets will only be connected once your app connects your xib to your ViewController class.
How do we do this? It's actually quite simple. Instead of instantiating our view controller like this:
let viewcontroller = ViewController()
We would connect our view controller to our xib in the instantiation:
let viewcontroller = ViewController(nibName: "MainWindow", bundle: NSBundle().mainBundle)
The nibName is telling the system the file name of your xib, and the NSBundle().mainBundle is telling the system where to look for the xib.
This will all only work if your xib has been assigned a custom class, like you mentioned. In your xib in interface builder, select the entire view controller. Then, in the custom class inspector type in the name of your ViewController class (in your case: ViewController - it should autocomplete). This will make sure your outlets are connected.
And you should be set up!! Let me know if you have any more problems come up.
Good luck!
EDIT:
This replaces the first part of my answer, however the part about hooking things up in Storyboard remains true. Upon reconsidering, I've believe I've realized that we are only creating the view controller, and not adding it to our view. Despite this, I believe we can take a short cut solution by adding one method to your view controller subclass (the one we set in the Storyboard). Start typing in viewDidLoad, and it should autocomplete. Type in super.viewDidLoad() at the beginning of the method. After that, type self.listUpdate(). This should work if the classes are hooked up correctly in Storyboard. This means you can delete the variables you created in the App Delegate.
Reference: You might also find Apple's documentation on creating a view controller handy (it's in Objective C online, but can be easily converted to Swift - it's the concept that counts): NSViewController Class Reference

How do I programmatically change a custom view object's member variables?

I appreciate you taking the time to read this and hopefully help me out!
I am writing my first program in Xcode 4, using Objective-C and Cocoa for the first time. I have been following the tutorials, but at this point I want to display custom graphics using a custom view, where the graphics change based on the values in my model object.
My controller class, GameController, based on NSObject, creates my model object during initialization, and successfully receives button action messages, updates the model object appropriately, and updates text strings on the window in return using its outlets. I accomplished this by creating an NSObject object in my xib file (which is called the default (?) name of MainMenu.xib, but it includes all the UI in my application), using the utilities pane to set its class to GameController, and then connecting its actions and outlets to the appropriate UI elements.
I have dragged a custom view into my window, and used the utilities pane to set its class to my custom view class, BoardView, which is based on NSView. In BoardView, I have overridden drawRect: to fill in the background of my view with a blue color, and then draw each of the graphics defined by my model class (GameStatus).
The problem is, I do not know how to access the data in GameStatus from my BoardView class, or have GameController update a member variable of BoardView. I have not instantiated BoardView anywhere besides in Interface Builder, by dropping a custom view on my window. I do not have a BoardView object in my xib file (the column or list on the left side in Interface Builder).
I tried to create an outlet to a BoardView object in my GameController class (which does have an object in my xib, as I mentioned above), and connecting that outlet to the BoardView custom view in my window, and Interface Builder seemed fine with that. However, when I run the program, the value of the BoardView outlet pointer in my GameController class is 0x0. It seems like the outlet is not being connected to a BoardView object. I don't know if I need to do something else in Interface Builder to make an actual object (I tried creating one in the list to the left, but then couldn't figure out a way to connect it to the actual custom view displayed on the window).
To add to the confusion, when I run my application, the BoardView area of the window will display the blue background, and in fact any other graphics which I define in the drawRect: function. However, without any way to talk to my model object, I can't change the graphics based on the state of the model. I'm not sure if the fact that the hard-coded graphics are displaying correctly means that there is an object there somewhere, or whether it is somehow drawing based on the general template of the class somehow. The latter doesn't really make sense to me, but if the former is true, I'm can't figure out how to talk to that object from other parts of my code.
I feel like I'm just missing some basic understanding of how Xcode / Interface Builder creates objects or something. I would really appreciate someone telling me exactly what I'm missing here in the connection between my MVC objects / classes.
Thank you in advance for any help you can give me!
EDIT 2011/09/06:
To download a copy of my project to take a look at it, go here:
http://talix.homeip.net/2011/rival/
That's my home server and I'm an amateur at this, so please leave a comment if it isn't working. Thanks! Also, if there is a better way to respond to comments other than editing my original post, please let me know; I'm also new to this website. ;-)
-Joe
It sounds like you're only instantiating one GameController and one BoardView, and that's happening in the nib.
This, then, is the heart of the problem:
I tried to create an outlet to a BoardView object in my GameController class (which does have an object in my xib, as I mentioned above), and connecting that outlet to the BoardView custom view in my window, and Interface Builder seemed fine with that. However, when I run the program, the value of the BoardView outlet pointer in my GameController class is 0x0. It seems like the outlet is not being connected to a BoardView object.
Where in your code are you needing a reference to your BoardView but getting nil? Is that in GameController's init method, or in some other method of GameController?
If it's inside init, this is what I'd expect. The code that loads nibs must initialize the objects before it connects the outlets.
(If it's outside of init, I'd suggest starting by disconnecting and reconnecting the outlet.)
View = BoardView
Controller = GameController
Model = GameStatus
In MVC, the controller usually brokers communication between the model and the view, so I suggest you handle it this way:
Add a gameController outlet to BoardView and connect it to your game controller.
In drawRect, have the BoardView get the game status from the game controller.
I also suggest you make GameController your application's delegate:
Delete RivalAppDelegate.[hm].
In your nib, delete the reference to Rival App Delegate, and connect the Game Controller reference to the File's Owner delegate outlet.
You've got two instance of BoardView in your nib. Hook up the one inside your window to the boardView outlet of GameController and delete the other.
In GameController.h, after #interface GameController : NSObject, add <NSApplicationDelegate>
In GameController.m, implement applicationDidFinishLoading and set up your application there. (You can even call setGameStatus there if you want to.)

Resources