Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
I have a set of view controllers. My app is supposed to use Core Data to remember which view controller was last used by the user. Ideally, I would want each view controller to store either its storyboard ID or its restoration ID in my app's database. The only problem is that instantiateViewControllerWithIdentifier uses a view controller's storyboard ID, which, unlike its restoration ID, is not a property of the view controller.
 
Maybe I can have every view controller except the controllers that the user first sees store its NIB name in the database. Then, I can have the view controller that is supposed to load one of those view controllers use the NIB name.

Each view controller's parent class is a subclass of UIViewController, so my above attempt at a solution may not be the solution I am looking for.
 
Error trying to load NIB file

OK, I just tried my own suggestion. Unfortunately, my code produced the following error.

Could not load NIB in bundle: 'NSBundle </Users/montana/Library/Application Support/iPhone Simulator/7.0.3/Applications/40F13F2C-DBF6-4D60-BD3B-E1D9C4E55AFD/(app name).app> (loaded)' with name '5dr-u6-8hq-view-sUj-6a-unA''

Now, usually other users would expect me to post some code. However, I firmly believe no code is necessary here, so instead of posting code, I will just tell you all what's supposed to happen, and what is actually happing.

What's supposed to happen: When I press a button in a view controller, the app first checks the database to see if the name of a Nib file is in there. Absent said name, the app takes me to a predefined view controller. When I am done with that view controller, the app takes me to another view controller and updates its database so that, until I am done with that view controller, the app will load the view controller from the controller's nib file.

What actually happens: The app saves the name of the second view controller's NIB file.
 
Last edited:
Could you not just manage that yourself with your own variables?

Code:
var old
var current
current = firstidentifier

old = current
// switch controller
current = whateveridentifier
 
Could you not just manage that yourself with your own variables?

Code:
var old
var current
current = firstidentifier

old = current
// switch controller
current = whateveridentifier

Here's the thing. I want the app to remember which view controller the user was on, even if the app is force-quitted.
 
What have you tried?

What have you done to actually debug this? Did you use the debugger? Set breakpoints at strategic locations in your view controllers, so you can see where it goes? Did you add NSLog statements? What sequence of execution did they show?


Now, usually other users would expect me to post some code. However, I firmly believe no code is necessary here, so instead of posting code, I will just tell you all what's supposed to happen, and what is actually happing.

What's supposed to happen: When I press a button in a view controller, the app first checks the database to see if the name of a Nib file is in there. Absent said name, the app takes me to a predefined view controller. When I am done with that view controller, the app takes me to another view controller and updates its database so that, until I am done with that view controller, the app will load the view controller from the controller's nib file.

What actually happens: The app saves the name of the second view controller's NIB file.

Your descriptions are difficult to follow because you don't clearly identify the view controllers by giving them names. Even names like Alice, Bob, Carol, and Dave would be better than what you have. Then in your "What actually happens", you say "second view controller" without stating its name, and without using the same adjectival phrase (i.e. you don't call it "second view controller" in your first description).

You also fail to identify in the "actually happens" part the entirety of what has actually happened. You give the end result, but you don't say how it got there. Thus, we're left to conclude that some, all, or maybe only parts of the "What should happen" may or may not have been executed. We don't know, because you didn't post any log of what was actually executed, what points were reached, and who or what might actually have produced "the name of the second view controller's NIB file", i.e. the actual output.

In short, you've described the final output, but nothing about how it got there or was produced.


Finally, one of the reasons for posting code is because computers don't execute descriptions written in everyday language. They only execute descriptions written in code. Your code precisely describes to the computer what it will do; it does not describe your intent. Nor does a description of your intent tell the computer what to do; it only tells humans (including yourself) what the actual code should do.

Your non-code description of what should happen is at best a rewrite or paraphrase of what you think your code says. The actual code could say something else. Rewrites and paraphrases invariably lose something in the translation. If you wrote it before writing code, then it's a first draft. The actual code could say something slightly different, or say it in a way that its execution isn't identical to your description of intent.

We have no way of knowing what the computer is actually doing except by seeing the code. You could have made any number of unseen errors that cause the code to not reflect your intention. If the intent was written first, the code is a translation of that. If your posted description was written after the code, then that description is a translation of the code. Neither one is a precise substitute for the other.

This is also why we ask for you to describe your intention, because if the intent doesn't match the code, we might see it. But unless we know the intent (the expected execution and result), all we know is the actual code. We only have a possibility of discovering what's wrong by knowing two things (code and intent), not just one (code or intent).

Debugging is a process of comparing actual results with expected results. If one of those is missing, no debugging is possible. A result is produced, but is it the right one? No one can tell unless they know what the expected result is. The same logic applies at every step of execution: compare actuality to expectation. Take one away, you can't tell anything.

Comparison of two things is fundamental to all problem solving.
 
What have you tried?

What have you done to actually debug this? Did you use the debugger? Set breakpoints at strategic locations in your view controllers, so you can see where it goes? Did you add NSLog statements? What sequence of execution did they show?
I have done nothing to debug this. Perhaps the cause of the error is that Xcode gives different names to the NIBs each time I build and run the app.

However, I just implemented another solution - instead of having the app store and retrieve Nib names, I just set the storyboard ID of each relevant view controller equal to its restoration ID, which I can tell the app to retrieve and store, in the Interface Builder.
Your descriptions are difficult to follow because you don't clearly identify the view controllers by giving them names. Even names like Alice, Bob, Carol, and Dave would be better than what you have. Then in your "What actually happens", you say "second view controller" without stating its name, and without using the same adjectival phrase (i.e. you don't call it "second view controller" in your first description).

You also fail to identify in the "actually happens" part the entirety of what has actually happened. You give the end result, but you don't say how it got there. Thus, we're left to conclude that some, all, or maybe only parts of the "What should happen" may or may not have been executed. We don't know, because you didn't post any log of what was actually executed, what points were reached, and who or what might actually have produced "the name of the second view controller's NIB file", i.e. the actual output.

OK, let me put it another way.

Here's an idea of what happens: Alice is the app's root view controller. When I first launch the app in the simulator, I click on a button that belongs to Alice. In response, Alice tells the navigation controller to display Bob. When I'm done working in Bob, Bob tells the navigation controller to display Carol. Before Bob does that, he makes sure my database is updated so that, if the app is terminated before I am done working in Carol, the next time my app is launched and I press Alice's button, Alice tells the navigation controller to load Carol instead of Bob.
 
Last edited:
I have done nothing to debug this.

Then I suggest the debugger. Or NSLog. Or a strategy other than guessing.


Perhaps the cause of the error is that Xcode gives different names to the NIBs each time I build and run the app.
Could be. Can you devise a test that produces some evidence that such a thing is happening (or isn't happening)? This could be NSLog output, debugger observations, etc.


However, I just implemented another solution - instead of having the app store and retrieve Nib names, I just set the storyboard ID of each relevant view controller equal to its restoration ID, which I can tell the app to retrieve and store, in the Interface Builder.
Could work. Again, think about how to devise a test producing evidence that this will work.

One of the crucial features is that the ID remain the same between builds. If Storyboard is generating new IDs at unpredictable times, then it will be impossible to restore based on that ID. One of the reasons for devising tests and producing evidence is to determine whether this ID stays the same across builds.


OK, let me put it another way.

Here's an idea of what happens: Alice is the app's root view controller. When I first launch the app in the simulator, I click on a button that belongs to Alice. In response, Alice tells the navigation controller to display Bob. When I'm done working in Bob, Bob tells the navigation controller to display Carol. Before Bob does that, he makes sure my database is updated so that, if the app is terminated before I am done working in Carol, the next time my app is launched and I press Alice's button, Alice tells the navigation controller to load Carol instead of Bob.
Does anyone (Alice, Bob, or Carol) ever stores anything in the database that says to load Bob? That is, is the absence of a name such as "Carol" the implicit command to load Bob?

Does Bob actually store Carol's name in the database? You expect that to happen, but does it? What's your evidence that it happens, or doesn't? Does it happen (or not) every time?

If some unpredictable name was in the database before, possibly a Storyboard-generated form such as "Xyzzy-404", what is expected to happen? Will Alice, Bob, or Carol be presented?
 
My answers are in bold.

Then I suggest the debugger. Or NSLog. Or a strategy other than guessing....Can you devise a test that produces some evidence that such a thing is happening (or isn't happening)? This could be NSLog output, debugger observations, etc.
I gave up.

Could work. Again, think about how to devise a test producing evidence that this will work.

One of the crucial features is that the ID remain the same between builds. If Storyboard is generating new IDs at unpredictable times, then it will be impossible to restore based on that ID. One of the reasons for devising tests and producing evidence is to determine whether this ID stays the same across builds.

The IDs are static. They are set in Interface Builder. I can even check a box that says "Use Storyboard ID" to easily set the restoration ID equal to the storyboard ID.

Does anyone (Alice, Bob, or Carol) ever stores anything in the database that says to load Bob? That is, is the absence of a name such as "Carol" the implicit command to load Bob?
Yes.

Does Bob actually store Carol's name in the database? Yes. What's your evidence that it happens, or doesn't? My testing shows that it does Does it happen (or not) every time? I think so.


If some unpredictable name was in the database before, possibly a Storyboard-generated form such as "Xyzzy-404", what is expected to happen? Will Alice, Bob, or Carol be presented? In such an event, I expect that the app would throw an exception. Therefore, touching Alice's button wouldn't do anything but cause the app to crash.
 
OK, looks like there is a problem. I want Carol's "back" button to take the user back to Alice, but it goes back to Bob. I thought that Bob would never appear, since after the user is done working in Bob, the navigation controller never pushes him into the navigation stack when Alice's button is tapped.
 
I'm still not sure why I'm reading this trying to gain understanding of why it's complicated.

If the first thing any viewcontoller did was write a meaningful key value,
then wouldn't the last saved key value indicate the last viewcontroller that was loaded
for the next time the program is run?
 
I'm still not sure why I'm reading this trying to gain understanding of why it's complicated.

If the first thing any viewcontoller did was write a meaningful key value,
then wouldn't the last saved key value indicate the last viewcontroller that was loaded
for the next time the program is run?

It's not very complicated. Carol's restoration ID, and those of subsequent view controllers, is set to be identical to the storyboard ID. Before the navigation controller loads Carol, Bob stores Carol's restoration ID in the database so that, unless the user is done working in Carol, a tap on Alice's button causes the navigation controller to load Carol instead of Bob.

Edit: As I said earlier, I had assumed that on the second run, Bob would never appear because I changed the behavior of Alice's button so that it doesn't load Bob. Since neither Carol nor any subsequent view controllers are supposed to tell the navigation controller to load Bob, Bob should not appear at all. Strangely, when I click Carol's back button, Bob appears.

Edit #2: I think I see where your confusion lies. I'm doing something a bit like what you suggested. I have a managed object that gets passed from one view controller to the next. This managed object has a property that stores the current view controller. However, the app needs to save all changes so that it can always remember the last view controller the user was on. It doesn't do that automatically. I have to call the app's managed object context's save: method.

To get a better idea of how storing data works in my app, read about the Core Data framework.
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.