I created a new UIViewController class including a xib file in xcode 6.
I set up everything like so
.h file next ViewController
#interface NextViewController : UIViewController
#property (nonatomic,assign) int gameID;
#end
.m file next ViewController
#synthesize gameID;
.m file previous View Controller
NextViewController *nextViewController = [[NextViewController alloc] initWithNibName:#"NextViewController" bundle:nil];
nextViewController.gameID = -1;
[self.navigationController pushViewController:nextViewController animated:YES];
when I ran it through the debugger the gameID is set in the .h file but when I want to access the value in the viewDidLoad method I get 0 for gameID instead of -1
Your code seems perfectly fine & it should work as expect a.k.a should rint "-1" in -(void) viewDidLoad.
Another approach I can think of is to try with overriding -init method like following:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil withGameId:(int)gameIdParam {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.gameID = gameIdParam;
}
return self;
}
Declare this method in .h file & then use this method to create new instance of your NextViewControllerwith passing gameID as a parameter.
Please note that, your code is itself correct. I tried it on Mac & it's working fine.
I think the viewDidLoad is getting hit before you set the GameID. Try setting a breakpoint on viewDidLoad and on nextViewController.gameID = -1; to see which one gets hit first. You can override the setter for gameID to perform logic based off of it if that is the case.
Related
So I'm trying to get a hang of using delegates, and I've watched a few tutorials on how to use them so far. I still find them confusing and after trying to implement one myself, have an issue that I can't seem to solve.
I have two ViewControllers, the first one ViewController contains a UITextField *sampleTextField and a button with the method switchViews. It also contains the protocol declaration with the method sendTextToViewController. SwitchViews is also linked to a segue that switches to the SecondViewController. In SecondViewController the only object is a UILabel *outputLabel When the user taps the button, it calls switchViews and the view changes to SecondViewController, and upon loading outputLabel should be changed to whatever text was entered in sampleTextField in ViewController. However the delegate method sendTextToViewController is never being called. All objects are created in Interface Builder.
Here is the code to make it a bit easier to understand:
ViewController.h
#import <UIKit/UIKit.h>
#protocol TextDelegate <NSObject>
-(void)sendTextToViewController:(NSString *)stringText;
#end
#interface ViewController : UIViewController
- (IBAction)switchViews:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *sampleTextField;
#property (weak, nonatomic) id<TextDelegate>delegate;
#end
Then declared this in ViewController.m
- (IBAction)switchViews:(id)sender {
NSLog(#"%#", self.sampleTextField.text);
[self.delegate sendTextToViewController:self.sampleTextField.text];
}
SecondViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface SecondViewController : UIViewController <TextDelegate>
#property (weak, nonatomic) IBOutlet UILabel *outputLabel;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize outputLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)sendTextToViewController:(NSString *)stringText
{
NSLog(#"Sent text to vc");
[outputLabel setText:stringText];
}
I've looked at this and the first answer makes sense, but for some reason it's not working.
I do think that the problem is where I am setting calling [vc setDelegate:self], but not sure how to fix this. Some pointers in the right direction would be greatly appreciated. Keep in mind I'm new to obj-c so if you can explain what you are saying, that would be great. Thank you.
Your are creating a new instance of ViewController but you don't do anything with it.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
The SecondViewController needs to have reference to the FirstViewController to be able to set itself as a delegate.
First you don't have to use delegation to do such a program.
A simpler way would be just creating a property in the SecondViewController that you'll pass the content of the textField into it.
Your code doesn't work because you called sendTextToViewController on a delegate that hasn't been set. You have set the delegate to a new instance of ViewController, not the one presented onscreen.
I tried some stuff in xcode, and i'm using this code for my MapView.
No known class method for selector 'setRegion:animated:'
I have made three View Controller with with 3 .h and .m files.
What's my mistake?
.m
#import "myPlacesAllTime.h"
#import <MapKit/MapKit.h>
#interface myPlacesAllTime ()
#end
#implementation myPlacesAllTime
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
MKCoordinateRegion startRegion = { {0.0,0.0}, {0.0,0.0} };
startRegion.center.latitude = 35.88905;
startRegion.center .longitude = -17.605591;
startRegion.span.latitudeDelta = 0.1;
startRegion.span.longitudeDelta = 0.1;
[myPlacesAllTime setRegion:startRegion animated: NO];
}
.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface myPlacesAllTime : UIViewController <MKMapViewDelegate>{
__weak IBOutlet MKMapView *myPlacesAllTime;
}
#end
You have chosen the same name myPlacesAllTime for the class and for an
instance variable of that class.
To solve the problem, rename the class, e.g. to MyPlacesController or similar.
Note that the convention is to let
class names start with a capital letter.
I think you problem may be a naming issue. The class you've created is named the same as the instance of MKMapView you have. I would follow convention and name your class with caps, but to solve the current problem try using
[self.myPlacesAllTime setRegion:startRegion animated:NO];
to see if it has a different outcome. You'll have to make your instance a property of the class, as stated in the comments below, which I missed in my original answer.
If you are intending to use setRegion:animated: at class level then make sure you have defined a method like this:
+ (void)setRegion:(OBJ_Type)iType animated:(OBJ_Type)iAnimated {
And f you are intending to use setRegion:animated: at object level then make sure you have defined a method like this:
- (void)setRegion:(OBJ_Type)iType animated:(OBJ_Type)iAnimated {
and in this case you need to call this method like this:
[self setRegion:PARAM animated:PARAM];
Am trying to write a simple custom delegate for displaying multiple selection list (after referring various online tutorials, stackoverflow, Apple doc), but in the class that I want to use the delegate, the line where I set the delegate runs into an infinite loop when I run it.
I have shared the source code here
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList?at=master
UIListViewController (where am declaring the protocols)
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList/UIListViewController.h?at=master
And am trying to use the delegate in a UIViewController called View_Exporter
#import <UIKit/UIKit.h>
#import "UIListViewController.h"
#interface View_Exporter : UIViewController <UIListViewDelegate, UIListViewDataSource>
#property (nonatomic, strong) IBOutlet UIView *viewForList;
#property (nonatomic, strong) UIListViewController *listViewController;
#end
View_Exporter.m
#import "View_Exporter.h"
#implementation View_Exporter
#synthesize arraySelectedList;
#synthesize viewForList;
#synthesize listViewController;
#pragma mark - UIListViewController Methods
-(NSArray *) itemsForList {
NSLog(#"View_Exporter itemsForList");
NSArray *array = [NSArray arrayWithObjects:#"Server", #"Memory", nil];
return array;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.listViewController = [[UIListViewController alloc] initWithNibName:#"UIListViewController" bundle:nil];
self.listViewController.listViewDelegate = self;
//[self.viewForList addSubview:self.listViewController.view];
self.listViewController.listViewDataSource = self;
}
#end
But this line in viewDidLoad seems to loop infinitely when I run the code :
self.listViewController.listViewDelegate = self;
Why is this looping infinitely? Am breaking my head since yesterday on this. not sure where am going wrong. can someone please help?
You've written a custom setter for listViewDelegate, at the end of this method you do this:
self.listViewDelegate = delegate;
This just calls the setter method again. Accessing a property via self. is just a way of calling[self setXX:xxx]. In your accessor method you need to set the instance variable directly, in the normal case this would be just
_delegate = delegate;
(The _delegate instance variable is created for you automatically). You can safely remove all of your synthesize statements, they aren't needed any more.
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! :)
I've run into some trouble with loading a sub-classed UIViewController from a nib. My viewDidLoad function is never called.
The super-class has no nib, but the sub-classes each have their own. i.e.
#interface SuperClass : UIViewController {
}
#end
#interface SubClass : SuperClass{
}
#end
#implementation SubClass
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad{
// Never called
}
The view is loaded from a nib as follows:
SubClass *scvc = [[SubClass alloc] initWithNibName:#"SubClass" bundle:nil];
[self.navigationController pushViewController:scvc animated:YES];
[scvc release];
There is a nib file with this name and it has it's file owner's class set properly.
viewDidLoad is not called in the child or super. Any ideas?
You say you are creating views in code (using loadView) in the super class, but trying to use a nib in the sub class?
According to the UIViewController docs (emphasis mine)
If you specify views using a nib file, you must not override loadView but should instead create a nib file in Interface Builder...
It looks like you may have a conflict there. As a test, comment out the loadView method in your superclass and see where that gets you.
I'm assuming SuperClass implements loadView. So when your SubClass is asked to loadView, you get your SuperClass' implementation, which overrides the normal nib loading mechanism.
I would rethink your design here. Your SuperClass' behavior is quite different from what you want your SubClass to do. Maybe that's not the best relationship there.
But, if you want, you should be able to at least make it work by doing this in your SubClass.m:
-(void)loadView {
IMP defaultImp = class_getMethodImplementation([[self superclass] superclass], _cmd);
/* or alternatively...
IMP defaultImp = class_getMethodImplementation([UIViewController class], _cmd);
*/
defaultImp(self, _cmd);
}
This implements a loadView for your subclass that skips over the loadView of your SuperClass and calls the default implementation instead.
IMO, this is ugly and might need to revisited if your class hierarchy expanded. I wouldn't do this in my own app, I would rethink the class hierarchy instead.
Where is this block located
SubClass *scvc = [[SubClass alloc] initWithNibName:#"SubClass" bundle:nil];
[self.navigationController pushViewController:scvc animated:YES];
[scvc release];
Are you sure it is called ?
I made a testproject to test it and the following works:
In your appDelegate.m file i put the following in the application didFinishLaunchingWithOptions method
UINavigationController *navController = [[UINavigationController alloc] init];
self.window.rootViewController = navController;
SubClass *viewController1 = [[[SubClass alloc] initWithNibName:#"SubClass" bundle:nil] autorelease];
[navController pushViewController:viewController1 animated:YES];
SuperClass.h
#import <UIKit/UIKit.h>
#interface SuperClass : UIViewController
#end
SuperClass.m
#import <UIKit/UIKit.h>
#import "SuperClass.h"
#implementation SuperClass
#end
SubClass.h
#import <UIKit/UIKit.h>
#import "SuperClass.h"
#interface SubClass : SuperClass
#end
SubClass.m
#import <UIKit/UIKit.h>
#import "SubClass.h"
#implementation SubClass
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
NSLog(#"Methods %# called", NSStringFromSelector(_cmd));
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
#end
This works for me, make sure you set the right class for your nibFile aswell. Click on the file's owner icon and change the class from UIViewController to SubClass
Try to add:
[super viewDidLoad];