I have a tableViewController that I will present once in a while.
I have created it as a property, on .h
myTVC *myTable;
and
#property (nonatomic, retain) myTVC *myTable;
then, on .m I have synthesized it and created a getter
#synthesize myTable = _myTable;
and
- (myTVC *) myTable {
if (_myTable == nil) {
_myTable = [[myTVC alloc] init];
}
return _myTable;
}
when it is time to use I simply do
[self presentModalViewController:myTable animated:YES];
[myTable release];
as far as I thought, myTable's getter would run at this point and allocate the tableViewController, but it is not running and the app crashes telling me that I am trying to present a nil tableViewController...
What am I missing? Thanks.
you need to do self.myTable if you do myTable you are asseccing your iVar that is call myTable into which your #property is not store, because you are doing this : #synthesize myTable = _myTable; which will create an iVar call _myTable.
So you are doing 2 wrongs things in here.
To correct your code do the following :
remove this line : myTVC *myTable;
and do [self presentModalViewController:self.myTable animated:YES];
A 3rd thing is also strange in your code
[self presentModalViewController:myTable animated:YES];
[myTable release]; // <---- this line, remove it to
I'm not sure why that line is there since you are storing your controller in a #property.
and a 4th By the way
The default initializer for a UIViewController is the following
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
You can pass nil if you don't have a .xib to go with it.
In
[self presentModalViewController:myTable animated:YES];
[myTable release];
You're not actually calling the myTable method.
Do
self.myTable = [self myTable]
first. Though I don't see why you need a myTable method instead of just doing an alloc init.
Related
Look at the following code.
In CusFormViewController.h
#interface CusFormViewController : CusBaseViewController
#protocol CusFormViewControllerDelegate <NSObject>
-(void)ticketCreated:(NSString*)ticketID;
-(void)ticketFormRenderingFinished;
#end
#property (nonatomic, weak) id<CusFormViewControllerDelegate> delegate;
In CusFormViewController.m
if ([self.delegate respondsToSelector:#selector(ticketFormRenderingFinished)])
[self.delegate ticketFormRenderingFinished];
if ([self.delegate respondsToSelector:#selector(ticketCreated:)])
[self.delegate ticketCreated:ticket_id];
In ViewController.m
#import "CusFormViewController.h"
#interface ViewController ()<CusFormViewControllerDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
CusFormViewController *formVC = [[CusFormViewController alloc] init];
[formVC setDelegate:self];
}
-(void)ticketCreated:(NSString*)ticketID{
NSLog(#"ticket created.");
}
-(void)ticketFormRenderingFinished{
NSLog(#"ticket form rendered.");
}
The ticketCreated & ticketFormRenderingFinished are not being called.
Most common reason for delegate method not being called is dealing with incorrect objects.
Ensure that CusFormViewController object created from
ViewController is the same which you are presenting on screen and
that the delegate is being set on the same object. I truly believe
you are creating a new CusFormViewController object and setting
delegate on that.
In CusFormViewController, before calling delegate, check the
existence of delegate as well. This is a safety check, you can also put a
NSLog statement to double check if your delegate exists or not. You
are failing here.
If you are segueing from ViewController to CusFormViewController then you set delegate in prepareForSegue: and not in viewDidLoad.
As a side note, put a NSLog statement in viewDidLoad of your CusFormViewController and print self.delegate to check the property setting.
Your controller formVC is dealloced after the function viewDidLoad executed. Create strong reference on your formVC for example like this:
#interface ViewController ()<CusFormViewControllerDelegate>
{
CusFormViewController *_formVC;
}
- (void)viewDidLoad {
[super viewDidLoad];
_formVC = [[CusFormViewController alloc] init];
[formVC setDelegate:self];
}
Hey try to create instance of CusFormViewController using below method
CusFormViewController * _formVC=[[UIStoryboard storyboardWithName:storyboardName bundle: nil]instantiateViewControllerWithIdentifier:#"IDENTIFIER_OF_YOUR_ CusFormViewController"];
I have FirstViewController and SecondTableViewController. In SecondTableViewController.m, I create a cell in the cellForRow... method where the cell.textLabel.text is a string from an NSInteger property ("count") of the SecondTableViewController.
I would like a button in FirstViewController to increment the value of count.
I've tried making a property of FirstViewController and then using that:
#property SecondTableViewController *viewController;
and
- (IBAction)buttonTouched:(id)sender {
self.viewController.count++;
[self.viewController.tableView reloadData];
}
But this way isn't working. count is still its original value of zero. I've also reloaded the table in viewWillAppear and still nothing. How can I do this?
Count being used as a property may be where you are going wrong because count is a method that returns the number of objects in an array that is found in foundation framework. Also keep in mind that if you are storing a integer into a string object try storing it in this format.
cell.textlabel.text = [NSString stringWithFormat: #"%i", count];
Hope this helps
Try following
firstViewController.h
#interface DMFirstViewController : UIViewController
#property (nonatomic, strong) DMSecondViewController * secondController;
- (IBAction)buttonPressed:(id)sender;
#end
firstViewController.m
- (IBAction)buttonPressed:(id)sender
{
++self.secondController.count;
[self.navigationController pushViewController:self.secondController animated:YES];
}
secondViewController.h
#property (nonatomic) int count;
secondViewController.m
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"%d", self.count);
}
EDIT
Check out those two images and implement the similar logic and get the solution.
----- END OF NEW EDIT -----
OLD
I think you haven't assigned and allocated memory for SecondTableViewController reference i.e, self.viewController of FirstViewController in its viewDidLoad method i.e,
-(void) viewDidLoad //In FirstViewController
{
self.viewController = [[SecondTableViewController alloc] init];
}
and pushed the same reference on to the stack of navigationController after performing button taps to increase the count of count variable of SecondTableViewController.
If you are not clear, comment.
I am trying to access an array defined as property on the parent view from child view and I get an empty array. here is what I did. could someone shed some light please!
FirstTableViewController.h
#interface FirstTableViewController : UITableViewController
#property (nonatomic,retain) NSMutableArray *SomeItems;
#end
in my FirstTableViewController.m. I have code that initialized the SomeItems with values. This has been verified
On the FirstTableViewController view there is a button that displays a second SecondTableView
in SecondTableViewController.m I have
#import "FirstTableViewController.h"
#import "SecondTableViewController.h"
- (void)viewDidLoad
{
[super viewDidLoad];
FirstTableViewController * objParent;
NSLog(#"count = %i",[objParent.SomeItems count]); //this return 0
}
thanks in advance!
EDITED
ToDoListTableViewController.h
#interface ToDoListTableViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *toDoItems;
- (IBAction)unwindToList:(UIStoryboardSegue *)segue : (id) sender;
#end
ToDoListTableViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//Attempt to pass toDoItems to new view controller.
//CompleteTableViewController.toDoItems = [self.toDoItems copy]; //this line caused compiler error saying toDoItems not found on object of CompleteTableViewController
CompleteTableViewController * objChild = (CompleteTableViewController*)[segue destinationViewController];
if(objChild != nil)
objChild.toDoItems = [self.toDoItems copy];
//sorry for weird code, as I don't really understand how this method really works.
//but I have a feeling I am just some inches away from getting it to work the way i want
}
CompleteTableViewController.h
#interface CompleteTableViewController : UITableViewController
#property (nonatomic,copy) NSMutableArray *toDoItems;
#end
CompleteTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"#%i record(s) in Complete Table View", [toDoItems count]);
}
Thanks again!
It is clear that you miss the basilar concept of the OOP.
You declared this:
FirstTableViewController * objParent;
but first of all it is not initializated and second it doesn't point to your instanced viewController.
Other things but that at this point become secondary are:
if you are using ARC, declare the property strong instead of retain;
method and variable should respect the Camel methodology so is not SomeItems but is someItems;
So if you are opening a viewController from another and you want access to that array, the best thing that you could do is pass that array and so have a property like this also in the second viewController:
#property (nonatomic,copy) NSArray *someItems;
and when you press the button in the first viewController, before push the second viewController:
secondViewController.someItems = [self.someItems copy];
Note that in the second view controller the array is not mutable, because probably you want just access to the informations. But this depend from you.
Is a little bit hard explain you more because i see that you are really a newbie. But, i hope to help you.
You need to pass a reference for the parent object through to the child on creation, or simply pass a reference to the array itself.
From Matteo suggestion, this seems to solve my issue
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController *navigationController = segue.destinationViewController;
CompleteTableViewController *objChild = (CompleteTableViewController *)navigationController.topViewController;
if(objChild != nil){
objChild.toDoItems = [self.toDoItems copy];
}
}
thanks Matteo.
In the SecondTableViewController, you've declared the FirstTableViewController in viewDidLoad, but that does not mean it's pointing to your previously created FirstTableViewController (you've made no assignment). Before viewDidLoad is called, you need to pass the FirstTableViewController to the SecondTableViewController, assign it to a variable that's not local in scope, and then you can access the FirstTableViewController and/or its SomeItems inside viewDidLoad.
Without knowing more of your design or what you're trying to accomplish, it'd be best to pass SomeItems to SecondTableViewController as part of initializing it if that's all you need from FirstTableViewController. If the state of what you're accessing is going to change as you are going from controller to controller, I'd highly recommend you spend more time reading up on Model-View-Controller (MVC), delegation and possibly Key-Value Observation (KVO). You're missing some fundamental knowledge.
Edit: also agree on naming, SomeItems should be someItems.
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 am trying to make a custom protocol that i hope somebody might help with.
I have a mainViewController (mainVC) that has a label. That label needs to be updated with a string when i press a button in edwwVC.
I am using ARC and storyboard.
The problem is when i press the Done Button on the edwwVC, the "done" method is called BUT the delegate method is not called in mainVC.
Whereas, if i call the done method VIA the mainVC, then the done method is called AND the delegate method. So I can see the connection is there, I just do not understand why the delegate method is not called when i press the done button in the edwwVC.
I imagine it has something to do with the init of the edwwVC. Because it is already initiated by storyboard, so it looks to me as if I am initializing it again the in the viewDidLoad method of the mainVC. But that is how far i got :)
Thanks in advance!
edwwVC.h
#import <UIKit/UIKit.h>
#import "IIViewDeckController.h"
#class EDWWViewController;
#protocol EDWWViewControllerDelegate <NSObject>;
#optional
- (void)edwwVCDidFinish:(EDWWViewController *)edwwVC;
#end
#interface EDWWViewController : UIViewController <IIViewDeckControllerDelegate> {
__weak id<EDWWViewControllerDelegate> delegate;
NSMutableArray *edwwPoints;
}
#property (weak) id<EDWWViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITableView *theTableView;
#property (strong, nonatomic) NSString *testString;
- (IBAction)done:(id)sender;
- (IBAction)add:(id)sender;
#end
edwwVC.m:
#pragma mark - delegate method
- (IBAction)done:(id)sender {
testString = #"This is the test string!";
[delegate edwwVCDidFinish:self];
[self.viewDeckController closeRightViewAnimated:YES];
NSLog(#"Done pressed");
}
MainVC.m:
- (void)viewDidLoad
{
[super viewDidLoad];
edwwViewController = [[EDWWViewController alloc] init];
edwwViewController.delegate = self;
}
- (void)edwwVCDidFinish:(EDWWViewController *)edwwVC {
edwwLabel.text= edwwVC.testString;
NSLog(#"delegate method called");
}
Remove the line ...
__weak id<EDWWViewControllerDelegate> delegate;
From the .h and change the line...
[delegate edwwVCDidFinish:self];
to...
[self.delegate edwwVCDidFinish:self];
In the .m.
That should sort it.
The way you have it set up the ivar delegate is not the same as the property delegate (which is actually an ivar called _delegate) (thanks #Joris Kluivers, just adding for clarity). They are pointing to different things.
If you add a breakpoint where you are calling the delegate method I think you'll find that delegate is nil. Whereas _delegate (or self.delegate) is not nil.
::EDIT::
Ahh... just spotted the second bit too.
If you are setting up the edwwvc in storyboard then you should be alloc initing it too.
If you are segue-ing to the edwwvc then you should intercept the segue in mainVC.m like this...
- (void)prepareForSegue: //blah the rest of the name...
{
if ([segue.identifier isEqualToString:#"the name of your segue"])
{
EDWWViewController *controller = segue.destinationViewController;
controller.delegate = self;
}
}
This will take the controller that you are pushing to from the storyboard and set the delegate to it.
:: ANOTHER EDIT ::
If EDWWVC is inside a containerViewController then you can do this inside viewDidLoad in MainVC.m...
- (void)viewDidLoad
{
// other stuff...
for (UIViewController *controller in self.childViewControllers) {
if ([controller isKindOfClass:[EDWWViewController class]]) {
EDWWViewController *edwwvc = (EDWWViewController*)controller;
eddwvc.delegate = self;
}
}
}
You may find this code has to go in viewDidAppear or something but I think viewDidLoad shouldd work just fine.
You may actually be able to set the delegate property directly by using the storyboard to (but I'm not 100% certain on this).
The answer was in the containerVC of both controllers.
Where i initialized the view controllers: the viewDidLoad of the containerVC m file:
- (void)viewDidLoad
{
[super viewDidLoad];
mainVC = (MainViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"MainVC"];
edwwVC = (EDWWViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"EDWWVC"];
//THIS LINE WAS MISSING
edwwVC.delegate = mainVC;
self.centerController = mainVC;
self.rightController = edwwVC;
}
BUT guys thanks for the help! :) Appreciate it got me in the right direction! :) THANKS! :)