I am an iOS noob.
I am having a problem similar to this:
"self" object for UIViewcontroller has #"0 objects" in debug window in xcode
Re-starting xcode does not solve the problem.
I can see the self object in the view controller after a segue from my main view controller. I have a UITableViewController inside that view controller, with a separate class for delagete/data source for the table. Once i get into this tableviewcontroller code, the self object shows "0 objects" in the debugger. I believe that I am initializing the table view incorrectly to cause this problem somehow, but not quite sure how.
Thanks for the help. My code is below.
#implementation ConnectTableController
#synthesize perpArray;
#synthesize nameArray;
+ (ConnectTableController *)connectTableController
{
return [[ConnectTableController alloc] init];
}
- (void)viewDidLoad {
[super viewDidLoad];
perpArray = [[NSMutableArray alloc] init];
nameArray = [[NSMutableArray alloc] init];
}
....
#interface ConnectTableController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
UITableView *tableView;
NSMutableArray* perpArray;
NSMutableArray* nameArray;
}
+ (ConnectTableController*) connectTableController;
#property (nonatomic, strong) NSMutableArray *perpArray;
#property (nonatomic, strong) NSMutableArray *nameArray;
...
// Parent view controller code
#implementation ConnectVC
- (void)viewDidLoad {
[super viewDidLoad];
// Set the controller delegate/dataSource for the Table
connectTableController = [[ConnectTableController alloc] init];
connectTable.dataSource = connectTableController;
connectTable.delegate = connectTableController;
[self addChildViewController:connectTableController];
}
...
#interface ConnectVC : UIViewController{
IBOutlet UIButton *CONNECT;
ConnectTableController *connectTableController;
IBOutlet UITableView *connectTable;
}
The following applies to UITableViewControllers as well, make sure you are accessing the views properly
"Self" for a viewController doesn't contain the views, you have to check "self.view.subViews", "Self.view.subViews" contains the views for the viewController, not just "self" alone.
for example, if Self is a UIViewController then the following will crash your app with the corresponding error:
for(UIView * a in self)
{
NSLog(#"%#", a.description);
}
error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x7f854176fbf0'
It crashes because "self" of uiviewController doesn't contain the views
BUT if you try this, then you will have something to work with:
for (UIView *s in self.view.subviews) {
NSLog(#"%#", s);
}
this will log to console all the views in the UIViewController, thereby allowing you to access the views
Also, it looks like you may be trying to access the views of "connectTableController". To access this controller's views then here's how it works:
connectTableController.view.subViews.
UITableViewController * aaa = [UITableViewController new];
aaa.tableView;
aaa.view;
aaa.view.subviews;
So, this means you are going to access the following:
connectTableController.tableView
connectTableController.view.subViews
and then from there, you can do this:
connectTableController.tableView.subViews
.. that is of course if the subviews you are looking for are subviews of the UITableViewController's tableView
In addition, I think the way you are doing the placement of a UITableViewController is OKAY, but probably not the best choice, only because it gets a little complicated and it's not as easy as adding it as a child like that in order to make this work. You should be using something like this:
tester2 = [UITableViewController new];
[self addChildViewController:tester2];
[self.view addSubview:tester2.view];
[tester2 didMoveToParentViewController:self];
then of course you should combine this method when/if you want to remove the child view controller
- (void)hideContentController:(UIViewController*) content
{
[content willMoveToParentViewController:nil];
[content.view removeFromSuperview];
[content removeFromParentViewController];
}
This will hopefully give you a start, so also try this:
- (void)viewDidLoad {
[super viewDidLoad];
// Set the controller delegate/dataSource for the Table
connectTableController = [[ConnectTableController alloc] init];
connectTable.dataSource = connectTableController;
connectTable.delegate = connectTableController;
[self addChildViewController:connectTableController];
[self.view addSubview:connectTableController.view];
[connectTableController didMoveToParentViewController:self];
}
Also, I don't know that you need to do anything with delegation declaration since the child view controller is basically it's own little world within a world. Try it with and without these lines:
connectTable.dataSource = connectTableController;
connectTable.delegate = connectTableController;
What I mean, is possibly declare these in the UITableViewController instance or make sure you are adding the "connectTable to the the UITableViewController, something like this:
cconnectTableController.tableView = connectTable;
or
[cconnectTableController setTableView:connectTable];
then you can try this
connectTable.dataSource = cconnectTableController;
etc, etc.
Try this for loop and list the results
for (id s in self.view.subviews) {
NSLog(#"%#", s);
}
Related
I am trying to use a NSMutableArray that I have created in ViewController in an ViewController2. But it is just returning nil.
Here is my ViewController.h file:
#property (nonatomic, strong) NSMutableArray *total_hours;
Here is my ViewController.m file:
total_hours = [[NSMutableArray alloc] init];
I also add object. Use NSLog to display that this have actually been added, so that is working. But now I try to use NSLog to display them again in the other ViewController2.
Here is my ViewController2.h file:
#property(nonatomic, assign)NSMutableArray*total_hours_copy;
here is my ViewController2.m file:
#import "TimelisteViewController.h"
// some auto enabled code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
TimelisteViewController *test = [[TimelisteViewController alloc]init];
NSMutableArray *total_hours_copy = test.total_hours;
NSLog(#"%#", [total_hours_copy objectAtIndex:0]);
}
Why is this not working?
Your question implies that you create the array in ViewController and want to later pass it to ViewController2. However, in ViewController2's viewDidLoad method, you create a new instance of ViewController. So that's a problem.
It would be easier to answer your question if :
You indicated in which method total_hours is initialized.
How control is transferred between the 2 controllers.
You are not initializing you array in the right place. viewDidLoad is only called when the view controller is shown, not at the initialization.
You could override init method in your view controller :
- (void)init{
[super init];
total_hours = [[NSMutableArray alloc] init];
}
However this is not a usual pattern, and i won't recommend it. I'm not sure what you're trying to do, but i believe it would be best to initialize you array in your viewcontroller2 and pass it after to your newly initialize controller.
TimelisteViewController *test = [[TimelisteViewController alloc]init];
NSMutableArray *total_hours = [[NSMutableArray alloc] init];
//Add your data in the array
test.total_hours = total_hours;
Based on the fact that Paul Lalonde has made good considerations, if you need to pass the array from a view controller to another you can follow two ways.
Create a singleton class that would share the array (in this way each controller can access to that singleton and hence to that array)
Inject the array from a controller to another (preferred way since it allows decoupling components and having less application rigidity)
So, following the second solution, from ViewController1 you inject the array like the following snippet. Now both controller will share the same array. Modifications made by one controller will be visible to the other and vice versa...
ViewController2 secondController = // alloc-init here…
secondController.sharedArray = [self sharedArray];
where ViewController2 would have a property like
#property (nonatomic, strong) NSMutableArray* sharedArray;
Then, for example, within its viewDidLoad or wherever you want you can say
[self.sharedController add…]
Said this, what it your application flow? For example, is ViewController2 a controller that is displayed after ViewController1 through a UINavigationController or something similar?
total_hours_copy is a local variable in your viewDidLoad method, not a property!. Change your code to
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
TimelisteViewController *test = [[TimelisteViewController alloc]init];
self.total_hours_copy = test.total_hours;
// or maybe self.total_hours_copy = [test.total_hours copy];
NSLog(#"%#", [total_hours_copy objectAtIndex:0]);
}
i'm not new to OOP but i'm very new to objective c and i've been having trouble with reaching model from two different view controllers, one to set it the other to get the data. Here's my model:
#import <Foundation/Foundation.h>
#interface ModelUnit : NSObject{
NSString * nickname;
int total;
}
- (void)setTotal:(int)newTotal;
- (void)setName:(NSString *)nick;
- (NSString *)getName;
#end
#import "ModelUnit.h"
#implementation ModelUnit
- (void)setTotal:(int)newTotal{
total = newTotal;
}
- (void)setName:(NSString *)nick{
nickname = nick;
}
- (NSString *)getName{
return nickname;
}
#end
Here's how i try to set nickname in the initial viewcontroller:
//.h
#interface introViewController : UIViewController{
ModelUnit * modl;
}
-(ModelUnit *) modl;
-(IBAction)nickEntered:(UITextField *)sender;
#end
//.m
-(ModelUnit *) modl{
if(!modl){
modl = [[ModelUnit alloc] init];
}
return modl;
}
- (IBAction)nickEntered:(UITextField *)sender{
[[self modl] setName:[sender text]];
ViewController *vew = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:vew animated:NO completion:Nil];
}
And here is how i try to receive and display it in the last viewcontroller:
- (void)viewDidLoad
{
[super viewDidLoad];
introViewController *pnt = [[introViewController alloc] initWithNibName:nil bundle:nil];
[display setText:[[pnt modl] getName]];
}
But it always prints it as null when i NSlog it to the console. I know it's a very novice question but i'm completely stuck. Thanks for any help.
It's because each of your UIViewController instances are referencing different instances of your model class (actually, a non-instance in the second case).
Make an #property in your "last" view controller (class name of "ViewController" it would seem), something like:
#property (strong, nonatomic) Model *model;
Then, when pushing your second view controller, set its model property, like this:
ViewController *vew = [[ViewController alloc] initWithNibName:nil bundle:nil];
vew.model = self.modl;
[self presentViewController:few animated:NO completion:NULL];
That way, you're passing around the same instance of your Model class. The way you're doing it, you're trying to access a property that was never initialized, which is why you're getting nil.
If you're not new to OOP, you should quite easily see the mistake you're making. You're trying to retrieve a value out of an object you just initialized.
Where you need to pass the data is in the first object as you initialized the second object.
Between this line:
ViewController *vew = [[ViewController alloc] initWithNibName:nil bundle:nil];
And this line:
[self presentViewController:vew animated:NO completion:Nil];
You're still in the first object and you hold a reference to the second object. Give the ViewController class (a better name and) a NSString property to hold the data the getName method returns. And then set that property between the two lines I posted.
Also, Objective-C doesn't name their getters with get.
I have an object that is sent from my main VC to my MasterTabViewController(UITabBarController) in the viewDidLoad I NSLog the object and it shows the object, good. Now I need that object to go to the first tab UIViewController. I tried multiple times and cannot get it to go. I am new so forgive my ignorance,
I send the object from my main vc to my MasterTabViewController via segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showLogin"])
{
MasterTabViewController *preview = segue.destinationViewController;
preview.communityTapped = self.tempCommunity;
}
}
^This works fine!^ self.tempCommunity is an instance community object.
MasterTabViewController.h
- (void)viewDidLoad
{
[super viewDidLoad];
FirstTabViewController *firstvc;
firstvc.communityTapped = self.communityTapped;
NSLog(#"%# !!!!!!!!! ",self.communityTapped.commDescription);
// Do any additional setup after loading the view.
}
FirstTabViewController.h
#property (nonatomic, strong) IBOutlet UILabel *descriptionLabel;
#property (nonatomic, strong) Community *communityTapped;
FirstTabViewController.m
- (void)viewDidLoad
{
self.descriptionLabel.text = self.communityTapped.commDescription;
[super viewDidLoad];
// Do any additional setup after loading the view.
}
If anyone could help that would be greatly appreciated as I have tried and failed many times.
You can't set up IBOutlets to a tab bar controllers view controllers (and I see from your project that you never hooked them up). In your viewDidLoad for the tab bar controller, you can get a reference to any of its view controllers with the viewControllers property. So do something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstvc = self.viewControllers[0];
self.firstvc.communityTapped = self.communityTapped;
NSLog(#"%# !!!!!!!!! ",self.communityTapped.commDescription);
}
I think the problem is in the viewDidLoad of your MasterTabViewController.h. You're creating the variable firstvc, but you're not setting the value to anything. So when you set the value of communityTapped in the next line, you're trying to set the value of communityTapped on nothing.
Option 1
If you've set up the tab in interface builder, you need to create an IBOutlet in your MasterTabViewController.h and connect it to your view controller. Something like the following:
#property (strong, nonatomic) IBOutlet FirstTabViewController *firstvc;
Then to set the value of the communityTapped, property, you would use something like this:
self.firstvc.communityTapped = self.communityTapped
Option 2
The other option would be to create the tab pragmatically, and add it to the view. I'm not sure quite what your setup is, but I imagine it would be something like this:
FirstTabViewController *firstvc = [[FirstTabViewController alloc] init];
firstvc.communityTapped = self.communityTapped;
NSArray *viewControllers = [[NSArray alloc] initWithObjects:firstvc, nil];
[self.navigationController.tabBarController setViewControllers:viewControllers animated:NO];
I am having a hard time communicating data between two view controllers that are inside a UISplitViewController. I am following this tutorial. I was able to create a split view controller with UITableViews on both master and detail views. Now, What I really want is that when I tap on a particular row in the master table, it has to send some value to the detail view.
I am just playing around with a custom delegate to pass some value from one view controller to another to see if there is any communication between them but nothing seems to work any way.
In MasterTableView.h
#protocol sendingProtocol <NSObject>
-(void)passSomeValue:(NSString *)someValue;
#end
#interface MasterTableView : UITableViewController
{
NSArray *menuArray;
id<sendingProtocol>delegate;
}
#property (nonatomic,assign) id<sendingProtocol>mydelegate;
#end
Synthesized in .m file.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self mydelegate] passSomeValue:#"Some Value"];
}
In DetailTableView.h
-(void)passSomeValue:(NSString *)someValue
{
NSLog(#"%#", someValue);
}
Please note that I am calling the mydelegate inside the ViewDidLoad method. Is this the write way? Can someone help?
- (void)viewDidLoad
{
[super viewDidLoad];
MasterTableView *masterView = [[MasterTableView alloc] init];
masterView.mydelegate = self;
}
Thank you in advance!
In viewDidLoad method of your DetailTableView you should not create a new MasterTableView object. The error is here in this method:
- (void)viewDidLoad
{
[super viewDidLoad];
MasterTableView *masterView = [[MasterTableView alloc] init];
masterView.mydelegate = self;
}
You are creating another object of MasterTableView and setting its delegate to self and hence all the problem.
To set the delegate of MasterTableView to DetailTableView, go to AppDelegate.h. You must have defined the MasterTableView and DetailTableView objetcs in AppDelegate.
//Set the DetailTableView as the master's delegate.
self.masterTableView.delegate = self.detailTabelView;
I'm trying to accomplish something incredibly simple. I am trying to programmatically push to a viewController when the only item in my collection view is pushed. Nothing happens. I believe there is more than one problem in my tangled mess. My understanding of the basics of arrays is clearly anything but. If I put an NSLog line inside my if statement below, I get nothing when pushing my lone item. Here is my didSelectItemAtIndexPath method:
NSMutableArray *itemApp = [model.viewControllers objectAtIndex:indexPath.row];
if (itemApp == 0) {
NSLog (#"This does not appear")
TableViewController *ctc = [[TableViewController alloc] initWithStyle:UITableViewStylePlain];
[self.navigationController pushViewController:ctc animated:YES];
}
model is defined in viewDidLoad:
model = [[SimpleModel alloc] init];
SimpleModel is mentioned in the .m implementation:
#implementation smileController;
{
SimpleModel *model;
}
viewControllers is property of the SimpleModel class, along with its friend, apps:
#property (nonatomic, strong) NSMutableArray *apps;
#property (nonatomic, strong) NSMutableArray *viewControllers;
Here is the SimpleModel.m
- (id)init
{
if (self = [super init])
{
self.apps = [NSMutableArray arrayWithObjects:#"1", nil];
self.viewControllers = [NSMutableArray arrayWithCapacity:self.apps.count];
TableViewController *tvc = [[TableViewController alloc] init];
[self.viewControllers addObject:tvc];
}
return self;
}
In SimpleModel.m you populate the viewControllers array with a single TableViewController.
Given this, when the first block of code you posted should be more like this:
TableViewController *itemApp = [model.viewControllers objectAtIndex:indexPath.row];
if (itemApp) {
NSLog (#"This should appear")
[self.navigationController pushViewController:itemApp animated:YES];
}
This assumes you want to push the view controller you obtain from the model.viewControllers property.
Please note that itemApp can only be nil if model or model.viewControllers are nil.