I want to pass a value to a property from one class to another.
In LAClaimReportViewController, I have a property
#property (strong, nonatomic) LAClaimReport *claimReport;
I want to pass the value to claimReport property (of LAClaimReportViewController)from below code of masterViewController.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([record.submitted isEqualToNumber:#0] && record != _selectedReport)
{
[self.detailViewController.navigationController popToRootViewControllerAnimated:NO];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
LAClaimReportViewController *claimReportViewController = [storyboard instantiateViewControllerWithIdentifier:#"ClaimReportView"];
[self.detailViewController.navigationController pushViewController:claimReportViewController animated:YES];
//Question: i want to assign record to claimReport of LAClaimReportViewController. how to do that.
}
}
#try this
[claimReportViewController setclaimReport:selectedReport];
Related
I have navigate to a new class with view by the below table view delegate method but I get a black screen returned.
#import "NewClass.h"
- (void)tableView: (UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName: #"MainStoryboard" bundle: [NSBundle mainBundle]];
NewClass *new = [storyboard instantiateViewControllerWithIdentifier: #"newDetail"];
new.array = localArray;
[self presentViewController: new animated: YES completion: nil];
}
I have NSLog the array on the new class there and the data is received in the new class, all the storyboard name, identifier tag are correct placed, but I don't know why I still getting a black screen, could anyone help me point out what is the error cause there?
try this code:
- (void)tableView: (UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
NewClass * new = [storyboard instantiateViewControllerWithIdentifier:#"newDetail"];
new.array = localArray;
[self.navigationController pushViewController:new animated:YES];
}
It should be,
ViewController *new = [storyboard instantiateViewControllerWithIdentifier: #"newDetail"];
And make sure the id of your view controller is set to newDetail on storyboard
In ViewControllerA I have a table with three rows of data right now (three messages). Clicking on a row, I'm trying to push to ViewControllerB with the text from one of the rows (the name). Problem I'm having is I'm trying to do everything programmatically, not using storyboard ids or storyboard segues. Is this possible? Here's what I have.
ViewControllerA m.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
Messages *cell = (Messages *)[tableView cellForRowAtIndexPath:indexPath];
NSString *from = [NSString stringWithFormat:#"%#", cell.from.text];
ViewControllerB *VCB = [[ViewControllerB alloc]init];
VCB.from = from;
[self.navigationController pushViewController:VCB animated:YES];
//using this^ creates a new view controller with a black screen but passes the variable
//[self performSegueWithIdentifier:#"pushMessage" sender:self];
using this^ shows my ViewControllerB perfectly but the value isn't set
}
ViewControllerB h.
#property (strong, nonatomic) NSString *from;
ViewControllerB m.
-(void)viewDidLoad{
NSLog(#"%#", from);
}
Is there a way to do this without initiating a new viewcontrollerB in VCA and getting the right push animation?
I believe I understand what you're asking and you are almost on the right track here. You said that it works when you use [self performSegueWithIdentifier:#"pushMessage" sender:self]; but the value is not set.
So, declare an NSString "from" in your header and in the previous code delete the [self.navigationController pushViewController:CVC animated:YES];
//ViewControllerA.h
#property (copy, nonatomic) NSString *from;
//ViewControllerA.m
#synthesize from;
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Messages *cell = (Messages *)[tableView cellForRowAtIndexPath:indexPath];
from = [NSString stringWithFormat:#"%#", cell.from.text];
[self performSegueWithIdentifier:#"pushMessage" sender:self];
}
Then you need to use the prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
//ViewControllerA.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"pushMessage"]) {
ViewControllerB *vcb = [segue destinationViewController];
[vcb setFrom:[self from]];
}
}
EDIT
Well, I feel like this is a really wrong way to do it. But, this will satisfy all of your conditions asked in the question. I have checked and this does in fact work:
First, Go to your storyboard, click on the View Controller B, click on the identity inspector and change the Storyboard ID. Also click the check that says "Use Storyboard ID".
In your ViewControllerA:
//ViewControllerA.h
- (void)callViewControllerWithCellString:(NSString *)str;
//ViewControllerA.m
- (void)callViewControllerWithCellString:(NSString *)str
{
NSString * storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
SecondViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"ViewControllerB"];
[vc setFrom:str];
[[self navigationController] pushViewController:vc animated:YES];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Messages *cell = (Messages *)[tableView cellForRowAtIndexPath:indexPath];
NSString *from = [NSString stringWithFormat:#"%#", cell.from.text];
[self callViewControllerWithCellString:from];
}
So lets see if i understand this.
You want the text from the clicked row passed to the view controller that you want to present
You want to do this without using storyboards
Sounds simple enough. Check this out.
// I actually recommend this option
// Simply initialize your view controller with the text that you want to pass
ViewControllerB * VCB = [[ViewControllerB alloc] initWithText:from];
// For this to work, you'll have to declare a new init method in your .h file like this
-(void)initWithText:(NSSTring *)text;
// You should also declare an iVar to store your text
NSString * fromText;
// and implement it in your .m file like this
-(void)initWithText:(NSString *)text
{
self = [super init];
if (self)
{
fromText = text;
}
return self;
}
// Or, you could do this.
// In ViewControllerB.h, create a property
#property (nonatomic, strong) NSString * fromText;
// In ViewControllerB.m, synthesize it
#synthesize fromText;
// Then you can pass that property a value like this
ViewControllerB * VCB = [[ViewControllerB alloc] init];
VCB.fromText = from;
Variables shoudl be lower case.
Your ViewControllerB should be displaed. Do you create all view elements in there programatically too? If you don't then you better load it from a XIB or from the storyboard. You can do that without segueing to it.
But I guess it is much easer to overwrite the perpareForSegue: method and set the from property there. That is what perpareForSegue is made for when you need to do some customization programatically while using storyboards for all the easy stuff.
First off, you should check your code. You are pushing a viewController named CVC onto the navigation controller. I assume this is a typo.
Did you override ViewControllerB "initWithNibName:bundle:" as I see you are calling init. How would the ViewController know what nib to load if you didn't?
Also, it is recommended that you call [super viewDidLoad] in your viewDidLoad call.
You can push views programmatically as well.
You seem to do following
ViewControllerB *VCB = [[ViewControllerB alloc]init];
VCB.from = from;
[self.navigationController pushViewController:CVC animated:YES];
Which means you want to push VCB and not CVC. This change should fix your problem.
You can also put a breakpoint in viewDidLoad to verify your new ViewController is loaded.
If you are using storyboard for VCB as well, I think you should do following --
ViewControllerB *VCB = [self.storyboard instantiateViewControllerWithIdentifier:#"VCBIdentifier"];
where VCBIdentifier is the identifier to your ViewControllerB marked in Identity Inspector -> StoryBoardID.
With your current init, I think, it is creating a default viewcontroller which is blank/empty.
I've got a view in a xib file that I load to my viewController - its a temp view and thus isn't on screen all the time. However the temp view and the main view, use the same view controller class as they both are doing the same job.
Now, in the xib view I load up a second viewControoler - lets call it viewControllerB - which is a UITableView with 197 cells. Once a cell is selected, the view is dismissed and the value of the cell is returned to viewControllerA.
viewControllerB is on the storyboard.
Here is the code I have used:
viewControllerB (The VC I need data back from)
Delegate Protocol:
#protocol CountrySelectedDelegate <NSObject>
-(void)selectedCountry: (id)countryReturned;
#end
#property (strong, nonatomic) id <CountrySelectedDelegate> myDelegate;
Then in the .m file:
Set the delegate:
ViewControllerA *viewA = [[ViewControllerA alloc]init];
self.myDelegate = viewA;
Then I call the delegate in the same file;
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self myDelegate] selectedCountry:indexPath.row];
[self dismissViewControllerAnimated:YES completion:nil];
}
Now in viewControllerA:
pragma mark - CountrySelected Delegate
-(void)selectedCountry:(id)countryReturned
{
self.testInt = countryReturned;
}
Now this method does get called by the delegate. Looking in the console: countryReturned is the correct value. Once this method has finished, self.testInt is also the correct value.
Then, in my viewWillAppear method, I simply check the value again to see if its still the same with a NSLog print.
the value is always nil in the viewWillAppear method (Or anywhere else I check it) - I have tried with NSMutableString and NSString - always nil.
Why are my properties / instance variables getting set to nil?
Update:
This is how I show viewControllerB
- (IBAction)countrySelect:(UIButton *)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UITableViewController *vc = [sb instantiateViewControllerWithIdentifier:#"CountrySelection"];
vc.modalTransitionStyle = UINavigationControllerOperationPop;
[self presentViewController:vc animated:YES completion:NULL];
}
On ViewB do the below I guess you have already done
#protocol CountrySelectedDelegate <NSObject>
-(void)selectedCountry: (NSInteger)countryReturned;
#end
#property (week, nonatomic) id <CountrySelectedDelegate> myDelegate;
and in didSelectRowAtIndexPath
if ([[self myDelegate] respondsToSelector:#selector(selectedCountry:)])
{
[[self myDelegate] selectedCountry:indexPath.row];
}
On ViewA
Conform the protocol
#interface ViewA : UIViewController < CountrySelectedDelegate >
create the call ViewB
ViewB *viewBObjc=[[ViewB alloc] init];
[viewBObjc setMyDelegate:self];
[[self navigationController] presentViewController:ViewB animated:YES completion:Nil];
implement the delegate on ViewA
-(void)selectedCountry: (NSInteger)countryReturned
{
NSLog(#"Country Id is :%d", countryReturned);
}
Try this,
Set delegate by
//in ViewControllerB
self.myDelegate = [self parentViewController];
or
- (IBAction)countrySelect:(UIButton *)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
ViewControllerB *vc = (ViewControllerB *)[sb instantiateViewControllerWithIdentifier:#"CountrySelection"];
vc.modalTransitionStyle = UINavigationControllerOperationPop;
vc. myDelegate = self;
[self presentViewController:vc animated:YES completion:NULL];
}
In my DetailViewController.h I've declared the property * type as seen below:
#interface DetailViewController : UIViewController
#property (strong, nonatomic) NSString *type;
#end
Then I got a ListViewController which is a UIViewController containing a TableView.
The ListViewController.h looks like this:
#interface ListViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#end
In my ListViewController.m I want to change the value of * type a soon I switch the View (view switching is working fine).
I'm doing this by adding the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UINavigationController * navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];
DetailViewController * detailController = [[DetailViewController alloc] init];
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController:navigationController animated:YES];
}
When I put a breakpoint at the second line in this block/function I get detailController with in it * type.
When I NSLog this a few lines later it return "(null)".
The View is changed but but the type is not set.
I can't figure out what I'm doing wrong?
Someone who has a solution for this or can point me to something we're this is explained?
Because I tried searching for the answer but I couldn't find anything equivalent to my problem, or I used the wrong search terms..
in your didSelectRowAtIndexPath: method change the following lines`
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController * detailController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];;
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController: detailController animated:YES];
}`
in your storyboard select DetailViewController and give storyboard id as "DetailController". Make sure your ListViewController is embed in UINavigationController, you can do that by selecting ListViewController and go to editor->Embed in->Navigation Controller. Follow these steps and your problem will be solved.
OR you can give segue from your ListViewController to DetailViewController and use
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *path = [self.tableView indexPathForSelectedRow]; //create tableview outlet
[segue.destinationViewController setType:#"video"];
}
What is this for?
UINavigationController * navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];
Why are you pushing a navigation controller inside a navigation controller?
[self.navigationController pushViewController:navigationController animated:YES];
detailController was not used or displayed.
Try this instead:
[self.navigationController pushViewController:detailController animated:YES];
Look at the last line - you are telling the nav controller to push itself!
It should be like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController * detailController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController:detailController animated:YES];
}
Is the navigation controller and the alloc-init method both instantiates the save view controller??
If yes, try this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController * detailController = [[DetailViewController alloc] init];
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController:detailController animated:YES];
}
I have a Master-Detail app and I want to load a new view on the click of rows in Master. If I select row-1, the view is different, and on selection of a different row, new view is presented in Detail portion. How can I achieve this thing?
I am doing something like this. The issue is - If I select any of these 2 rows for the first time, the view actually changes. But again when I click on the other row, it does not change.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0){
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
TwitterTweetViewController *detailView=(TwitterTweetViewController *)[storyboard instantiateViewControllerWithIdentifier:#"TwitterDetailView"];
self.splitViewController.mainViewController = detailView;
[self.splitViewController.mainViewController viewDidLoad];
[self.splitViewController viewDidLoad];
}
if(indexPath.row == 1)
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
TwitterDetailViewController *detailView=(TwitterDetailViewController *)[storyboard instantiateViewControllerWithIdentifier:#"TwitterDetailView"];
self.splitViewController.mainViewController = detailView;
[self.splitViewController.mainViewController viewDidLoad];
[self.splitViewController viewDidLoad];
}
}
What should I do in order to change the view on selecting these rows?
There is a great method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Use it. It is called right after the click has been made on a cell. You can put some check in there. Short example:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
SomeViewController *svc = [[SomeViewController alloc]initWithNibName:#"SomeViewController" bundle:nil];
[self.navigationController pushViewController:svc];
} else if (indexPath.row > 0 && indexPath.row < 5) {
SomeOtherViewController *sovc = [[SomeOtherViewController alloc]initWithNibName:#"SomeOtherViewController" bundle:nil];
[self.navigationController pushViewController:sovc];
} else {
AnotherViewController *avc = [[AnotherViewController alloc]initWithNibName:#"AnotherViewController" bundle:nil];
[self.navigationController pushViewController:avc];
}
//some other code if needed
}
Hope it helps
You can create an enum of your view controllers as :-
enum MyViewControllers
{
viewcontroller1
viewcontroller2
viewcontroller3
}
The constatns in enum would correspond to your viewcontrollers for each indexPAth.
and then in the delegate method of UITAbleVIew didSelectRowAtIndexPath: , use switch case :-
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
switch(indexPath.row)
{
case 1:
Load view1
break;
case 2:
Load view2
break;
case 3:
Load view3
break; .
.
so on.
}
}
Or in case of different NavigationControllers (as in iPad )you will have to pass data using delegates and protocol.Define the protocol in rootViewController and then set its delegate in the detail(Where you want to push the viewcontroller)
somethinglike :-
#protocol SendSelectedINdexDelegate
{
#required
-(void)sendTheIndex:(NSNumber)number.
#end
in interface
id <SendSelectedINdexDelegate> delegateSend
set its property:-
#property (nonatomic) id delegateSend;
in .m
#synthesize delegateSend
and in didSelectRowAtIndexPath:-
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
[self delegate]sendTheIndex:indexPath.row];
}
At the receiving controller
conform to protocol
and set
rootview.delegateSend=self;
and implement the method of protocol;
-(void)sendTheIndex:(NSNumber)number
{
//nsnumber is your index perform operation based on this.
}
Take care that if you are using ARC,it forbids synth of a property with unspecified ownership attribute( in .m #synthesize delegateSend).