Basically i am using a segue to display a modal ViewController.
I want to the modal ViewController to display a custom subclass of UIView which i have declared as a strong property in my main ViewController like this:
#property (nonatomic,strong) myView *theView;
in prepareForSegue:sender: i adjust the custom UIViews frame and add it to the modal ViewController:
-(void)prepareForSegue:(UIStoryBoardSegue*)segue sender:(id)sender{
UIViewController *destination = [segue destinationViewController];
[self.theView setFrame:destination.view.bounds];
[destination.view addSubview:self.theView];
}
Aside from the View still being the wrong size, only works the first time i invoke it. The second time it will crash with EXC_BAD_ACCESS on the
[destination.view addSubview:self.theView];
line.
Any ideas why this is happening?
Thanks in advance
Related
I am beginning to learn Objective-c and my problem is the following:
I have created a UIView to create a profile and in that UIView, i have an imageView for the Picture as a Datepicker for the Birthday and a Slider for the Weight of the person. When the user presses the button "Conclude" i wish for him to have his Profile created and show all the info that it was set before , Picture , Birthday,name and Weight there.
I tried to use prepareForSegue but i have no idea of what i am doing so could you guys give me a little hint on what i can do to make it work? thank you :)
In the view controller you will be segueing to, you can setup variables to hold the information from the original view controller, then assign them in prepare for segue.
So in your destination view controller .h file, declare
#property (nonatomic) UIImageView *imageView; then in your prepare for segue in your original viewController
NextViewcontroller *nvc = [segue destinationViewController];
nvc.imageView = currentImageView;
You can access the imageView in the destination view controller by calling self.imageView
I have two views. The main view is ViewController and the next is AddItemViewController. ViewController has a tableview that lists items that you add when you go to AddItemViewController. There is a button on AddItemViewController that segues back to ViewController. The problem is, upon returning to ViewController expecting that an item be added, the private data of ViewController is suddenly set to nil. I have lost data and any chance to interact with my objects after returning from the segue.
Here is the data that's getting set to nil
#property (strong, nonatomic) costEstimator *myCost;
#property NSString *testString;
What am I doing wrong?
Here is my prepareforsegue code in the AddItemViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
ViewController *vC = [segue destinationViewController];
[vC addSomething:_selectedItem withQuantity:[_quantBox.text doubleValue]];
}
Any help is greatly appreciated. Thanks :)
You want to pop the AddItemViewController in this case. When you segued from ViewController to AddItemViewController, I am guessing you did a push. What this does effectively is it adds AddItemViewController ontop of ViewController in the memory stack. By 'segue-ing' again from AddItemViewController to ViewController, you are adding ANOTHER ViewController instance ONTOP of AddItemViewController. This is why you think you are losing your data when in actuality, you aren't. You are only seeing the wrong view controller.
I have been trying to have a better understanding on how to pass data between view controllers and everything is make more sense but there is one thing I would like to understand better.
I came across this thread/tutorial here at StackOverFlow (Passing Data between View Controllers), I tried it and it worked as expected, but the one thing I don't know understand is why we can change a BOOL property located in the second view controller but NOT a Label. In other words if I add a second property and try to change the label in the prepareForSegue: method it doesn't work, why?
In section Passing Data Forward using Segue's I tried adding a second property for a label in the second view controller, right where isSomethingEnabled is, like this...
#property(nonatomic) BOOL *isSomethingEnabled;
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
Than in prepareForSegue: method located in the first view controller I did this..
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showDetailSegue"])
{
ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
controller.isSomethingEnabled = YES;// this works fine
controller.myLabel.text = #"Hello"; // here, no error but it doesn't update the label
}
}
Why you can modify a BOOL property located in a second view controller but not a label? Can someone explain this a little bit?
Thanks a lot
As Grzegorz Krukowski said the UIViewController isn't loaded at that moment. You can set #property values and access them in the viewDidLoad method and setup your Labels accordingly.
First of all, you should not do this. You should treat another view controller's views as private. The reason for this is the concept of encapsulation. A view controller's views are part of the view's appearance, not it's API. If at a future date you decide to refactor the VC so that it uses the text string in question as the title in a navigation controller, you should be free to do this. If another view controller reaches inside your view controller and manipulates it's view objects directly, you must keep those view objects unchanged forever, or you run the risk of breaking the way the other view controller interacts with it. That's bad, and 6 months from now you won't remember that 3 outside view controllers manipulate your view controller's views, and when you forget and change your views and decide to move a piece of text to a different UI object, your app will stop working correctly.
What you SHOULD do is to add a string property to your ViewControllerB, and set THAT in your prepareForSegue. Then in ViewControllerB's viewWillAppear:animated method, fetch the contents of that string property and install it in your label's text property.
Then the string property becomes part of your view controller's API contract (its public interface.) By adding a public string property to your interface, you guarantee that you will accept string values to that property and that you will do the right thing with them.
Now, as to why it doesn't work. A view controller's view hierarchy is not loaded until it's displayed. At the time of prepareForSegue, the view controller has been initialized, but it's views haven't been loaded yet. All its IBOutlets are nil. (this is another reason why you should not try to manipulate another view controller's views BTW)
Your prepareForSegue method looks like this: (wrong)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"showDetailSegue"])
{
ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
controller.isSomethingEnabled = YES;// this works fine
controller.myLabel.text = #"Hello"; // here, no error but it doesn't update the label
}
}
Instead, your code should look like this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"showDetailSegue"])
{
ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
controller.isSomethingEnabled = YES;// this works fine
controller.textToShow = #"Hello"; //This is the change
}
}
Then, in your ViewControllerB's viewWillAppear:animated method:
- (void) viewWillAppear: animated;
{
[super viewWillAppear: animated];
//install the text from our textToShow property into the label
self.myLabel.text = self.textToShow;
}
I am attempting to perform a Storyboard segue from a UIbutton that is a day on a calendar to a DayViewController with info on that day. The currentTitle of the sender UIbutton should be passed to a UILabel in the dayView of the DayViewController. It successfully segues to the new VC and assigns the button title to a property therein, however the dayView (and the base view) of my DayViewController is not getting initialized (their addresses in the debugger are both 0x0) and I get a blank page. How can I get these views to initialize in this segue? (I thought views linked to a VC were automatically initialized when segued to?)
Here's the prepareForSegue getting called:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(UIButton *)sender
{
if ([segue.identifier isEqualToString:#"ShowDay"]) {
DayViewController *vc = segue.destinationViewController;
[vc setCurrentDayNumber:sender.currentTitle];
}
Here is setCurrentDayNumber in the new VC
-(void)setCurrentDayNumber:(NSString *)currentDayNumber
{
_currentDayNumber = currentDayNumber;
[self.dayView setNeedsDisplay];
}
Here is my view that is linked to DayViewController in the storyboard.
#property (nonatomic, weak) IBOutlet DayView *dayView;
Thanks in advance!
When you declare a property as weak, it will not "hold on" to the value unless someone else has a reference to it as well. When the new view controller is pushed, the old button goes away, leaving currentDayNumber as the only reference, so it automatically sets itself to nil. (This is what weak is supposed to do.)
If you want to keep a reference to it no matter what, use strong instead of weak and make sure to set _currentDayNumber to nil somewhere (like viewDidUnload) so that you don't retain it forever.
I'm trying to implement an iBooks-like flip transition as a storyboard. The segue should push resp. pop the destinationViewController onto/from the UINavigationControllers stack.
I can push viewcontrollers in my segues perform method but I am not able to pop. When I pop the controller right after creating my flip animation the animation does not run and its callback - that should perform [[UIApplication sharedApplication] endIgnoringInteractionEvents] gets never called and my App results dead.
So I tried to push/pop in the animationDidStop:anim:flag delegate method but it never gets called with the flag set to true.
I assume that the segue is deallocated before the delegate method gets called. What else could I do?
Forgive me if I am completely misunderstanding this question, but it seems like you just want to do a basic horizontal flip back and forth between two view controllers. And even if you've already figured this out, maybe it will help anyone else who has the same question.
(1) In your storyboard (that has ViewController A & B) create a Modal Segue from A to B. Give it an identifier (showViewControllerB) and choose Transition:Flip Horizontal.
We set up the protocol and delegates:
(2a) In ViewControllerB.h add above #interface:
#class ViewControllerB;
#protocol ViewControllerBDelegate
- (void)viewControllerBDidFinish:(ViewControllerB *)controller;
#end
(2b) Add the delegate as a property:
#property (weak, nonatomic) id <ViewControllerBDelegate> delegate;
(3a) In ViewControllerB.m synthesize:
#synthesize delegate;
(3b) And delegate in the method to flip back:
- (IBAction)flipBack:(id)sender
{
[self.delegate viewControllerBDidFinish:self];
}
(4) In ViewControllerA.h add at the very top #import "ViewControllerB.h" and on the end of #interface <ViewControllerBDelegate>
(5a) In ViewControllerA.m add the method to conform to the protocol:
- (void)viewControllerBDidFinish:(ViewControllerB *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
(5b) Then set it as the delegate in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showViewControllerB"]) {
[[segue destinationViewController] setDelegate:self];
}
}
I hope this answers your question. If I misunderstood, just let me know.
Your question is a bit confusing as so mingle pop, push, flip and backflip. I´m not sure if ai can answer your question, but i can tell what i did.
If i push a viewController into the navigation controller stack and set the Storyboard Segue Style to Push, it will be pushed into the view from right to left. A back button appears and shows the title of the presentingViewController in it.
If i set the Storyboard Segue Style to Modal i can set the Transition to Flip Horizontal (what seems to be what you want). But then no Back Button will appear. In the presentedViewController i dismiss the view with:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
It will flip the second view back with a right flip.
But this is the dirty solution and it is not recommended by apple.
http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ManagingDataFlowBetweenViewControllers/ManagingDataFlowBetweenViewControllers.html#//apple_ref/doc/uid/TP40007457-CH8-SW9
Luke Dubert gave you an example how to implement the delegate.