I have two view controllers: CropImageViewController and ImageCropperViewController
In CropImageViewController I have this method:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepareForSegue called");
if([segue.identifier isEqualToString:#"goBack"])
{
NSLog(#"processedText = %#",self.processedText);
[segue.destinationViewController setProcessedText:self.processedText];
}
}
Then, in ImageCropperViewController, I have this:
-(void)viewWillAppear:(BOOL)animated
{
NSLog(#"view will appear called");
//self.processedImageLabel.text = self.processedText;
NSLog(#"processedText = %#",self.processedText);
NSLog(#"testLabel: %#",self.testField.text);
}
This is the console output. For some reason, "processedText" is always NULL no matter what.
2014-05-23 16:51:43.488 ImageCropper[9294:60b] prepareForSegue called
2014-05-23 16:51:43.490 ImageCropper[9294:60b] processedText = E33
===..., ____
2014-05-23 16:51:43.493 ImageCropper[9294:60b] view will appear called
2014-05-23 16:51:43.494 ImageCropper[9294:60b] processedText = (null)
I see your segue "goBack". Are you come back after pushed CropImageViewController from ImageCropperViewController?
So in this case you shouldn't use a segue. You should write an IBAction for your button (or i don't know what you have to come back) and when you press it do:
[self popViewControllerAnimated:YES];
but before this, you should call the delegate to pass the new value:
[_delegate changeProcessedText:self.processedText];
Obviously i assume that you know how implement a delegation pattern.
Another way could be use KVO, so observing from the first viewController, the processedText.text value in the second viewController.
Related
I have made a segue passing a string which tells the next view controller which instance to parse the CoreData for. The problem is, I am using some code that calls init methods and the sent string is not initialized when it is called. However, the segue is working when I display the string in the destination view controller's viewDidLoad
- (id)init
{
self = [super init];
if (self)
{
[self initFakeData];
}
return self;
}
When that initFakeData method is called it sets up a graph and needs the exercise to hold a valid value
- (void)initFakeData
{
NSString *myExercise=exercise; //returns nil
if (myExercise==nil)
{
myExercise=#"Default";
}
}
Meanwhile...
-(void)viewDidLoad{
NSString *myExercise=exercise; //returns value
}
exercise is a property that is initialized by the previous view controller in a tableview
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if ([segue.identifier isEqualToString:#"showGraph"]) {
JBLineChartViewController *destViewController = segue.destinationViewController;
NSString *myExericse=[NSString stringWithFormat:#"%#", [[_exercises valueForKey:#"exercise"]objectAtIndex:indexPath.row]];
NSLog(#"%#",myExericse);
destViewController.exercise = myExericse;
}
}
The behaviour is correct because during init the exercise in JBLineChartViewController was not set. If you need the exercise attribute in the init method to set certain behaviour that have to be before viewDidLoad, my suggestion is to not use segue but do a designated initWithExercise and push the controller in code. Maybe like this:
- (IBAction)chartButtonPressed:(id)sender {
JBLineChartViewController *vc = [[ShopViewController alloc]initWithExercise:#"EXERCISE_STRING_HERE"];
[self showViewController:vc sender:self];
}
The new view controller is allocated and initialized before prepareForSegue is called. Anything you need to do with CoreData should be done in viewDidLoad. Or you can do it later, e.g. in viewWillAppear or viewDidAppear.
I found a really good walk through of how to pass string values back from a ViewController to a calling ViewController and got it working perfectly. The example is really very good.
https://www.youtube.com/watch?v=YVikeoR3gYg
That said, the technique for passing back content seems relatively straight forward now that I have seen it, even if it's not that intuitive.
The example code however only includes two controllers. When I replicated the code using a much more detailed Storyboard, the code simply doesn't work. In my test app, I even embedded the calling Controller inside a NavigationController to see whether this would have an affect, but it still continued to work fine.
In my application, the ViewController is embedded within a NavigationController that is called via a SWRevealController segue class. I don't know if this is important or relevant but I am mentioning it.
I then call a CollectionViewController to choose an icon that should be passed back to the calling ViewController.
When I select the icon, I correctly identify the icon and pop
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
selectedIcon = [placeIcons objectAtIndex:indexPath.row];
NSLog(#"In IconCollectionViewControlled - selected %#", selectedIcon);
NSString *itemToPassBack = #"12345"; // Just testing any old string here...
// [self.delegate passBackIcon:selectedIcon]; // commenting out while testing
[self.delegate passBackIcon:itemToPassBack];
[self.navigationController popViewControllerAnimated:YES];
}
I get a correct trace suggesting that the right icon is selected. I would then expect that the text '12345' would be passed back to the calling Controller.
In my calling Controller, I have the following:
- (void)passBackIcon:(NSString *)iconName {
NSLog(#"Icon to use is %#", iconName);
}
But this just isn't being called at all (or at least I'm not seeing the NSLog being shown. It's just being ignored.
The delegate is being correctly declared as far as I can tell.
Am I missing something?
assuming you are working with segues, in the method prepareSegue you should setting the delegate
for Example :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"YOUR_SEGUE_IDENTIFIER"] ) {
DestinationVc *vc = (DestinationVc *)segue.destinationViewController;
[vc setDelegate:self];
}
}
Hope it works for you
I've found this to be the easiest way to pass string and other information around using a tableView.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ViewControllerYouWantToPassToo *result = [self.storyboard instantiateViewControllerWithIdentifier:#"NameOfTheViewController"];
result.stringName = #"12345" // String Name is a NSString property you set up in the ViewController you want to pass too
[self.navigationController pushViewController:result animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I suggest you wrapping your delegate in a check to see that it is valid and that it has adopted the respective method (if optional).
if(self.delegate && [self.delegate respondsToSelector:#selector(passBackIcon:)]){
[self.delegate passBackIcon:itemToPassBack];
}else{
NSLog(#"Your delegate is not setup correctly");
}
If it enters the else, you have not set the delegate properly..ie you likely never did
self.delegate = SomeInstanceOfAClassThatAdoptsYourDelegate;
I'd like to pass some object from one view (number 2) to view number 1. View 1 triggers view 2 and before that in "prepareForSeque" I'm passing "self" to the second view and store it in variable "delegate". After some time I'd like to pass back new created object to view 1 and I'm trying to achieve it but I got an error that method is not visible for this interface. How to pass created object to the mother view triggering method?
When I declare #property someObject and synthetize it, it works ok using delegate. Is there another option or am I forced to use delegate?
Code:
- (IBAction)saveAndClose:(id)sender {
KwejkModel *mod = [[KwejkModel alloc] init];
((ViewController *)self.delegate).model = mod;
}
It works ok, but is there another option triggering method not using the property? Like this:
[((ViewController *)self.delegate) someMethod];
but here is an error.
Here is my code:
VIEW 1
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"addItemSeque"]) {
ScrollViewViewController *destViewController = segue.destinationViewController;
destViewController.delegate = self;
}
}
-(void) addNewPosition:(KwejkModel *)newKwejk
{
//for testing only this
[modelArray count];
}
VIEW 2:
- (IBAction)saveAndClose:(id)sender {
KwejkModel *mod = [[KwejkModel alloc] init];
// ((ViewController *)self.delegate).model = mod;
//it crashes here with error:-[NSPlaceholderString initWithString:]: nil argument' but it sees method from VIEW 1
[self.delegate addNewPosition:mod];
}
Try this link: Passing Data between View Controllers
Take a look at the first answer under Passing Data Back.
In this case, I am assigning values below to stringToDisplay and want to send them to SegViewController, which also retains stringToDisplay. Do I need to use cell.textLabel.text here with isEqualToString: #"Fire House Gallery? Would I use indexPath or UITableViewCell here?
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SegViewController *seg = segue.destinationViewController;
seg.delegate = (id)self;
if ("......" isEqualToString: #"Firehouse Gallery"])
{
seg.stringToDisplay = #"Firehouse Gallery";
}
else
{
seg.stringToDisplay = #"Frog Hollow Craft Center";
}
}
Thank you,
Greg
The short answer:
You shouldn't derive data from your table view cells because they are your view. You should be "deriving data" from your model.
The longer answer:
Determining how to configure your segue depends on how you are calling it:
If you are calling it in code (using performSegueWithIdentifier:sender) then pass your string as the "sender" in your method call.
If you have setup the segue in your storyboard, then you should use different segues for each possibility, and check the segue identifier to determine which string that you should pass.
I found an answer for what I was looking for. I now have ONE segue link between two UIViewcontrollers, with the segue identifier called #"seg". For a place named Radio Bean, I use the following when the "Radio Bean" cell is pressed:
if ([cell.textLabel.text isEqualToString: #"Radio Bean"])
{
self.stringToDisplay = #"Radio Bean";
[self performSegueWithIdentifier:#"seg" sender:self];
}
Then, in prepareForSegue I DO NOT specify segue identifier but use the following:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SegViewController *seg = segue.destinationViewController;
seg.delegate = (id)self;
if ([self.stringToDisplay isEqualToString: #"Radio Bean"])
{
seg.stringToDisplay = #"Radio Bean";
}
}
This successfully passes "Radio Bean" to the next UIViewcontroller, and I can include multiple place options with the use of only ONE segue link, so, no need for multiple links.
I want to send a image to next scent.but failed.
here is my code
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepareForSegue start");
NSLog(#"count is %d",count);
//bigStyle1 is a NSArray,full of UIImage
//bigImage is a UIImageView outlet
if ([bigStyle1 objectAtIndex:count]==nil) {
NSLog(#"no array image");
}
viewController3.bigImage.image=[bigStyle1 objectAtIndex:count];
if (viewController3.bigImage.image==nil) {
NSLog(#"no controller image");
}
NSLog(#"secondToThird");
NSLog(#"prepareForSegue end");
}
here is Xcode's log
2013-03-12 15:15:38.683 animation[1876:f803] prepareForSegue start
2013-03-12 15:15:50.825 animation[1876:f803] count is 0
2013-03-12 15:17:10.829 animation[1876:f803] no controller image
It seems that the problem is in assignment of image.Why assignment failed?
UPDATE
viewController3 isn't nil.But bigImage is nil.I don't know why.I actually connect bigImage to the image view
I suspect that you intend viewController3 to be the destination of the segue. In that case, you should be setting it like this:
viewController3 = segue.destinationViewController;
I further suspect that viewController3.bigImage is a UIImageView. If so, you have a problem because viewController3 hasn't loaded its view hierarchy by the time the system sends prepareForSegue:sender:, so viewController3.bigImage hasn't been set yet. It's nil, and setting a property on nil does nothing (with no warning or error message).
It would be better to give viewController3 an image property directly, and store the image on that property. Then, in viewController3's viewDidLoad method, copy the image from that property to self.bigImage.image.
Alternatively, you can cheese it by forcing viewController3 to load its view in prepareForSegue:sender: just by asking it for its view:
[viewController3 view]; // forces it to load its view hierarchy if necessary
viewController3.bigImage.image = [bigStyle1 objectAtIndex:count];