Best way to pass variables between views - iphone

I am very new to xcode & Objective-C (having come from PHP) i have started to play around and am finding it very hard to pass variables between views this is what i have so far:
Game_info.h
#import <UIKit/UIKit.h>
#interface Game_Info : UIViewController {
IBOutlet UITextField *groupName;
IBOutlet UISegmentedControl *gameType;
}
#property (nonatomic,retain) IBOutlet UITextField *groupName;
- (IBAction) GameTypePicker;
- (IBAction) KeyboardHide;
- (IBAction) BackBTN;
- (IBAction) NextBTN;
#end
Game_Info.m
#import "I_Dare_YouViewController.h"
#import "Game_Info.h"
#import "Game_TDoR.h"
#implementation Game_Info
#synthesize groupName;
// Next Button
-(IBAction) NextBTN{
if ([groupName.text length] == 0) {
// Alert
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Group Name"
message:#"Please enter a group name"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil
];
[alert show];
[alert release];
}else if([groupName.text length] < 3){
// Alert
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Group Name"
message:#"Please enter a name longer than 3 characters"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil
];
[alert show];
[alert release];
}else{
Game_TDoR *screen = [[Game_TDoR alloc] initWithNibName:nil bundle:nil];
screen.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:screen animated:YES];
[screen release];
Game_TDoR *screen1 = [[Game_TDoR alloc] initWithNibName:nil bundle:nil];
NSLog(#"Game_Info: %#",self.groupName.text);
screen1.groupNameText = self.groupName.text;
[self presentModalViewController:screen1 animated:YES];
[screen1 release];
}
}
Then in another view / .h / .m file i am trying to get to the 'groupName' property.
Game_TDoR.m
#import "I_Dare_YouViewController.h"
#import "Game_Info.h"
#import "Game_TDoR.h"
#implementation Game_TDoR
#synthesize groupNameText,Testlbl;
- (void)viewDidLoad
{
NSLog(#"Game_TDoR: %#",self.groupNameText);
NSString *msg = [[NSString alloc] initWithFormat:#"Hello, %#",[self.groupNameText capitalizedString]];
[Testlbl setText:msg];
[msg release];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
So what i am trying to do is on the first view page (Game_info) there is an input text box and im trying to pass that to a label on another view page (Game_TDoR)
This is what comes out in the NSLog (note that the second page (Game_TDoR) comes out first in the log.
2011-07-17 00:25:34.765 I Dare You[3941:207] Game_TDoR: (null)
2011-07-17 00:25:34.774 I Dare You[3941:207] Game_Info: Name
Problem solved:
On the next button i needed to add the variable before i moved page (not the other way around - silly noobish thing to do...)
Game_TDoR *screen1 = [[Game_TDoR alloc] initWithNibName:nil bundle:nil];
NSLog(#"Game_Info: %#",self.groupName.text);
screen1.groupNameText = self.groupName.text;
[self presentModalViewController:screen1 animated:YES];
[screen1 release];
Game_TDoR *screen = [[Game_TDoR alloc] initWithNibName:nil bundle:nil];
screen.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:screen animated:YES];
[screen release];

If you need to pass the value of groupName.text from the Game_Info view controller to the Game_TDoR view controller, which is presented modally by the former, you can declare a property in Game_TDoR to hold the value:
1) Declare a NSString property in Game_TDoR #interface block:
#property (nonatomic,copy) NSString *groupNameText;
(Remember to synthesize or implement the accessor methods in the implementation block)
2) In NextBTN action, after you initialize your Game_TDoR instance, set the property:
Game_TDoR *screen = [[Game_TDoR alloc] init...];
screen.groupNameText = self.groupName.text;

Merely including the header file will not make the variable available. You are only including the definition of the class (class is for PHP what #interface is for Obj-C) You have to instantiate Game_Info and access the variable via the instance of Game_Info.

groupName is a member (ivar) of Game_Info. Its default visibility is #protected, so any classes outside Game_Info can't access it, unless they derive from Game_Info. To make groupName accessible, you can either create a property that exposes it, or you can make it #public. How this is done is documented in the vast documentation for Xcode.
But groupName, being an ivar (instance variable) of an object, only exists if there is in fact an instance of the Game_Info. I assume you have some globally accessible instance of Game_Info in your program, let's call it globalGameInfo. Now you can access its groupName using
UITextField *gName = [globalGameInfo groupName];

Take this in .h file in SecondViewController
NSString *strABC;
Make below function in SecondViewController.m
-(void)setString:(NSString *)strEntered{
strABC=strEntered;
}
Now In First view controller do like this:
SecondViewController.m *objSecond = [[SecondViewController.m] initwithNibName:#"secondView.xib" bundle:nil];
[objSecond setString:#"Comment Controller"];
[self.navigationController pushViewController:objSecond animated:YES];
[objSecond release];
Now, In secondViewController viewWillAppear Method write this.
-(void)viewWillAppear:(BOOL)animated{
lblUserInput.text = strABC;
}
Please check spelling mistakes as I hand written this. Hope this help.
If you are not using navigationContoller then you can do something like this.
SecondViewControler *objSecond = [[SecondViewController] initwithNibName:#"secondview.xib" bundle:nil];
[objSecond setUserInput:txtUserInput.text];
[objSecond viewWillAppear:YES];
[self.view addSubview:objSecond];
[objSecond release];

Related

MFMailComposeViewController in a separate class

I seek to create a "Utility Email sender class" that I can use in several iPhone projects.
I created MailSender header and implementation for that purpose.
MailSender.h:
#interface MailSender : NSObject<MFMailComposeViewControllerDelegate>
- (id) initWithParent:(UIViewController*) mainController;
- (void) invokeMailSender:(NSString*) to:(NSString*) subject:(NSString*) failureTitle:(NSString*) failureMessage:(NSString*) failureCancel;
#end
MailSender.m:
#import "MailSender.h"
#implementation MailSender
MFMailComposeViewController* mailer;
UIViewController* mailParentController;
- (id) initWithParent:(UIViewController*) mainController
{
if( self = [super init])
{
mailParentController = mainController;
}
return self;
}
- (void) invokeMailSender:(NSString*) to:(NSString*) subject:(NSString*) failureTitle:(NSString*) failureMessage:(NSString*) failureCancel;
{
if([MFMailComposeViewController canSendMail])
{
mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:subject];
NSArray *toRecipients = [NSArray arrayWithObjects:to, nil];
[mailer setToRecipients:toRecipients];
[mailParentController presentModalViewController:mailer animated:YES];
}
else
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:failureTitle message:failureMessage
delegate:nil cancelButtonTitle:failureCancel otherButtonTitles: nil];
[alert show];
}
}
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
// Do nothing
[mailParentController dismissModalViewControllerAnimated:YES];
mailer = nil;
}
#end
I called the class from a View Controller (in a button touch down action) using the following instructions:
#implementation InfoViewController
MailSender *sender;
- (IBAction)openMail:(id)sender
{
sender = [[MailSender alloc] initWithParent:self];
[sender invokeMailSender:#"test#test.com" :#"123" :#"123" :#"123" :#"123"];
}
....
#end
When I run the code, I am able to show the email views correctly. However, this is then followed by a crash.
Note that I do not have a crash when using MFMailComposeViewController directly from my UIViewController (And assigning the View Controller as the delegate),
Any ideas?
Sorry I am still a new to Objective C :)
You need to retain your sender MailSender instance. It is being released after you call the invoke message.
You could do this by declaring a property named sender. E.g.
#property (strong, nonatomic) MailSender *sender;
...
#synthesize sender = _sender;
...
self.sender = [[MailSender alloc] initWithParent:self];
[self.sender invokeMailSender:#"noor#dimachk.com" :#"123" :#"123" :#"123" :#"123"];
By the way, your method declaration is a bit funny. You should name the arguments. E.g.
- (void)invokeMailSender:(NSString *)sender
to:(NSString *)to
subject:(NSString *)subject
failureTitle:(NSString *)failureTitle
failureMessage:(NSString *)failureMessage
failureCancelButtonTitle:(NSString *)failureCancelButtonTitle

Display a UIAlertView in NSObject Class

I'm building a login system within my app that will be called several times. So instead of copying and pasting the code into several spots, I'm of course making an NSObject class so I can call the class when needed, instead.
The login system will display a UIAlertView, and when "OK" is tapped, the system will attempt to log in. I can call the class and the UIAlertView will show, but I cannot tell which buttons are tapped. Here is my code:
//Calling the login system
Login *login = [[Login alloc] init];
Login.h:
#import <Foundation/Foundation.h>
#interface Login : NSObject <UIAlertViewDelegate> {
}
#end
Login.m:
#import "Login.h"
#implementation Login
+(void)initialize {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Login" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[alert show];
[alert release];
NSLog(#"Testing");
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"Here");
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"OK"]) {
NSLog(#"Tapped");
}
}
#end
For now, before I put UITextFields in the view, I just want to get the app to know which button was tapped. Testing appears in the log, but neither Here nor Tapped appear. Thanks!
Your alert view should not be called by the class method +(void)initialize but by the instance -(id)init method that's why your instance doesn't get the notifications.
the class method "+(void)initialize" is called when the class first load.
the instance method "-(id)init" has its name beginning by init, and is called when you create (instantiate) your object.
-(id)init {
//alert view
self = [super init];
return self;
}
Just
switch(buttonIndex){
case 0:
NSLog(#"Tapped First Button");
break;
case 1:
break;
default:
break;
}
When you use self in a class method you're referring to the class itself, rather than an instance of the class. However, your delegate method is an instance method. You probably want the caller to create a Login instance and have the instance create the alert, plus be its delegate.
It's Simple :
Create a property for your NSObject class in your view controller class :
in h file :
#property (nonatomic , retain) LoginCheckNSObject *LoginCheckerObject;
in m file :
self.LoginCheckerObject=[[LoginCheckNSObject alloc] init];
[self.LoginCheckerObject setDelegate:self];
[self.LoginCheckerObject TrackNowLogin];

Using UIAlertView in an NSObject

I'm having a terrible time getting a UIAlertView to work within my custom NSObject class. In the research I've done it appears it should be possible but here's what I've run into.
First, here's my code:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"clickedButtonAtIndex: %d", buttonIndex);
}
-(void)testAlertView {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"List Contains Items"
message:#"List contains items. Remove all items & delete?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[alertView show];
}
If I set the delegate to self this code crashes as soon as I tap a button. If I set it to nil clickedButtonAtIndex is never called. I've tried with and without using the <UIAlertViewDelegate>.
I know someone will ask 'why are you doing this in NSObject instead of in your UIViewController?'. Primarily because I want to separate this code out so I can use it from multiple places in my app. But also because this is a small piece of a larger block of logic that makes sense to be on it's own.
Any ideas what I'm doing wrong?
Thanks,
Rich
I had the same problem using ARC. The root of the problem was the same. I solved it by putting my custom NSObject into a "strong" property to make sure the object exists as long as the calling object (an UIVIewCOntroller in my case) exists, so when the delegate of my alert view is called I still have my custom object around and the delegate method works fine.
Add the NSObject as strong property:
#import "Logout.h" // is NSObject
.
.
.
#property (nonatomic, strong) Logout *logout;
Then you will get the delegatemethods called in your NSObject.
Don´t forget to register the delegate for the UIAlertView:
#interface Logout () <UIAlertViewDelegate>
and in your method:
UIAlertView *a = [[UIAlertView alloc] initWithTitle:#"title"
message:#"message" delegate:self cancelButtonTitle:#"cancel"
otherButtonTitles:#"ok", nil];
[a show];
How To Present An Alert View Using UIAlertController When You Don't Have A View Controller. Detail description.
Yes, you can only use UIAlertController only in UIViewController classes. So how can we do it in NSObject classes. If you see the description link given above you will get to the answer. To summarise in a line for the above description: Create a new window above the the current window. This new window will be our viewController where we display alert. So using this viewController you can call the method [presentViewController: animated: completion:].
Answer:
dispatch_async(dispatch_get_main_queue(), ^{
UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = [UIViewController new];
window.windowLevel = UIWindowLevelAlert + 1;
NSString *msg=#“Your mssg";
UIAlertController* alertCtrl = [UIAlertController alertControllerWithTitle:#“Title" message:msg preferredStyle:UIAlertControllerStyleAlert];
[alertCtrl addAction:[UIAlertAction actionWithTitle:NSLocalizedString(#"Yes",#"Generic confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
// do your stuff
// very important to hide the window afterwards.
window.hidden = YES;
}]];
UIAlertAction *cancelAction= [UIAlertAction actionWithTitle:#"cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
window.hidden = YES;
}];
[alertCtrl addAction:cancelAction];
//http://stackoverflow.com/questions/25260290/makekeywindow-vs-makekeyandvisible
[window makeKeyAndVisible]; //The makeKeyAndVisible message makes a window key, and moves it to be in front of any other windows on its level
[window.rootViewController presentViewController:alertCtrl animated:YES completion:nil];
});

'NSObject' may not respond to -navigationController

Hi there I currently I have a warning on a line of code where I am trying to push a new view onto the screen.
Outline // my NSObject receives a code=1 from my server I have set up. Everything works fine the code comes through which then initializes an AlertView where I have set up an if statement to catch the button click of my AlertView message. When that button is pressed my application falls over.
I have declared my ViewController of the view I am trying to push in its header file and there are no errors just the warning when compiled.
this is my NSObject I have made
/////.h
#import <Foundation/Foundation.h>
#interface alerts : NSObject {
}
- (void)pleaseRegisterDevice;
#end
/////.m
#import "alerts.h"
#import "instaCode1_3AppDelegate.h"
#import "RegisterDeviceViewController.h"
#implementation alerts
//use this alert when phone falls out of sync
- (void)pleaseRegisterDevice {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Please Register Device"
message:#"click OK to register"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert autorelease];
[alert show];
}
//Catch pleaseRegisterDevice method
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
NSString *buttonTitle=[alertView buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"OK"]) {
NSLog(#"msg from alertView method");
//open new wndow
RegisterDeviceViewController *regViewController = [[RegisterDeviceViewController alloc] init];
//Push it onto the top pf the navigation controller's stack
**[[self navigationController] pushViewController:regViewController animated:YES];**
}
else {
NSLog(#"was not able to push view");
}
}
- (void)dealloc {
[super dealloc];
}
#end
I have bolded the line of code where I get the warning 'alerts' may not respond to -navigationController
any help would be greatly appreciated.
I dont think an NSObject subclass has a UINavigationController...
You need to get a pointer to your app delegate's navigation controller like so
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.navigationController pushViewController:regViewController animated:YES];
navigationController is a property defined on a UIViewController. A NSObject does not have this method.
You don't have any instance member or method called navigationController, hence the warning.

Pass an int between a view and it's subview

I have a view called PatternsViewController and a subview named SolutionsViewController. I want to pass a variable in PatternsViewController named iteration to my SolutionsViewController, right before I present it with
solutions = [[SolutionsViewController alloc] init];
solutions.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:solutions animated:YES];
solutions = [[SolutionsViewController alloc] init];
solutions.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
// Set your value here
[solutions setMyIntWithSomeMethodIWrote:123];
[self presentModalViewController:solutions animated:YES];
And in SolutionsViewController
- (void)setMyIntWithSomeMethodIWrote:(int)value {
myInstanceVar = value;
}
I figured it out by slightly modifying Squeegy's code.
In PatternsViewController.m
[solutions setIteration:iteration];
and in SolutionsViewController.m
-(void) setIteration:(int)value {
iteration = value;
NSLog(#"Iteration set from value: %d" , iteration);
}
I would use a Singleton class.
What should my Objective-C singleton look like?
Then you can do like:
[SingletonClass sharedInstance].var = iteration;
And access it with:
[SingletonClass sharedInstance].var
Why not simply over-ride the init with an additional argument that take the int you want to set? This allows a clean instantiation without an added set call.
solutions = [[SolutionsViewController alloc] initWithIntVal: int];
The selected answer works for me but it is giving me a semantic warning. I'm a little annal retentive about warnings even if the code works so I am wondering if there is a way to make it work without the warning.
The warning is:
Instance method '-SetPrompt:' not found (return type defaults to 'id')
Here is what I did while following along to the answer in this question.
In the calling .m file
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
vcSelection *ViewSelection = [[vcSelection alloc] initWithNibName:#"vcSelection" bundle:nil];
ViewSelection.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
if ([[SettingsTableData objectAtIndex:indexPath.row] isEqualToString:DeviceType])
{
[ViewSelection SetPrompt:#"Select the device type."];
}
else if ([[SettingsTableData objectAtIndex:indexPath.row] isEqualToString:DeviceManufacturer])
{
[ViewSelection SetPrompt:#"Select the device manufacturer."];
}
else if ([[SettingsTableData objectAtIndex:indexPath.row] isEqualToString:DeviceModel])
{
[ViewSelection SetPrompt:#"Select the device model."];
}
[self.view addSubview:ViewSelection.view];
}
In the receiving .m file
#implementation vcSelection
NSMutableString *Prompt;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Debug"
message:Prompt
delegate:self
cancelButtonTitle:#"Done"
otherButtonTitles:nil];
[alert show];
[alert release];
}
- (void) SetPrompt:(NSMutableString *)Value
{
Prompt = Value;
}
#end