So i'm trying to pass data between two views (first view is tableViewController,when cell is pressed data is send to second view,second view got imageView, when data is send image is shown) using this tutorial iphonedevsdk.
I'm using same theAppDataObject method in my views:
- (AppDataObject*) theAppDataObject
{
id<AppDelegateProtocol> theDelegate = (id<AppDelegateProtocol>) [UIApplication sharedApplication].delegate;
AppDataObject* theDataObject;
theDataObject = (AppDataObject*) theDelegate.theAppDataObject;
return theDataObject;
}
When cell is pressed i'm trying to send data theAppDataObject.imageString = tempImageString;:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
tempImageString = (((championList *) [self.champions objectAtIndex:indexPath.row]).championImage);
AppDataObject *theDataObject = [self theAppDataObject];
NSLog(#"tempIm-g = %#",tempImageString);
theDataObject.imageString = tempImageString;
NSLog(#"theAppDataObject.imageString = %#",theDataObject.imageString);
[self.navigationController popToRootViewControllerAnimated:YES];
}
NSLog output:
tempIm-g = Champ_0.jpg
theAppDataObject.imageString = (null)
SecondViewController (show image):
-(void)viewWillAppear:(BOOL)animated
{
AppDataObject* theDataObject = [self theAppDataObject];
UIImage *tempImage = [UIImage imageNamed:theDataObject.imageString];
NSLog(#"temp image = %#",tempImage);
[choosenChampionImageView setImage:tempImage];
}
NSLog output:
temp image = (null)
My problem is that theAppDataObject.imageString is always null
Possible solutions that i know:
Do not use AppDataObject as generic data container and just save data in appDelegate.
Ex.:
AppDelegate *appdelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
appdelegate.imageString = tempImageString;
But i want to figure out how to use protocols.
What i tried:
Make theDataObject global:
view1.h
#interface championsListTableViewController : UITableViewController
{
NSString *tempImageString;
AppDataObject* theDataObject;
}
#property(strong,nonatomic) NSString *tempImageString;
#property(strong,nonatomic) AppDataObject* theDataObject;
output of NSLog(#"theDataObject is %#",theDataObject); :
theDataObject is (null), how is this possible?
First Check theAppDataObject is null or not.
If it is null then:
Write AppDataObject* theDataObject; in your inteface and declare a property as strong
If theDelegate.theAppDataObject is returning null , allocate that object first.
If it is not null then:
Change this line theAppDataObject.imageString = tempImageString;
to
theAppDataObject.imageString = [tempImageString retain];
If you are using ARC set the property of imageString to strong.
or Check with this
theAppDataObject.imageString = [[NSString alloc] initWthString:tempImageString];
In a class if you want to use a protocal you can use like as :
// this the way too declare a protocal.
// .h file
#protocol TestProtocol <NSObject>
-(void)testMyProtocolMethod:(NSString *)testvalue;
#end
#interface TestProtocolClass: NSObject
{
id <TestProtocol> delegate;
}
#property (nonatomic , assign) id <TestProtocol> delegate;
/* synthesize in the .m file of this class*/
#end
//Now you have to use this protocol in any class where you want to use , Do like as:
//let us suppose you want to use this protocal method in a class named "DemoProtocal".
// .h file
import "TestProtocol.h"
#interface DemoProtocal <TestProtocol>{
}
#end
//.m file
#import "DemoProtocal.h"
#implementation DemoProtocal
- (id)init{
TestProtocol *test = [[TestProtocol alloc]init];
test.delegate = self;
}
-(void)testMyProtocolMethod:(NSString *)testvalue{
// Do appropriate things.
}
#end
In any class where you want to set any variable of the "AppDelegate Class", you can try this, this will surely solve your problem.
//Declare a variable from where you want to set the value of the "AppDelegate Class".
//in the yourclass.h file.
AppDelegate/* this is the main class of the Application*/ *appDel;
//and initialize it where you want to use or you can initialize at the init of the class.
appDel = (AppDelegate *)[[UIApplication sharedApplication]delegate];
// Then set the value.
appDel.imageString = tempImageString;
Related
I have to pass a UITextField value from one view to other views(2nd,3rd...views).Actually in my 3rd ViewController I have a scrollView and I have to display value on it .But UITextField value is not getting passed.It is returning null.Couldn't get what might be wrong?
THis is the code I am working with:
In ViewController1.m:
-(IBAction)butonclick:(id)sender{
ViewController2 *view2=[ViewController2 alloc];
view2.id=name.text;
ViewController3 *view3=[ViewController3 alloc];
view3.id=name.text;
[view2 release];
[view3 release];
}
IN ViewConroller2.h :
#interface ViewController2 : UIViewController {
NSString *id;
UIlabel *displayId;
}
In ViewController2.m :
- (void)viewDidLoad
{
self.displayId.text=self.id;
}
In ViewController3.h:
#interface ViewController2 : UIViewController {
NSString *id;
UIlabel *dispId;
}
In ViewController3.m :
- (void)viewDidLoad
{
self.dispId.text=self.id;
}
But here the id value is not passed to ViewController3.It is returning null ..Where I m going wrong?
You are passing the values without initializing.
ViewController2 *view2=[[ViewController2 alloc]init];
view2.id=name.text;
ViewController3 *view3=[[ViewController3 alloc]init];
view3.id=name.text;
If you want to use object globally within your app, you can declare it in the appDelegate.
In AppDelegate.h
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
NSString *idGlobal;
}
#property (nonatomic, retain) NSString *idGlobal;
In AppDelegate.m
#synthesize idGlobal;
In ViewController1.m:
-(IBAction)butonclick:(id)sender{
appDelegate.idGlobal=name.text;
}
In ViewController2.m: and
In ViewController3.m:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
id=appDelegate.idGlobal;
Declare the string globally in the AppDelegate.h this will help in keeping the value of the string constant throughout the files. Also wherever you want to add the string or change its value or assign it import the AppDelegate.h .
Also check these links :-
passing NSString from one class to the other
Pass NSString from one class to another
I am just correcting the code you have written meanwhile the suggestions given above for using AppDelegate property is a good one.
The main problem with your code is that you are just declaring NSString object instead of making it a property. Check this:
-(IBAction)butonclick:(id)sender{
ViewController2 *view2=[ViewController2 alloc]init];
view2.str=name.text;
ViewController3 *view3=[ViewController3 alloc]init;
view3.str=name.text;
[view2 release];
[view3 release];
}
IN ViewConroller2.h :
#interface ViewController2 : UIViewController {
NSString *str;
UIlabel *displayId;
}
#property(nonatomic, retain) NSString* str; //Synthesize it in .m file
In ViewController2.m :
- (void)viewDidLoad
{
self.displayId.text=self.str;
}
In ViewController3.h:
#interface ViewController2 : UIViewController {
NSString *str;
UIlabel *dispId;
}
#property(nonatomic, retain) NSString* str; //Synthesize it in .m file
In ViewController3.m :
- (void)viewDidLoad
{
self.dispId.text=self.str;
}
I am not aware with your scenario but the most effective way of implementing such situations is using Delegates. Make a delegate of the class where your string is being set (ViewController1) and set delegate accordingly in your other view controllers.
I have a TableViewController that segues into a TabBarViewController.
I know how to pass my object via a segue, but not by a relationship like the TabBarViewController and it's tab share.
How can I do this? From the TabView is there a way to access the TabBarViewControllers member variables?
Update:
This is how I've solved the problem so far, but I'm not crazy about using the AppDelegate to do this...
Add the Following to WhateverYouNamedYourAppDelegate.h
#class myObjectIWantToPass;
#property (strong, nonatomic) myObjectIWantToPass *object;
Then add the following to the View Class file you have your data in that you want to pass on. I'm going to assume you know how to set up your object already in this file if your planning on passing it to another view.
WhateverYouNamedYourAppDelegate *appDelegate =
(WhateverYouNamedYourAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.object = object;
Then you do some similar work to retrieve the object back from the appDelegate in your destination View Class.
WhateverYouNamedYourAppDelegate *appDelegate = (WhateverYouNamedYourAppDelegate *)[[UIApplication sharedApplication] delegate];
object = appDelegate.object;
You can make singleton classes, so that all of the controllers can access those variables in the Singleton. See Code below
SingletonClass.h
#interface SingletonClass : NSObject {
NSString *someString;
}
#property(nonatomic, retain)NSString *someString;
+(id)shared;
#end
SingletonClass.m
#import "SingletonClass.h"
static SingletonClass *aShared;
#implementation LibShared
#synthesize someString;
+(id)shared
{
if (aShared == nil) {
aShared = [[self alloc] init];
}
return aShared;
}
-(id)init
{
if (self = [super init]) {
}
}
-(void)dealloc
{
[someString releease];
[super dealloc];
}
In the tabbar you can set the variable on SingletonClass:
[[SingletonClass shared] setSomeString:#"Value_Set"];
On the tableViewController, you can get the property of the someString variable on the SingletonClass:
NSString *string = [[SingletonClass shared] someString];
There's no need for a singleton pattern here. Instead, you can send the data-object forwards in - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender just as you do normally, you just need to find the correct viewController in the UITabBarController's viewControllers property.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"MyTabBarSegue]) {
UITabBarController *tabBarController = segue.destinationViewController;
// Either set the index here, if you know for sure which viewController is which, or
// Enumerate the viewControllers for isKindOfClass:[MYCustomViewController class] to be robust and change-proof
MYCustomViewController *myVC = [[tabBarController viewControllers] objectAtIndex:0];
myVC.dataObject = self.dataObject;
}
}
this is probably simple but I'm stuck!
Basically I have a parent and child view controller, and I'm trying to pass data from the child to the parent.
//Child VC interface
#protocol ANSearchGetawayFilterDelegate
-(void)selectedCell:(NSString *)cellTitle;
#end
#interface ANSearchGetawayFilterViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
{
NSString* cellTitle;
}
#property (nonatomic, assign) id<ANSearchGetawayFilterDelegate> delegate;
#end
//Child VC implementation
#implementation ANSearchGetawayFilterViewController
#synthesize delegate = _delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
cellTitle = selectedCell.textLabel.text;
[[self delegate] selectedCell:cellTitle];
[self dismissModalViewControllerAnimated:YES];
}
//Parent VC interface
#import "ANSearchGetawayFilterViewController.h"
#interface ANGetawayFilterViewController : UIViewController <ANSearchGetawayFilterDelegate>
{
NSString* _cellText;
}
//Parent VC Implementation
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
search.delegate = self;
}
return self;
}
//delegate method
-(void)selectedCell:(NSString *)cellTitle
{
_cellText = cellTitle;
NSLog(#"cell text %#", _cellText);
}
the delegate method is never called and when is NSLog the _cellText else where it comes up as null...what am I doing wrong? Thanks!
You are most likely creating a new instance of ANSearchGetawayFilterViewController when you present it and not configuring the delegate on it.
When you called
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
search.delegate = self;
you created an instance of ANSearchGetawayFilterViewController and then set the delegate up correctly, but you never stored this instance of ANSearchGetawayFilterViewController anywhere. So later on when you come to present it you call again
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
which gives you a completely different instance, which you then need to configure again. For example
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
ANSearchGetawayFilterViewController *search1 = [[ANSearchGetawayFilterViewController alloc] init];
NSLog(#"%d", search1 == search);
#=> 0
To fix update your code to be
- (BOOL)textFieldShouldBeginEditing:(UITextField*)textField;
{
BOOL shouldBeginEditing = YES;
NSLog(#"text field should begin editing");
ANSearchGetawayFilterViewController *myANSearchGetawayFilterViewController = [[[ANSearchGetawayFilterViewController alloc] init] autorelease];
myANSearchGetawayFilterViewController.delegate = self; // <--- configure the delegate
[self presentModalViewController:myANSearchGetawayFilterViewController animated:YES];
[self closeAllPickers];
return shouldBeginEditing;
}
I wouldn't make it an ivar as the likelihood is you will present this viewController momentarily just to select some data and then get rid of it, so it is probably safe to discard it and make a new one each time.
Au contraire, the delegate method is being called (hence the NSLog()). However, _cellText is (null) because the value being passed in is nil, ergo selectedCell.textLabel.text.
Firstly, are you sure that the -selectedCell method is being called?
You can do this by putting an NSLog() before or after -tableViewDidSelectRow...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
NSLog(#"TABLEVIEW DID SELECT ROW BEFORE -> %# <-", cellTitle);
[[self delegate] selectedCell:cellTitle];
NSLog(#"TABLEVIEW DID SELECT ROW DELEGATE CALLED");
...
}
Also, you might want to do some cleanup (optional)
Firstly, you are leaking in your initialisation method. Either set the ANGetawayFilterViewController as a property of the parent class using the delegate, or release it after you set the delegate.
Secondly, in the -tableViewDidSelectRow, your code assumes that the delegate has the -selectedCell method coded. If you don't have the method implemented, then the application will result in a crash. You can prevent this by checking to see if the delegate -respondsToSelector...:
if ([self.delegate respondsToSelector:#selector(selectedCell:)]) {
[self.delegate selectedCell:cellTitle];
}
Thirdly, the method of which is being called by the delegate to notify the parentViewController doesn't follow the general schema that delegate methods use, with the exception of -numberOfRowsInSection (UITableViewDelegate). Your method should contain the actual ANFilterGetawayViewController instance too:
- (void) filterGetawayViewController:(ANSearchGetawayFilterViewController *) controller didSelectCellWithTitle:(NSString *) title {
...
}
It can be called as such:
[self.delegate filterGetawayViewController:self didSelectCellWithTitle:cellTitle];
Are you using ARC? Because when the init function ends, your object (and it's reference to the delegate) are cleaned up. What happens if you make the search variable a global one (defining it in your header and initializing it in your code)?
Assuming you are using ARC:
You need to make a retained #property for your ANSearchGetawayFilterViewController instance. It will have been released by ARC by the time the delegate method is called. Do something like this.
#property (strong, nonatomic) ANSearchGetawayFilterViewController *search;
...
#synthesize search = _search;
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
self.search = [[ANSearchGetawayFilterViewController alloc] init];
self.search.delegate = self;
}
return self;
}
Not related to your problem, but best practice is to check if the delegate actually implements the method you expect it to before calling it, like so:
if ([self.delegate respondsToSelector:#selector(selectedCell:)]) {
[self.delegate selectedCell:cellTitle];
}
ok, i was trying to understand this post about best way to transfer data from one view controller to other.
the thing is, if i want to set an attr of the object its works like a champ. If i try to set the entire object, it doesnt do it.
my code is:
#protocol AppDelegateProtocol
- (Lote*) theLoteAppObject;
#end
on AppDelegate:
#interface AgroferiaAppDelegate : NSObject <UIApplicationDelegate, AppDelegateProtocol> {
Lote *theLoteAppObject;
}
#property (nonatomic, retain) Lote *theLoteAppObject;
#end
...
...
- (id) init;
{
self.theLoteAppObject = [[Lote alloc] init];
[theLoteAppObject release];
return [super init];
}
the class where i get the problem (UIViewcontroller):
-(void)tableView:(UITableView *) aTableView didSelectRowAtIndexPath:(NSIndexPath *) indexPax{
...
NSArray *lotes = [[self.evento lotesStore]allLotes] ;
Lote* theDataObject = [self theLoteAppObject];
theDataObject._id = [[lotes objectAtIndex:[indexPax row]]_id];
[[self navigationController]pushViewController:lotesOpViewController animated:YES];
}
- (Lote*) theLoteAppObject;{
id<AppDelegateProtocol> theDelegate = (id<AppDelegateProtocol>) [UIApplication sharedApplication].delegate;
Lote* theDataObject;
theDataObject = (Lote*) theDelegate.theLoteAppObject;
return theDataObject;
}
so that works, but if i want to do the followimg,
theDataObject = [lotes objectAtIndex:[indexPax row]];
it does not save the object on theDataObject.
is this a problem of bad memory managment?
edit: is it theDataObject a reference from appDelegate ?? or here is the problem?
try something like this:
if([indexPax row] < [lotes count])
{
Lotes * dataObjectToCopy = [lotes objectAtIndex: [indexPax row]];
if(dataObjectToCopy)
{
theDataObject = [dataObjectToCopy copy];
}
}
This creates a separate, retained copy of your Lote object. Make sure to release it when you're finished with it (if you're not using ARC).
I have 4 buttons on main screen, each one sends me to a viewController. The third one, sends me to a view on which I wanna set the managedObjectContext. If I use the class name to create an instance, it's all right. But I'm looking for a way to use just one method that uses an array to retrieve the name of the Class for the needed viewController. But it's leading to an error message, like it doesn't exist on the destination viewController??? Anyone have any ideas about this aproach??? Thanks in advance!
Here is the code:
NSArray *viewControllers = [[NSArray alloc]
initWithObjects:#"nil",#"OpcoesView",#"nil",#"TheNames", nil];
NSString *viewName = [viewControllers objectAtIndex:[sender tag]]; //the taped button tag
UIViewController *viewController = [[NSClassFromString(viewName) alloc]
initWithNibName:viewName bundle:nil];
if ([sender tag] == 3) {
viewController.managedObjectContext = contexto;
}
You do not need to know the subclass at all. Because Objective-C is a dynamic language and messages are resolved at runtime, you can send the message without having to know anything about the subclass at all.
First I would refer to the subclass as an id (instead of UIViewController) and as long as you have its header imported you can call [viewController setManagedObjectContext:contexto] directly.
However if you don't want to or can't import the header then just use KVC as follows:
[viewController setValue:contexto forKey:#"managedObjectContext"];
I would keep MOC in my app delegate instead of assigning it down to every of my viewControllers:
And in my viewController .m file:
#import "MyAppDelegate.h" // Assuming you have a property called managedObjectContext in your MyAppDelegate
#interface MyViewController (PrivateMethgods)
#property (nonatomic, readonly) NSManagedObjectContext * managedObjectContext;
#end
#implementation MyViewController
#dynamic managedObjectContext
- (NSManagedObjectContext *)managedObjectContext {
MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
return appDelegate.managedObjectContext;
}
So I can use it in my viewController like this:
if ([self.managedObjectContext hasChanges]) {
...
}
To set a property that is only in the subclass view controller (such as "managedObjectContext"), you can take advantage of the fact that you know the type like this:
NSArray *viewControllerNames = [[NSArray alloc] initWithObjects:#"nil",#"OpcoesView",#"nil",#"TheNames", nil];
NSString *viewControllerName = [viewControllerNames objectAtIndex:[sender tag]]; //the tapped button tag
UIViewController *viewController = [[NSClassFromString(viewControllerName) alloc] initWithNibName:viewControllerName bundle:nil];
if ([sender tag] == 3) {
TheNames *namesVC = (TheNames*)viewController;
namesVC.managedObjectContext = contexto;
}