Object of array in new ViewController keeps empty - ios

I've a problem with an array.
There's an array with some objects of the class Car in my CarViewController:
...Car.h
#interface Car : NSObject
#property (nonatomic, strong) NSString *name;
..and Car.m
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:name forKey:#"name"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [[Car alloc] init];
if (self != nil)
{
name = [coder decodeObjectForKey:#"name"];
}
return self;
}
and CarViewController
Car *car1 = [Car new];
car1.name = #"A1";
...
cars = [NSArray arrayWithObjects: car1, car2, ..., nil];
But when I now try to have access to this array in NewViewController there is a problem:
- (IBAction)btn:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
CarViewController *vc = (CarViewController *)[storyboard instantiateViewControllerWithIdentifier:#"CarVC"];
Car *car = [vc.cars objectAtIndex:0];
NSLog(#"%#", car.name);
}
But in the log is just written that car.name = (null).
Thanks in advance to your effort.
UPDATE:
- (IBAction)btn:(id)sender {
UINavigationController *nav = self.tabBarController.viewControllers[1];
CarViewController *vc = nav.topViewController;
Car *car = [vc.cars objectAtIndex:0];
NSLog(#"%#", car.name);
}
I've tried something (thanks to rdelmar for his effort), but the result is still the same.

if you put this code
Car *car1 = [Car new];
car1.name = #"A1";
...
cars = [NSArray arrayWithObjects: car1, car2, ..., nil];
in the viewDidLoad method of your view controller, the the result is normal because your view is not loaded yet. (the viewDidLoad method has not been called yet)
I'm not familiar with storyboards but I think when you call
CarViewController *vc = (CarViewController *)[storyboard instantiateViewControllerWithIdentifier:#"CarVC"];
it will instantiate a new ViewController. So if you try to access cars property it will be nil if this new viewController is not presented on screen
Apple Documentation
You use this method to create view controller objects that
you want to manipulate and present programmatically in your
application. Before you can use this method to retrieve a view
controller, you must explicitly tag it with an appropriate identifier
string in Interface Builder.
This method creates a new instance of the specified view controller
each time you call it.

Related

Not Updating Label From Different View Controller using NSUserDefaults

I am trying to update a label on view controller (DropPinVC) by pressing a button on different view controller 2 (TypeLocation).
In DropPinVC.m I have:
- (void)viewDidLoad
{
TypeLocation *VC2 = [[TypeLocation alloc] initWithNibName:#"TypeLocation" bundle:nil];
VC2.myVC2 = self;
[super viewDidLoad];
}
In TypeLocation.h I have:
#property (nonatomic, strong) DropPinVC *myVC2;
In TypeLocation.m I have:
-(IBAction) switchValueChanged
{
if (self.TASwitch.on){
TypeLocation = #"Tourist Attraction";
[[NSUserDefaults standardUserDefaults] setObject:TypeLocation forKey:#"Type Location"];
}
else {
TypeLocation = #"Unsafe Location";
[[NSUserDefaults standardUserDefaults] setObject:TypeLocation forKey:#"Type Location"];
DropPinVC *myVC2 = [[DropPinVC alloc] initWithNibName:#"DropPinVC" bundle:nil];
NSString *updatedLabel = [[NSUserDefaults standardUserDefaults] stringForKey:#"Type Location"];
NSLog(#"Updated Label = %#", updatedLabel);
myVC2.TypeLabel.text = updatedLabel;
[self closeScreen];
}
However, the label on view controller 1 does not update. Does anybody know a solution to this problem? Thank you for your help!
You need to pass the string, updateLabel, to a string property you create in DropPinVC, and have that controller populate its label in viewDidLoad. Your approach doesn't work because the view hasn't loaded yet at the time you try to set the label's text, so myVC2.TypeLabel will be nil.
Also, you're not using your property, myVC2 in TypeLocation. this line,
DropPinVC *myVC2 = [[DropPinVC alloc] initWithNibName:#"DropPinVC" bundle:nil];
should be,
self.myVC2 = [[DropPinVC alloc] initWithNibName:#"DropPinVC" bundle:nil];

Accessing NSDictionary of another ViewController shows null

I am using NSDictionary to plot various markers on a Map.After the pins have been plotted I click the call out of the marker to show the user details.Now when I press the call out I am passing details like marker.title and marker.snippet to another View Controller.With refrence to these values I am trying to fetch other details from the dictionary.This is what I do for accessing the dictionary from another view controller.
-(void)fetchMarkerData:(NSString *)typeOfMarker nameOfUser:(NSString *)username
{
NSString *type = typeOfMarker;
NSString *name = username;
NSLog(#"User Type - %# & Name - %# ", type, name); // shows name and type
NSLog(#"members dict from map view - %#" , self.membersDetailsDict); // shows null & self.membersDetailsDict is allocated and initialised in viewDidLoad.
if ([type isEqualToString:#"Member"])
{
for (NSDictionary *instance in self.membersDetailsDict)
{
NSString *name= [instance objectForKey:#"pseudo"];
if ([name isEqualToString:name])
{
self.nameLabel.text = name;
self.displayPicture.image =[instance objectForKey:#"avatar"];
self.cityLabel.text = [instance objectForKey:#"pays"];
}
}
}
}
Passing data this way :-
- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
UserProfileViewController *userProfileViewController = (UserProfileViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"UserProfileViewController"];
[userProfileViewController fetchMarkerData:marker.snippet nameOfUser:marker.title];
userProfileViewController.membersDetailsDict = self.membersDict; //passing dictionary also
UINavigationController *nv = [[UINavigationController alloc]initWithRootViewController:userProfileViewController];
[self.revealSideViewController popViewControllerWithNewCenterController:nv animated:YES];
It seems as though you are trying to access the membersDict variable from your second view controller which you actually instantiated again there when instead you should be accessing the actual membersDict variable from where it was originally created - in what i assume was in your ViewController1. Now from what I understand this is your setup.
Viewcontroller1 contains your maps data points stored in a variable called membersDict.
user clicks on a point and it will push a viewController2, and that's where you're trying to access the membersDict variable from viewController1.
One way you can do this is by feeding your ViewController2 with the variable from ViewController1 when youre about to push it rather than trying to access the membersDict from your `ViewController2 after its been pushed.
So you can do something like this, this is just a crude quick example:
// in .h viewController file
NSMutabledictionary *membersDict; //whatever the data object was that you stored the data in
//in .m viewController1 file
//viewDidLoad method
membersDict = [[NSMutableDictionary alloc] init];
//add whatever data you like to your membersDict
//In section of code where youre about to push your second ViewController 2: Pass the members dict data too along with pushing the second viewController.
ViewController2 = [[ViewController2 alloc] initWithWhatever];
viewController2.membersDict = self.membersDict; //
or
ViewController2 = [[ViewController2 alloc] initWithMembersDict:self.membersDict];
//Then push the viewController2.
This will ensure your membersDict data successfully passes on.

Property getting set then reset in init

Here's the property declaration in my SlidingVC header, a subclass of UITableViewController:
#property (strong, nonatomic) NSString *user;
Here's my synthesize line:
#synthesize user = _user,sortedWordlist = _sortedWordlist, wordlist = _wordlist;
Here's my custom init:
- (id)initWithUser:(NSString*)theUser
{
self = [super init];
if (self) {
if ([theUser isEqualToString:#"user"]) {
_user = #"user";
}
else if ([theUser isEqualToString:#"opponent"]){
_user = #"opponent";
}
}
return self;
}
So what's happening is that as I step pver initWithUser:, I see that _user takes on the memory address of theUser in the variable debugger window. I step over return self and then to the closing } of the method and it's still set. However, Xcode returns to return self one more time and then if I step over that _user doesn't have a memory address next to it anymore, and it remains null for the methods that follow.
Why is it returning twice and then setting to null the second time?
Here's the method in my MainVC that instantiates the SlidingVC:
- (WSWordlistTableViewController *)setupWordlistTableViewController:(NSString*)user
{
WSWordlistTableViewController *wordlistTableViewController;
UIView *wordlistContainerView;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
if ([user isEqualToString:#"user"]){
if(!self.userWordlistTableViewController){
self.userWordlistTableViewController = [[WSWordlistTableViewController alloc] initWithUser:#"user"];
wordlistTableViewController = self.userWordlistTableViewController;
wordlistContainerView = self.userWordlistContainerView;
}
}
else if ([user isEqualToString:#"opponent"]) {
if(!self.opponentWordlistTableViewController){
self.opponentWordlistTableViewController = [[WSWordlistTableViewController alloc] initWithUser:#"opponent"];
wordlistTableViewController = self.opponentWordlistTableViewController;
wordlistContainerView = self.opponentWordlistContainerView;
}
}
wordlistTableViewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"wordlistTableViewController"];
wordlistTableViewController.view.frame = wordlistContainerView.bounds;
wordlistTableViewController.view.autoresizingMask = wordlistContainerView.autoresizingMask;
[self addChildViewController:wordlistTableViewController];
[wordlistContainerView addSubview:wordlistTableViewController.view];
[wordlistContainerView bringSubviewToFront:wordlistTableViewController.wordlistTableView];
[wordlistTableViewController didMoveToParentViewController:self];
return wordlistTableViewController;
}
And the method that calls that, depending on which button is pressed:
- (IBAction)slideUserWordlistView:(id)sender {
if(!self.userWordlistTableViewController){
[self setupWordlistTableViewController:#"user"];
}
// (sliding drawer code here)
}
Or:
- (IBAction)slideOpponentWordlistView:(id)sender {
if(!self.opponentWordlistTableViewController){
[self setupWordlistTableViewController:#"opponent"];
}
// (sliding drawer code here)
}
What I'm doing is sliding out a view that contains my SlidingVC. I have two of them, one for each of two users. When each respective button is pressed I check if each respective SlidingVC exists, if not, instantiate then add to the the slidingViewContainer.

Using delegate from different classes

Having some difficulty getting my delegate to "work".
It works when the ClassA pushes ClassB onto the stack via UINavigationController, but ClassB does not call the delegate method (in ClassA) when ClassB is pushed by a different ClassC.
This method from within ClassA works:
- (void)openViewController:(NSString *)title:(int)dataType:(NSArray *)currentData {
ClassB *nextController = [[ClassB alloc] initWithNibName:#"ClassBView" bundle:nil];
nextController.delegate = self;
nextController.title = title;
nextController.dataType = dataType;
nextController.currentData = currentData;
nextController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:nextController animated:YES];}
How do I get this method, from ClassC, to properly designate ClassA as the delegate for ClassB???
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ClassB *nextController = [[ClassB alloc] initWithNibName:#"ClassBView" bundle:nil];
nextController.delegate = ??????????
nextController.title = [self.tableData objectAtIndex:indexPath.row];
nextController.dataType = self.dataType;
nextController.currentData = [NSArray arrayWithArray:[self.dictionary objectForKey:[self.tableData objectAtIndex:indexPath.row]]];
nextController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:nextController animated:YES];}
Appreciate any assistance. Cheers.
I feel like knowing more about the view controller hierarchy in the app would help, but it sounds like you'll need to add a reference to ClassA in ClassC that it could pass on to ClassB. So (in ClassC) nextController.delegate = self.ClassARef

Passing info between views in uinavigation

I'm implementing a uinavigationcontroller. The first view is a uitableview (imagine the Contacts app) with a list of names.
The second view is the person profile.
So, when I click a person in the uitable, it's suppose to load his profile.
How do I pass the person data to the second view?
In didSelectRowAtIndexPath I do:
ContactView * varContactView = [[ContactView alloc] initWithNibName:nil bundle:nil];
varContactView.title = [[contactsArray objectAtIndex:indexPath.row] name];
[varContactView initWithPerson:[contactsArray objectAtIndex:indexPath.row]];
[navigationController pushViewController:varContactView animated:YES];
In the interface of ContactView I've got:
Person * person;
And then:
#property (nonatomic, retain) Person * person;
-(void) initWithPerson:(Person *)newperson;
And in .m:
#synthesize person
-(void) initWithPerson:(Person *)newperson{
person = [[Person alloc] init];
person = newperson;
}
However, when I try to access person in ContactView, it says always EXC_BAD_ACCESS.
What is wrong here?
Instead of:
[varContactView initWithPerson:[contactsArray objectAtIndex:indexPath.row]];
you can simply use:
varContactView.person = [contactsArray objectAtIndex:indexPath.row];
That will make use of person property setter and assign the given object as varContactView's data. The default implementation of that setter is (in case of retain property):
- (void)setPerson:(Person *)newPerson
{
if (person != newPerson) {
[person release];
person = [newPerson retain];
}
}
That's what you're trying to achieve in -initWithPerson: method. That method is not needed, as its functionality is covered by person property setter. BTW, remember to release person property in -dealloc method of your view controller:
- (void)dealloc
{
[person release];
[super dealloc];
}
The bad access exception might be caused by something else in your code, though...
In .m file, change the code as given below.
-(void) initWithPerson:(Person *)newperson
{
self.person = newperson;
}

Resources