I need to work out how to identify what storyboard is active at any given time. I have a specialised nativation in which I need to identify the storyboard (UIView) then change things programmatically depending on what the user presses.
All storyboards have Identifiers.
in the viewDidLoad of the root view I have the following.
- (void)viewDidLoad
self.topViewController =
[storyboard instantiateViewControllerWithIdentifier:#"View1"];
{
What I would like to do is identify which storyboard the user is on and depending on the press do the following sudo-code
- (void)viewDidLoad
if (storyboard.name != RootView)
self.topViewController =
[storyboard instantiateViewControllerWithIdentifier:#"View1"];
{
else if (storyboard.name = View2){
self.topViewController =
[storyboard instantiateViewControllerWithIdentifier:#"View2"];
}
etc....
I have step through the code and seen the StoryboardID however it's which I'm pretty sure your not meant to use....
Thanks in advance
Jeremy
UPDATE: Explanation to Navigation
I'm trying to implement the ECSlideViewController, but It's doing my head in. Effectively adding in the slide to the right function to reveal more options. SO, this thinking was going to be easy turned out icky. I have the master UIViewController<title:HomeView> I then have 4 buttons on the screen which segueway to other UIViewControllers<View1>, UIViewController<View2> etc.
In order to produce the effect on View1,View2,View3,View4 I need to bring the class (ECSlideViewController as per the example) into the UIViewController<HomeView>. However If I change the below code to represent this...
self.topViewController =
[storyboard instantiateViewControllerWithIdentifier:#"HomeView"];
It crashes because it calls itself. Not good, circular coding is a no no.
but if I set it to what was originally there
self.topViewController =
[storyboard instantiateViewControllerWithIdentifier:#"FirstTop"];
( btw firstTop is the title of the view used with the example)
It works but then disregards the UIViewController<HomeView>
This is why I asked if there was a way to identify the self.title of the UIViewController(said storyboard...my bad) as I was going to put conditional logic around it in order to not put the code in if it's on the UIViewController<HomeView>.
It really is hard to explain unless you download the ECSlideViewController and start playing with it. But effectively I just want to test the self.title.....I think...
The other idea was to bring the logic into the UIViewControllers of the four and get it to work there...but It freaks out passing nil as it's expecting an identifier...
Hope this makes sense....
J.
Okay Guys,
Totally ditched ECSlideViewController. I found a few articles explaining that it had issues when you had multiple UiViewControllers not passing data correctly. I ended up using Andrews suggestion. http://www.youtube.com/feed/UCJA_puohXgnze8gPaerTeig It worked for easier for me.
Although I take note of what the design guidelines Apple have an this is usually a no no, but I'm hoping that they won't mind.
Thanks everyone again!
J.
I'm not sure if this helps, but it sounds like you will have to compare instances to get the results you are looking for. I haven't tried this, but I would create properties of each storyboard in your app delegate, then reference the app delegate in your view controller to compare. This might not be the best coding practices, but I'll leave that into your hands.
Something like (untested code):
- (void)testStoryBoard //After awake from nib or viewDidLoad
{
NXAppDelegate *appDelegate = (NXAppDelegate *)[[UIApplication sharedApplication] delegate];
if ([self.storyBoard isEqual:appDelegate.view1StoryBoard])
NSLog(#"View1 Storyboard");
else
NSLog(#"View 2 Storyboard");
}
Related
I'm trying to recreate an effect similar to the iOS Music app in that I want a completely new view to appear in my app when the phone flips from vertical to horizontal (the Music app shows album covers). And I can't quite seem to get it working. So far I've tried variations of the following:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
TMFHorizontalFavoritesViewController *horizontalVC = [[TMFHorizontalFavoritesViewController alloc] init];
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation)) {
[self presentViewController:horizontalVC animated:YES completion:nil];
}
}
But at best all I seem to get is a black screen. I've tried googling and searching here on Stackoverflow for similar questions, but I can't seem to piece together the right answer. If anyone has any input it would be much appreciated!
If there's one piece of advise I could give new iOS programmers, it would be never ever instantiate a view controller with alloc init (there are times when it's legit, but newbies almost always get it wrong).
This is how you do it with a storyboard defined controller,
TMFHorizontalFavoritesViewController *horizontalVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier"];
I'm trying to come up with a good way to organize transitioning between UIViewControllers that removes the logic from the controllers themselves. I came up with a pattern based on the Pro ObjC Design Patterns book that I liked, but I'd like to know how to improve it.
The pattern in a nutshell. Forgive the semi-pseudo code.
I subclassed the UINavigation Controller and created a method that all the View Controllers call when they need to transition.
-(void)requestViewChangeByObject:(id)object withData:(object*)someData{
if ([object isKindOfClass:[ViewController1 class]]) {
[self showViewController2Animated:YES withSomeData:nil];
}
if ([object isKindOfClass:[ViewController2 class]]) {
[self showViewController3Animated:YES withSomeData:someData];
}
if...
}
Then I just defined methods for each controller. Some just instantiate and push the controller and some set properties or pass information in.
-(void)showViewController2Animated:(BOOL)animated withSomeData:(object*)someDataVariable{
viewController2 *VC2 = [viewController2 defaultViewController];
[self pushViewController:VC2 animated:animated];
}
-(void)showViewController3Animated:(BOOL)animated withSomeData:(object*)someDataVariable{
viewController3 *VC3 = [ViewController3 defaultViewController];
VC3.someData = someDataVariable
[self pushViewController:VC3 animated:animated];
}
The reason I'm doing it this way is because it makes the application much more flexible in terms of changing around controller order and adding/removing controllers as the design and requirements change. We also tend to re-use apps and this makes it easier to reskin and reorganize to build a new application.
The main problem I have is the more complicated the application gets the bigger that method with all the if statements is going to get. It might get confusing if there's more logic involved than just push viewController2 if the request comes from viewController3. I'd really like to know how I can improve this so that it's more flexible and less likely to cause confusion and errors.
Second, it's not very flexible when you add passing data around to the problem. I ended up taking the parameter out that accepted a data object and just created an separate singleton manager object that handles saving/getting the data that I needed, which I understand is not good design. However, when I tried passing the data back and forth between controllers like Apple suggests(ie setting properties on the controller as in the above code) it just became a confused mess and I feel like there's a better way to do this.
So any suggestions on this would be appreciated thanks.
I am currently in a project creating an iPad book. Unfortunately, since this is my first iPad project I am coding in a very unconventional style.
This is a 20 page book and I have 20 XIBs. On each XIB I am calling the next XIB, but my fear is that the current XIB isn't getting unloaded and still is taking up memory. When I am about on page 10 or so, the app will crash due to didReceiveMemoryWarning.
I am switching views using 2 different methods (I don't know which one will better suit my purpose):
#METHOD 1
-(IBAction)NextPage:(id)sender
{
nextPage = [[NextPage alloc] initWithNibName:#"NextPage" bundle:nil];
[self.view addSubview:nextPage.view];
[self presentModalViewController:nextPage animated:YES];
[self.view release]; // this was added to hopefully release the current view.
}
#METHOD 2
-(IBAction)NextPage:(id)sender
{
NextPage *nextpage = [[[NextPage alloc] init] autorelease];
[self presentModalViewController:nextpage animated:YES];
}
Each view has buttons and stuff, but I want to make sure I complete erase them from memory on each page call.
I used dealloc to try to remove the view, but when I check for memory leaks and go back and forth between pages, the memory crawls up.
- (void)dealloc {
[view release]; // don't know which is which
[self.view release]; // is this correct?
[super dealloc];
}
Any help is appreciated! Thanks in advance.
If you're just switching between pages in a book, you probably shouldn't be presenting modally. Instead, you could just swap out views.
http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html
... transitionFromView:toView:duration:options:completion: methods to
swap out entire sets of views for new ones.
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/clm/UIView/transitionFromView:toView:duration:options:completion:
Another option would be to use layers within a view.
http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial
If you present the next page modally (as you are doing), the current page won't be released. Instead, set your window's rootViewController to the new page.
UINavigationController could handle this much more simply. Take a look at the documentation. Also, as of iOS5 there is now a book type viewController that may serve you well.
this is my first post on here, though with the help of many questions and answers from members of this community, I have brought my project to near completion.
I have read multiple threads similar to what I'm asking, but the methods were completely different. No code has worked so far.
Basically (I say this because my code involves a lovely snake-like descent into a complicated mess, but applicable snippets will be put up upon request), my problem is that I'm calling
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
and it pushes my viewcontroller in the simulator and NSLogs the string I need changed beautifully, but it pushes a blank view! The code for that run makes the view controller variable a constant:
UIViewController *viewController = [[xSheetMusicViewController alloc]initWithNibName:nil bundle:nil];
So I thought to myself, what am I doing!? So I went back to the old method, which involved making the UIViewcontroller an if-then, if-else-then statement that would push different views depending on whether certain rows were selected (standard stuff). Which pushed a new view with my string loaded perfectly, but it only NSLog'ed one string over and over! And the worst part was the my app would call either SIGABRT, or EXC_BAD_ACCESS when I tried returning to the rootviewcontroller. (here's the applicable code):
UIViewController *viewController = [[[UIViewController alloc]init]autorelease];
if (indexPath.row == 0 && indexPath.section == 0) {
appDelegate.baseURL = #"mussette.pdf";
viewcontroller = [[xSheetmusicViewController alloc]initwithnibname:nil bundle:nil];
}
else if (...)
//pushview, changestring, blah blah//
Now, I would prefer that my view push the PDF like it's supposed to, and have the correct string value (and not give me SIGABRT or EXC_BAD_ACESS, but those are givens), but it seems that compromise is just out of my reach. I know there's probably something stupid I'm doing that could be solved with one line of code, but for now, it seems hopeless.
Thanks in advance.
EDIT: To answer all of your questions, yes, there is no xib, rather an
(id)init
method in the next view.
EDIT 2: to answer lostInTransit's request and add some additional details:
<else if (indexPath.row == 1 && indexPath.section == 0) {
appDelegate.baseURL = #"Importing PDF's.pdf";
Also, if it helps, the output keeps logging:
Application tried to push a nil view controller on target .
When I try to push the view from a tableviewcell, and it did that before when it loaded the PDF right so I ignored it.
Question: why do you first initialize your viewController as a UIViewController and then again as xSheetmusicViewController? I think the problem is with releasing values properly. In one init, you do an autorelease, in the other you don't. So chances are you are releasing a variable twice leading to the BAD ACCESS.
Do you mind posting the "blah blah" :) in the last piece of code?
Do you have a file named xSheetmusicViewController.xib in your application? That will be loaded with your view controller as its owner after you call [[xSheetmusicViewController alloc] initNithNibName:nil bundle:nil]; (it will actually be loaded when the view property is first accessed). If that file doesn’t exist, then the view controller’s -loadView: method will be called to load its view.
If you have a blank view, either you have a blank or mis-named nib (perhaps you renamed the class but not the nib?) or you aren’t creating the right view in -loadView:.
When using the the Three20 framework I have a problem with the way how TTNavigator seems to work. If in applicationDidFinishLaunching I restore the previous state of the app with:
TTNavigator* navigator = [TTNavigator navigator];
navigator.persistenceMode = TTNavigatorPersistenceModeAll;
navigator.window = self.window;
[navigator restoreViewControllers];
The methods loadView and viewDidLoad of the ViewController that was just restored never get called. How can that be so?
Is that a bug or by design?
If it's by design, what would be a good fix. My problem is that I want the ViewController to load its nib. I've seen other workarounds, but they are ugly and have outside component (like the app delegate instead of the view controller itself) load the nib, which I would like to avoid. An example of those ugly workarounds is given in the TTNibDemo example that ships with the Three20 source code.
It depends in what way you are calling viewController, try in viewWillAppear, should work.
Are you testing on device?
navigator.window = self.window;
_ [navigator restoreViewControllers];
On the device the first screen is always the first screen, whereas on the simulator that is not the case, and you should always check before with the condition
if(![navigator restoreViewControllers])
// do this
else
TTNavigationController* navi = [[((MyViewController1*)[navigator topViewController]) viewControllers] objectAtIndex:0];