How to use NSString from NSObject class in multiple Classes (View Controllers) [duplicate] - iphone

This question already has answers here:
What's the best way to communicate between view controllers?
(4 answers)
Closed 9 years ago.
I have NSObject class that has a NSString called tweetTitle;
TweetDesc.h file
#import <Foundation/Foundation.h>
#interface TweetDesc : NSObject
#property (strong, nonatomic) NSString * tweetTitle;
-(void) setFullTweetTitle:(NSString *) fullTweetTitle;
#end
TweetDesc.m file
#implementation TweetDesc
#synthesize tweetTitle;
-(void) setFullTweetTitle:(NSString *) fullTweetTitle
{
self.tweetTitle = fullTweetTitle;
}
#end
I have three classes (View Controllers), FirstViewController, SecondViewController and ThirdViewController.
Here are the code of FirstViewController
FirstViewController.h
#interface TweetViewController : UIViewController <UITextViewDelegate>
#property (strong, nonatomic) NSString * tweet;
#property (weak, nonatomic) IBOutlet UITextView *tvTweetTitle;
- (IBAction)btnCreateTweet:(id)sender;
#end
FirstViewController.m
#implementation TweetViewController
#synthesize tvTweetTitle, tweet;
- (void)viewDidLoad
{
[super viewDidLoad];
self.tvTweetTitle.delegate = self;
}
- (IBAction)btnCreateTweet:(id)sender
{
tweet = [[NSString alloc]initWithFormat:#"%#", tvTweetTitle.text];
TweetDesc * td = [[TweetDesc alloc]init];
[td setFullTweetTitle:tweet];
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:ivc animated:YES];
}
My Question is: How can I use tweetTitle in Second and third ViewController without creating new instance of TweetDesc class and set again the tweetTitle in every ViewControler.
In the second view controller I tried:
TweetDesc * td = [[TweetDesc alloc]init];
NSLog(#"%#", td.tweetTitle);
but I get null, it seems that it was released already or something else.
Thanks for the help in advance.

Just give SecondViewController a TweetDesc property, like this:
#interface TweetDesc : UIViewController
#property (nonatomic, strong) TweetDesc *tweetDesc;
...
Then, after you instantiate a SecondViewController, set its tweetDesc property:
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
svc.tweetDesc = td;
[self.navigationController pushViewController:svc animated:YES];
In your SecondViewController implementation, use self.tweetDesc to access the instance.

First thing you don't need a class for a single property use the string only. There are several ways of doing this.
First you can have a tweet property globally defined in AppDelegate.
You can pass the variable reference from one to another viewcontrolleres.
Or, you can use NSUserDefaults to set and get the text.
In your case first one is more useful. Just do as follows
In AppDelegate.h
Define a property as NSString *tweetText;
Now in you action
- (IBAction)btnCreateTweet:(id)sender
{
AppDelegate *appDelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.tweetText=tvTweetTitle.text;
}
Then in any controller you want to access the value just use
AppDelegate *appDelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog("%#",appDelegate.tweetText);
Same approach can be used for NSUserDefaults as to set value
[[NSUserDefaults standardUserDefaults] setObject:tvTweetTitle.text forKey:#"Tweet"];
[[NSUserDefaults standardUserDefaults] synchronize];
and to get
NSLog("%#",[[NSUserDefaults standardUserDefaults] valueForKey:#"Tweet"]);
Make sure you set the values before navigating to other controllers..
The above should solve your purpose..

Based on your comment I feel you want each of your view controllers to hold a TweetDesc object. For that you could have a base class like
#interface baseViewController:UIViewController
#property(strong, nonatomic)TweetDesc *td;
#end
All your viewcontrollers should derive from this base class. So that your controllers definition look like this -
#interface FirstViewController:baseViewController
...
#end
#interface SecondViewController:baseViewController
...
#end
#interface ThirdViewController:baseViewController
...
#end
U instantiate it in the FirstViewController -
TweetDesc * td = [[TweetDesc alloc]init];
[td setFullTweetTitle:#"whatever string you want"];
And pass it on to SecondViewController - //like in Rob Mayoff's answer
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
svc.tweetDesc = td;
[self.navigationController pushViewController:svc animated:YES];
INSIDE SecondViewController you may refer it as self.tweetDesc. And pass it on to whichever viewcontroller you want after this using the above code.
ThirdViewController *third= [self.storyboard instantiateViewControllerWithIdentifier:#"ThirdViewController "];
third.tweetDesc = self.tweetDesc;
[self.navigationController pushViewController:third animated:YES];
Pass it on the ANY viewcontroller just make sure it's base class is the baseClassViewController.

You need to use category of TweetDesc where you create method that adds your default title. Or you can create singleton of TweetDesc that will always hold one title.

In your ViewController create a method called initWithTweetDesc. The method will look like this:
- (id)initWithTweetDesc:(TweetDesc*)tweet
{
self = [super init];
if (self) {
_tweet = tweet;
}
return self;
}
Now, when you want to move to the new view controller, run this code:
TweetViewController *vc = [[TweetViewController alloc] initWithTweetDesc:tweetDesc];
[self.navigationController pushViewController:vc animated:YES];

You can use your AppDelegate for this.
eclare the property #property(nonatomic, strong) TweetDesc * td; in AppDelegate.h file.
And change the method like:
- (IBAction)btnCreateTweet:(id)sender
{
tweet = [[NSString alloc]initWithFormat:#"%#", tvTweetTitle.text];
TweetDesc * td = [[TweetDesc alloc]init];
[td setFullTweetTitle:tweet];
[[[UIApplication sharedApplication] delegate] setTd:td];
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:ivc animated:YES];
}
And in your second and third view controllers you can get the value using:
TweetDesc *desc = [[[UIApplication sharedApplication] delegate] td];
NSLog(#"%#",desc.fullTweetTitle);

Related

pass NSMutableArray to another view giving null values

I'm new to iOS development and I want to pass an NSMutableArray from one viewcontroller to another but always gives me null values
FirstViewController.h
#interface FirstViewController : UIViewController
#property (nonatomic, retain) NSMutableArray *colorArray;
-(IBAction)btn:(id)sender;
FirstViewController.m
#implementation FirstViewController
-(IBAction)btn:(id)sender
{
SecondViewController* secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondViewController.animalArray = self.colorArray;
NSLog(#"%#",secondViewController.animalArray); // here its not null
[self.navigationController pushViewController:secondViewController animated:YES];
}
SecondViewController.h
#interface SecondViewController : UIViewController
#property (nonatomic, retain) NSMutableArray *animalArray;
SecondViewController.m
I only used NSLog(#"animalArray:%#",self.animalArray); in viewDidLoad to check the values but gives me null
is there anything I'm missing?
Edit :
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"indidLoad%#",self.animalArray);
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(#"inwillAppear%#",self.animalArray);
}
Replace with following method
-(IBAction)btn:(id)sender{
SecondViewController* secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondViewController.animalArray=[[NSMutableArray alloc]initWithArray:self.colorArray];
[self.navigationController pushViewController:secondViewController animated:YES];
}
:) +1
If you call your NSLog from (void)viewWillAppear:(BOOL) animated, you should see something.
In your code example the viewDidLoad method is called straight after initWithNibName :
[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
and before you have a chance to set your property.
**FirstViewController.h**
#interface FirstViewController : UIViewController
{
NSMutableArray *SongArray;
}
#property(nonatomic,retain)NSMutableArray *SongArray;
**FirstViewController.m**
SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondView.SongArray = self.SongArray;
[self.navigationController secondView animated:YES];
**SecondViewController.h**
#interface SecondViewController : UIViewController
{
NSMutableArray *SongArray;
}
#property(nonatomic,retain)NSMutableArray *SongArray;
Do it like this your values arent being retained. Please also check Pass NSMutableArray to one view controller to another
Check the value in viewWillAppear instead of viewDidLoad.
It should work
-(IBAction)btn:(id)sender
{
SecondViewController* secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
NSLog(#"%#",secondViewController.animalArray); // here its not null
[self.navigationController pushViewController:secondViewController animated:YES];
secondViewController.animalArray = self.colorArray;
}
Sometimes if you pass value before pushing the the view it will give null value in second view
Better way is to create your NSMutableArray in Appdelegate file like below...
#property (nonatomic, retain) NSMutableArray *animalArray;//define this in Appdelegate.h file
synthesize it in Appdelegate.m file like
#synthesize animalArray;
Create Appdelegate object in prefix.pch file like below.
#define AppDel ((AppDelegate *)[UIApplication sharedApplication].delegate)
and import your Appdelegate file in prefix.pch like below..
#import "AppDelegate.h"
now where you want to use that array...just write like below..
AppDel.animalArray=//you can do whatever you want with array....
By doing this no need to pass array to other view controller, you can use that global array in whole project ,you can insert object in that array in any class and can access in any class.
Let me know it is working or not!!!
Happy coding!!!!

Objective-C iPhone data between classes

Here is my situation. I have ViewController class A with a button that goes to TableViewController class B by doing the following.
- (void) goToClassB
{
ViewControllerB *viewController =
[[ViewControllerB alloc] initWithStyle:UITableViewStylePlain];
// Present view controller modally.
if ([self
respondsToSelector:#selector(presentViewController:animated:completion:)]) {
[self presentViewController:viewController animated:YES completion:nil];
} else {
[self presentModalViewController:viewController animated:YES];
}
}
I want to be able to have an array that can be accessed and edited by both class A and class B. How can I achieve this?
Create a Array variable in Class B like:
#interface classB:NSObject
{
NSMutableArray *arrayFromA;
}
#property (nonatomic, assign) NSMutableArray *arrayFromA;
Synthesize the variable.
And in this method pass the array like:
- (void) goToClassB
{
ViewControllerB *viewController = [[ViewControllerB alloc] initWithStyle:UITableViewStylePlain];
[viewController setArrayFromA:yourArray];
// Present view controller modally.
if ([self
respondsToSelector:#selector(presentViewController:animated:completion:)])
{
[self presentViewController:viewController animated:YES completion:nil];
}
else
{
[self presentModalViewController:viewController animated:YES];
}
}
Create a NSMutableArray in ViewControllerA and pass it to ViewControllerB after your allocation.
This can be achieve Creating NSMutableArray And And Make it in Property assign in one of the class
#property(nonatomic,assign) NSMutableArray *array;
I mention that you want edit by both so.You can use application delegation for sharing app level variable. Check this link.
Some code is here. In your app delegate class.
#interface YourDelegateClass:UIResponder
{
NSMutableArray *array;
}
#property (nonatomic, assign) NSMutableArray *array;
You can access that array from everywhere of your app class with this code
YourDelegateClass * delegate =[[UIApplication shareApplication]delegate];
yourclassa.array = delegate.array;
or yourclassb.array = delegate.array;
Note: your must alloc *delegate.array* on your prefer at class or your delegate.
Create NSMutable array in view1 set property
#property(nonatomic,assign) NSMutableArray *array;
Create same array in viewB and set property and
#property (nonatomic, assign) NSMutableArray *arrayB;
#Synthesize that
Now at the time call viewB set value of array of viewA to viewB like this
ViewControllerB *viewController = [[ViewControllerB alloc] initWithStyle:UITableViewStylePlain];
[viewController arrayB:array];
The simplest way would, just as others point out, be simply passing the array to B by setting a property, but one other option would be to let B have a weak back reference to A. Thus you're always using the same array. This could be useful if A and B are changing the array at the same time.
#interface ViewControllerA : UIViewController
#property (nonatomic, strong) NSArray *array;
#end
#interface ViewControllerB : UIViewController
#property (nonatomic, weak) ViewControllerA *viewControllerA;
#end
/* When you're creating the ViewControllerB, do this: */
...
viewController.viewControllerA = self;
...
/* Use the array (From ViewControllerB) */
- (void)doSomethingWithTheArray
{
self.viewControllerA.array = ...
}

Pass a value to the text field of the first view

I have two views with navigation controller: first view, there are empty text fields while the second view is a table view where the user can select a row. At the touch of a row there is an action that sets a value to a text field of the first view. Unfortunately when I go back to the first view field is not set.
This is my code:
FirtViewController.h
#interface FirstViewController : UIViewController
{
UITextField *firstField;
UITextField *secondField;
}
#property(nonatomic, retain) IBOutlet UITextField *firstField;
#property(nonatomic, retain) IBOutlet UITextField *secondField;
#property(copy) NSString *selectedRow;
-(IBAction)showTable:(id)sender
FirstViewController.m
#import "FirstViewController.h"
#import "AppDelegate.h"
#import "SecondViewController.h"
#implementation FirstViewController
#synthesize .....
.............
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.firstField.text = selectedRow;
}
-(IBAction)showTable:(id)sender
{
SecondViewController *controllerSecond = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:controllerSecond animated:YES];
}
SecondViewController.h
#class FirstViewController;
#interface ListaViewController : UIViewController
<UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>
{
UITableView *table;
UISearchBar *search;
FirstViewController *controller;
}
#property (nonatomic, retain) FirstViewController *controller;
SeconViewController.m
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedRow = [tableData objectAtIndex:indexPath.row];
controller.selectedRow = selectedRow;
[self.navigationController popViewControllerAnimated:YES];
}
Based on your code above, you never set the connection in secondViewController back to first
You probably need something like this:
-(IBAction)showTable:(id)sender
{
SecondViewController *controllerSecond = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[controllerSecond setController:self]; //this sets the reference back
[self.navigationController pushViewController:controllerSecond animated:YES];
}
What you need to use is delegate. It is very commonly used pattern in Object-C. Check out my answer to this SO post. Let me know if you still need code after.
I'm not certain I fully understand what you mean, but why don't you creating an NSString containing the value you need in the SecondViewController. That way you can do something like this when you set up the SecondViewController.
SecondViewController *nextView = [[SecondViewController alloc] init];
nextView.myNSString = #"Value you need in the next view";
Then in SecondViewController.h you'll be able to access the NSString like so:
#NSLog(#"%#", self.myNSString);
The main thing you are missing is the Value passing between views. You are not using any object in any of the view that is passing the value to another view. Like, If you want to pass a text from FirstViewController to SecondViewController. You Can do it as follwos.
NSString *textToPass = self.firstField.text;
In Your SecondViewController there need to be a string object say passedText. When you create object of secondViewController in firstViewController, Do it as follows:
SecondViewController *controllerSecond = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
controllerSecond.passedText = textToPass;
[self.navigationController pushViewController:controllerSecond animated:YES];
Now Wherever you want to show the text of first screen, just use "passedtext" String.
Hope it Helps.
:)
===============================================
In your code you may try the followinf modification:
NSString *selectedRow = [tableData objectAtIndex:indexPath.row];
controller = (FirstViewController *)[self.navigationController topViewController];
controller.selectedRow = selectedRow;
[self.navigationController popViewControllerAnimated:YES];
It Will resolve your problem forsure.

Access Delegate Data

Hello i'm trying to make a simple ios app with tabs and navigation .
in the delegate i have the following type:
BlogRss * _currentlySelectedBlogItem;
with this property:
#property (readwrite,retain) BlogRss * currentlySelectedBlogItem;
and i'm trying to get his data with two other classes, one is a table view with the data and the other will show the data;
in both classes i have declared the following:
#class NewsAppDelegate;
NewsAppDelegate * _appDelegate;
#property (nonatomic, retain) IBOutlet _NewsAppDelegate * appDelegate;
#synthesize appDelegate = _appDelegate;
ofter "touching" the cell in the table view i wrote this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self appDelegate] setCurrentlySelectedBlogItem:[[[self rssParser]rssItems]objectAtIndex:indexPath.row]];
// Navigation logic may go here. Create and push another view controller.
// [[self appDelegate] loadNewsDetails];
NewsDetailViewController *detailViewController = [[NewsDetailViewController alloc] initWithNibName:#"NewsDetailViewController" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
when i'm writing in the other class:
NSLog(#"%#",self.appDelegate.currentlySelectedBlogItem);
i'm getting null.
clearly i'm doing something wrong, but i don't know what...
The problem is likely that this line is returning null:
[[[self rssParser]rssItems]objectAtIndex:indexPath.row]
Code is easier to debug when you don't nest so many sentences.
You can access your delegate from anywhere because UIApplication is a singleton, you don't need to keep a reference as you do with self.appDelegate. Example:
(NewsAppDelegate *)[[UIApplication sharedApplication] delegate];
Or just do as Jennis suggest, who is a faster typer than me, and remove the IBOutlet. :P
When you do
NewsAppDelegate * _appDelegate;
#property (nonatomic, retain) IBOutlet _NewsAppDelegate * appDelegate;
#synthesize appDelegate = _appDelegate;
The result is the same if you skip the first line, because the runtime creates it for you.
See Question about #synthesize. And I guess _NewsAppDelegate is really NewsAppDelegate (no underscore).
Please do as follow.
//Your Header File
#import "YourAppDelegate.h"
#interface YourViewController : UIViewController
{
YourAppDelegate *appDelegate;
}
#property(nonatomic,retain) YourAppDelegate *appDelegate;
#end
//Your Implementation file
#implementation YourViewController
#synthesize appDelegate
- (void)viewDidLoad {
self.appDelegate = (YourAppDelegate*) [[UIApplication sharedApplication] delegate];
}
#end
After declaring as above you will have access of appDelegate anywhere in your view controller.
Hope it helps.

How to assign managedObjectContext to a dynamic viewController?

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;
}