This is what I got so far.
mainview.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender(id)sender {
secondView *secView = [segue destinationViewController]
secView.ext = #".com";
}
secondView.h
#interface secondView : UIViewController {
NSString *ext;
}
#proper (nonatomic, retain) NSString *ext;
#end
secondView.m
-(void)viewDidLoad {
NSString *url = [#"www.google" stringByAppendingFormat:ext]
}
And its returning a error saying ext is null... what am I doing wrong?
Did you try to turn ext into a property instead? My understanding is that the "dot" notation essentially turns your code into
[secView setExt:#".com"]
So turn SecondView.h into
#interface secondView : UIViewController
#property (nonatomic, copy) NSString *ext;
#end
And don't forget to #synthesize it in your .m file
Check the followings:
Make sure #synthesize ext; is in SecondView.m
In Storyboard, have you linked the segue correctly?
In Stodyboard, is the viewController that represetns SecondView defined as a class of SecondView?
Make sure that you are calling the SecondView via prepareForSegue:sender method (i.e. SecondView doesn't get called by pushViewController:animated somewhere else in your code).
Put a breakpoint at the line:
secView.ext = #".com";
and make sure that the ext ivar is properly set after the assignment. If it's not, you might be specifying that the accessors use a different ivar in your #synthesize directive for ext, or you might have provided a setter -setExt: that doesn't properly set the ivar.
If ext is set properly after the assignment, perhaps you've got two different instances of secondView. That used to happen a lot when people used .xib files -- they'd create one view controller in code and have another instance of the same class in their .xib file. I wouldn't expect that to be the case here since you're getting secView straight from the segue, but it's worth thinking about.
There are two views: view1 and view2.
Add view2.h file in view1.h
init object of view2 and set their variable.
Related
I am making an iOS app that uses payment methods.
At the moment I am trying to work on the checkout flow, which contains an OderFormViewController and a CheckoutTableViewController as you can see below:
I connected both by dragging a segue, as highlighted in blue. I also added a segue identifier for my segue.
I called the first view controller as E_OrderFormViewController(Its title is Shipping Address), and in it I created an IBActionfor my Continue button and also used -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender to pass in the information.
I also have an Order model, with some properties in it. On my CheckoutTableViewController, I have got my labels and orderInfo as public properties, so the first view controller one can access it.
#import <Foundation/Foundation.h>
#interface Order : NSObject
#property(strong, nonatomic) NSString *shippingName;
#property (strong, nonatomic) NSString *shippingAddress;
#property (strong, nonatomic) NSString *shippingCity;
#property(strong, nonatomic) NSString *shippingState;
#property(strong, nonatomic) NSString *shippingZip;
#end
//E_OrderFormViewController.m
#import "E_OrderFormViewController.h"
#import "F_CheckoutTableViewController.h"
...
#pragma mark - My Actions
- (IBAction)storePaymentInfoProceedToConfirmation:(id)sender {
[self performSegueWithIdentifier:#"toCheckout" sender:self];
}
#pragma mark - Navigation
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"toCheckout"]) {
F_CheckoutTableViewController *checkoutView = segue.destinationViewController;
//Store Information and pass it to next view
checkoutView.orderInfo.shippingName = self.txtFieldNameOnCard.text;
NSLog(#"Shipping Name Stored: %#",checkoutView.orderInfo.shippingName);
}
}
My NSLog always returns (null) for whatever text I type inside my first textField, which is the one I am testing first.
Here is my CheckoutTableViewController, with its public property. The orderInfois listed here. I am using it to pass in the information, as I mentioned above:
//F_CheckoutTableViewController.h
#import <UIKit/UIKit.h>
#interface F_CheckoutTableViewController : UITableViewController
#property (strong, nonatomic)Order *orderInfo;
#end
On my viewDidLoad, on my destination view controller, I did:
//F_CheckoutTableViewController.m
#implementation F_CheckoutTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Load all information
self.labelShippingName.text = self.orderInfo.shippingName;
NSLog(#"Typed Name: %#",self.orderInfo.shippingName);
}
I just pasted the viewDidLoad as a reference, as I am aware if my NSLog in my prepareForSegue is not returning anything, the information is not being passed.
I really don't know where the error is. I searched in a couple of threads here on StackOverFlow, and none of them helped me, one which seems to be similar, is this one, but it didn't help with my issue:
Multiple segues not passing Object data between themselves
This seems to be pretty simple, but I am making some mistake that I can not find.
I really appreciate your help.
orderInfo must be null, because you didn't initialize it, therfore you cannot set its properties... so you got 2 options:
checkoutView.orderInfo = [[OrderInfo alloc]init];
checkoutView.orderInfo.shippingName = self.txtFieldNameOnCard.text;
or change your property from:
#property (strong, nonatomic)Order *orderInfo;
to:
#property (strong, nonatomic)NSString *shippingName ;
Based on the storyboard set up, you are using Textfield in Shipping Address View Controller, it may miss the delegation of Textfield to its controller.
i have defined variable in GroupView.h
#interface GroupView()
{
NSMutableArray *chatrooms;
}
#end
#implementation GroupView
Now i want to pass this variable in segue
#interface FriendsViewController ()
#end
#implementation FriendsViewController
else if ([segue.identifier isEqualToString:#"showGroupView"]) {
GroupView *groupView = (GroupView *)segue.destinationViewController;
groupView.chatrooms = [NSMutableArray arrayWithArray:chatrooms];
}
i know that chatrooms has to be property in header file to code this way but it is not
So is there any way to use this variable in segue.
Thanks for help.
chatrooms defined as an ivar like you have done is accessed using -> notation:
groupView->chatrooms = [NSMutableArray arrayWithArray:chatrooms]
This is generally discouraged, though. You should use a property instead:
#interface GroupView
#property (strong) NSMutableArray *chatrooms;
#end
Incidentally, if you're using an NSMutableArray, that indicates that you want to modify the element list of the array directly and not just replace the array wholesale. If you only ever want to replace the array with a whole new array every time, I suggest using NSArray instead.
Another point to make here is that you're attempting to cast the object held at segue.destinationViewController as a GroupView. You have either named a UIViewController subclass in a very misleading way, or you are not accessing the GroupView as a correct member of the UIViewController that is returned to you.
Normally, if you are not building the SDK or something. You don't really have a better reason not to expose it in the header file. However, you can expose the property in the extension and declare a private property in the host class(It's really not able to pass if you just declare a local variable). For example, You have a extension called GroupView+Helper. So, you can pass it into the property exposed in the extension. And then internally translate into the GroupView.
In GroupView.m:
#interface GroupView
#property (strong, nonatomic) NSMutableArray *chatrooms;
#end
In GroupView+Helper.h
#property (strong, nonatomic) NSMutableArray *internalChatrooms;
Also, you need to import the GroupView+Helper in the GroupView.
It will make your chatrooms private and internalChatrooms protected.
I am trying to do the following, and not able to find a straightforward answer.. It is related to this :Passing uitextfield from one view to another. But not exactly.
I have a Firstview.m, from which I push to a Secondview.m. The Secondview.m has a UITextView. I allow the user to edit the UITextView on Secondview.m. Now I want to store this text value in a variable in Firstview.m. One way to to do this is as follows
in Firstview.h
#property (nonatomic) Secondview *secondView;
That is keep a secondView variable in Firstview itself. But this doesn't seem efficient. Ideally I should only have 1 NSString text field in FirstView. What is the right way to do this ? Thanks
You can achieve this by using Delegation in Objective-C.
In your SecondView.h add following right after Header Inclusion
#protocol YourDelegateName <NSObject>
-(void)setText:(NSString *)strData;
#end
Also add delegate property to your header for accessing them in calling class, like below (This goes with other properties declaration in SecondView.h file):
#property (nonatomic, weak) id<YourDelegateName> delegate;
Now, Comes the calling the delegate part. Say, you want to save the text value of UITextView of SeconView in strTextViewData of FirstView class, when the following event occurs:
- (IBAction)save:(id)sender
{
[self.delegate setText:self.txtView.text]; // Assuming txtView is name for UITextView object
}
Now, In FirstView.h add YourDelegateName in delegate list like below:
#interface FisrtView : ViewController <YourDelegateName>
#property (nonatomic, reatin) NSString *strTextViewData;
#end
And then in FisrtView.m file when you create instance of SecondView class, set delegate to self like below:
SecondView *obj = [[SecondView alloc] initWithNibName:#"SeconView" bundle:nil];
obj.delegate = self; // THIS IS THE IMPORTANT PART. DON'T MISS THIS.
Now, Implement the delegate method:
-(void)setText:(NSString *)strData
{
self.strTextViewData = strData;
}
Applying this to your code will do what you want. Also, Delegation is one of the most important feature of Objective-C language, which - by doing this - you will get to learn.
Let me know, if you face any issue with this implementation.
I'm trying to set the delegate for my custom protocol that has one required method allowing me to pass an array of objects back in the hierarchy of two UITableViewControllers. My delegate continues to return nil. Due to this, my required method is never called.
I'm wondering if the datasource and delegate implementations with my UITableViewControllers is causing a conflict. Also, perhaps ARC is getting in the way when declaring the delegate?
It should be noted that both UITableViewControllers were built using Storyboard and are navigated using segues within a UINavigationController (not sure if this may be causing issues or not).
The nav is --> AlarmViewController --> AlarmDetailsViewController. I create an Alarm object in my AlarmDetailsViewController that contains all the details for an alarm, place it into an array and I want to pass that array back to my AlarmViewController to be displayed in a custom cell in the table.
NOTE: I want to use the Delegate pattern here. I'm not interested in solutions that invoke NSNotifications or use my AppDelegate class.
AlarmDetailsViewController.h
#import "Alarm.h"
#protocol PassAlarmArray <NSObject>
#required
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray;
#end
#interface AlarmDetailsViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
//.....
id <PassAlarmArray> passAlarmsArrayDelegate;
}
#property (nonatomic, retain) id <PassAlarmArray> passAlarmsArrayDelegate;
#end
AlarmDetailsViewController.m
#import "AlarmDetailsViewController.h"
#interface AlarmDetailsViewController ()
#end
#implementation AlarmDetailsViewController
#synthesize passAlarmsArrayDelegate;
-(void) viewWillDisappear:(BOOL)animated
{
NSLog(#"delegate = %#", self.passAlarmsArrayDelegate); // This prints nil
[[self passAlarmsArrayDelegate] passAlarmsArray:alarmsArray];
}
//....
#end
AlarmViewController.h
#interface AlarmViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, PassAlarmArray>
{
//...
AlarmDetailsViewController *alarmDetailsViewController;
}
#property (nonatomic, retain) AlarmDetailsViewController *alarmDetailsViewController;
#end
AlarmViewController.m
#import "AlarmViewController.h"
#import "AlarmDetailsViewController.h"
#import "AlarmTableViewCell.h"
#import "Alarm.h"
#interface AlarmViewController ()
#end
#implementation AlarmViewController
#synthesize alarmDetailsViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
// This is where I'm attempting to set the delegate
alarmDetailsViewController = [[AlarmDetailsViewController alloc]init];
[alarmDetailsViewController setPassAlarmsArrayDelegate:self];
}
//....
//My #required protocol method which never gets called since my delegate is nil
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray
{
alarmsTableArray = theAlarmsArray;
NSLog(#"alarmsTableArray contains: %#", alarmsTableArray); // Never gets called due to delegate being nil
NSLog(#"theAlarmsArray contains: %#", theAlarmsArray); // Never gets called due to delegate being nil
}
#end
I've attempted to set the delegate in a method that fires when a button is pressed in AlarmViewController (as opposed to the viewDidLoad method) but that does not work either.
I'm assuming I've got a logic flow error somewhere here . . . but nearly 2 days of hunting and rebuilds haven't uncovered it. Ugh.
You're setting your delegate in the wrong place, and on a different instance of the controller than the one you will get when you do the segue. You should set the delegate in the prepareForSegue method if you're pushing AlarmDetailsViewController from AlarmViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AlarmDetailsViewController *alarm = segue.destinationViewController;
alarm.passAlarmsArrayDelegate = self;
}
You really need to understand the life cycle of view controllers, how and when they're instantiated, and when they go away. This is the very heart of iOS programming, and Apple has extensive documentation on it. Reading up on segues would also be very useful. A segue (other then an unwind segue) always instantiates a new instance of the destination controller. So, when your segue is performed, whether directly from a button, or in code, a new (different from the one you alloc init'd directly) details controller is instantiated. Before that segue is performed, prepareForSegue: is called, and that's when you have access to the one about to be created. That's the place to set a delegate or pass any information on to the destination view controller.
Did you try replace (nonatomic, retain) with (nonatomic, strong) since you are using ARC?
Auto-synthesized properties like your alarmDetailsViewController property have backing ivars prefixed with underscores, e.g. _alarmDetailsViewController. Your alarmDetailsViewController ivar (the alarmDetailsViewController declared inside the #interface ... {} block in AlarmViewController.h) is different from the backing ivar of your alarmDetailsViewController property.
Just delete your alarmDetailsViewController ivar and use the #property, preferably through self.alarmDetailsViewController.
The Problem
An IBOutlet is released before I have a chance to use it.
What I Want
I want to access a navigation controller from my app delegate so I can reload a table view.
My Setup
I have:
A Main.xib that's set as my main interface in target settings
An IBOutlet to the navigation controller as an ivar on my app delegate
This IBOutlet hooked up to the correct navigation controller in Main.xib
App Delegate is instantiated in the xib but not set as File's Owner
I'm using ARC, Xcode 4.3.2 and iOS5.1
What I've Tried
Changing deployment target
Putting a break point on dealloc for the navigation controller, app delegate - they're never called
Reading everything I can find on ARC and IBOutlets - nothing seems to contradict what I'm doing
Creating a fresh project with just a the minimum classes required - I see exactly the same problem
Code
KPAppDelegate.h
#interface KPAppDelegate : UIResponder <UIApplicationDelegate> {
IBOutlet KPBrowseExpensesNavigationController *nc;
}
#property (strong) IBOutlet KPBrowseExpensesNavigationController *nc;
KPAppDelegate.m
#implementation KPAppDelegate
#synthesize nc;
-(void)setNc:(KPBrowseExpensesNavigationController *)nc_ {
nc = nc_; // This gets called on view load and nc gets set.
}
...snip...
// This is called about 5 seconds after app startup
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
// By the time we get here, nc is nil.
UITableViewController *tvc = [[nc viewControllers] objectAtIndex:0];
[[tvc tableView] reloadData];
}
#end
UPDATE
I must be doing something really silly here. Even an incredibly simple project still shows this problem. See link below.
Download a simple test project that shows the problem.
In Window nib, set the FilesOwner Class as UIApplication and then point it's delegate from Outlets to the AppDelegate object. This is what is wrong in your project example.
is your outlet from the Interface Builder set as an KPBrowseExpensesNavigationController type?
If not it is not going to create the connection between your nib and ViewController.
You should set its Custom Class as KPBrowseExpensesNavigationController in the Identity Inspector
I am not sure why you declare it as a property & a non-property. I should do something like this:
#interface KPAppDelegate : UIResponder <UIApplicationDelegate>
#property (nonatomic, strong) IBOutlet KPBrowseExpensesNavigationController *nc;
And in your implementation:
#implementation KPAppDelegate
#synthesize nc = _nc; // So you don't accidentally use nc
...snip...
// This is called about 5 seconds after app startup
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
// By the time we get here, nc is nil.
UITableViewController *tvc = [[**self.nc** viewControllers] objectAtIndex:0];
[[tvc tableView] reloadData];
}
#end
Hope this helps!
I didn't see where you alloc your nav controller. Just declaring the property won't assign any value to it, so it would be nil. In you -didFinishLaunchingWithOptions in the app delegate, set your alloc/init statement. Everything else looks fine.
KPBrowseExpensesNavigationController *nc = [[KPBrowseExpensesNavigationController alloc] init];
If you have a custom init, you can use that too, but just make sure to set it up before you try and use it.