Accessing an array variable of AppDelegate.m from another ViewController.m - iphone

I have just solved another problem regarding the same piece of code but I want to separate my 2 problems.
I want to store in my AppDelegate the table generated by an Rss parser so that it is not necesary to do it again each time the viewcontroller that displays the list is loaded, To do so, I have the following code:
AppDelegate.h
#import <Three20/Three20.h>
#import "NewsRssParser.h"
#import "NewsRss.h"
#class NewsRssParser;
#class NewsRss;
#interface AppDelegate : NSObject <UIApplicationDelegate,NewsRssParserDelegate> {
NewsRssParser * _rssParser;
NSMutableArray * _newsRssArray;
}
#property(readwrite, retain) NewsRssParser * rssParser;
#property(readwrite, retain) NSMutableArray * newsRssArray;
#end
ApDelegate.m
[...]
#implementation AppDelegate
#synthesize rssParser = _rssParser;
#synthesize newsRssArray = _newsRssArray;
[...]
At a certain stage of execution of the app, the table is properly populated by the Rss parser. When this happens, I want to transform it into a format that can be displayed in another view controller:
(void)myFunction{
NSMutableArray *dsItems = [[[NSMutableArray alloc] init] autorelease];
for(NewsRss *rssItem in self.rssParser.rssItems)
{
NSString * rssItemTitle = [rssItem title];
NSString * rssItemAuthor = [#"par " stringByAppendingString:[rssItem author]];
NSString * rssItemDescription = [rssItem description];
NSString * rssItemLinkUrl = [rssItem linkUrl];
NSString * rssItemImageUrl = [rssItem mediaUrl];
TTTableMessageItem *tMsgItem = [TTTableMessageItem itemWithTitle:rssItemTitle caption:rssItemAuthor text:rssItemDescription timestamp:nil imageURL:rssItemImageUrl URL:rssItemLinkUrl];
[self.newsRssArray addObject:tMsgItem];
[dsItems addObject:tMsgItem];
}
}
I controlled that this works by showing the [_newsRssArray count] in gdb with NSLog. It returns 10 which is the number of articles I have in my RSS feed.
This is when I want to load my ViewController to show the list of articles. I do it this way:
NewsVc.h
#import <Three20/Three20.h>
#protocol NewsVcDelegate;
#class AppDelegate;
#interface NewsVc : TTTableViewController {
id<NewsVcDelegate> _delegate;
AppDelegate * _appDelegate;
}
#property(nonatomic,assign) id<NewsVcDelegate> delegate;
#property(nonatomic, retain) AppDelegate * appDelegate;
#end
#protocol NewsVcDelegate <NSObject>
- (void)NewsVc:(NewsVc*)controller didSelectObject:(id)object;
#end
NewsVc.m
[...]
- (void)loadNewsFromParser {
self.tableView.allowsSelection = NO;
//reload the table view
TTListDataSource *ds = [[TTListDataSource alloc] autorelease];
//NSMutableArray *dsItems = [[[NSMutableArray alloc] init] autorelease];
NSLog(#"NewsVC(loadNewsFromParser):count/newsRssArray=%d", [self.appDelegate.newsRssArray count]);
NSLog(#"NewsVC(loadNewsFromParser):count/rssItems=%d", [self.appDelegate.rssParser.rssItems count]);
[ds initWithItems:self.appDelegate.newsRssArray];
self.dataSource = ds;
self.tableView.allowsSelection = YES;
}
[...]
But in this function of the ViewController, I see the array empty, as well as when I try to access directly the parsed data of the NewsRss. What it wrong on my code of AppDelegate/NewsVc to be able to access this array from NewsVc?
Thanks for your help ! I feel very slow today stuck on this...

Where do you assign appDelegate? There must be a line like this somewhere in your view controller initialization:
self.appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

Related

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

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

Passing Values Between Master and Detail in UISplitViewController Using Storyboards

I have defined the protocol in Customer.h file which is shown below:
#class Customer;
#protocol CustomerDelegate <NSObject>
-(void) didSelectCustomer:(Customer *) customer;
#end
#interface Customer : NSObject
{
}
#property (nonatomic,copy) NSString *name;
#property (nonatomic,copy) NSString *occupation;
#end
The MasterViewController (left side) invokes the didSelectCustomer method as shown below:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Customer *selectedCustomer = [customers objectAtIndex:[indexPath row]];
[self.delegate didSelectCustomer:selectedCustomer];
}
Now, I need to tell the DetailViewController (right side) to do something. The DetailViewController complies with the CustomerDelegate protocol.
#interface DetailViewController : UIViewController<UISplitViewControllerDelegate,CustomerDelegate>
{
}
-(void) didSelectCustomer:(Customer *)customer
{
NSLog(#"sssdasdasdasd");
}
The didSelectCustomer method is never invoked. I think I need to set the masterViewController.delegate = self but I am not sure where to set this thing up.
UPDATE 1:
I added the instance of MasterViewController inside the DetailViewController but it did not work:
- (void)viewDidLoad
{
[super viewDidLoad];
MasterViewController *master = [[MasterViewController alloc] init];
master.delegate = self;
}
SOLUTION:
In AppDelegate:
else
{
UISplitViewController *splitViewController = (UISplitViewController *) self.window.rootViewController;
splitViewController.delegate = [splitViewController.viewControllers lastObject];
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
// splitViewController.delegate = (id)navigationController.topViewController;
DetailViewController *detail =(DetailViewController *) [splitViewController.viewControllers lastObject];
UINavigationController *masterNavigationController = [splitViewController.viewControllers objectAtIndex:0];
MasterViewController *master = (MasterViewController *)masterNavigationController.topViewController;
master.delegate = detail;
}
You never explicitly declare yourself as the delegate to the Consumer class. Merely conforming to it won't cut it. Declare it in -viewDidLoad by creating an instance of Consumer, possibly like this:
-(void)viewDidLoad {
Consumer *consumer = [[Consumer alloc]init];
[consumer setDelegate:self];
}
You also don't declare a property for your delegate object in Consumer, so it can never actually be accessed. Do this first:
#class Customer;
#protocol CustomerDelegate <NSObject>
-(void) didSelectCustomer:(Customer *) customer;
#end
#interface Customer : NSObject
{
}
#property (nonatomic,copy) NSString *name;
#property (nonatomic,copy) NSString *occupation;
#property (weak) id <CustomerDelegate> delegate; //use assign or __unsafe_unretained if targeting <5.0.
#end
You can check if your class conforms to your protocol like so:
if (![delegate conformsToProtocol:#protocol(CustomerDelegate)]) {
[NSException raise:#"Delegate Exception"
format:#"Parameter does not conform to CustomerDelegate protocol at line %d", (int)__LINE__];
}
the split view controller's last object.
this object is return a UI navigation controller.
you know, then you can do yourself.

Null value when accessing variable in other classes (Combined Navigation & Tab Controller)

I have a navigation controller residing inside a tab bar controller and whenever I try to access a class from a class within the navigation controller all my values return (null).
This is how I'm trying to do it.
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate> {
NSString *searchQueryA;
}
#property (strong, nonatomic) NSString *searchQueryA;
ThirdViewController.h
#import "MasterViewController.h"
#import "AppDelegate.h"
#class MasterViewController;
#interface ThirdViewController : UIViewController {
code
}
#property (strong, retain) MasterViewController *masterViewController;
ThirdViewController.m
- (IBAction)showDetail:(id)sender {
AppDelegate *appDelegate = [[AppDelegate alloc] init];
appDelegate.searchQueryA = _searchField.text;
masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[self.navigationController pushViewController:masterViewController animated:YES];
}
MasterViewController.h
#import "AppDelegate.h"
#interface MasterViewController : UITableViewController
{
NSString *searchQueryM;
}
#property (nonatomic, strong) NSString *searchQueryM;
MasterViewController.m
AppDelegate *appDelegate = [[AppDelegate alloc] init];
searchQueryM = appDelegate.searchQueryA;
NSLog(#"%#", searchQueryM);
And in the log I can see that searchQueryM is (null). If I try to access the variable in AppDelegate from another class, that isn't involved with navigation controller, then it shows perfectly fine. What am I missing?
If you need to see more code I'd be happy to provide it.
EDIT:
For legibility I'll post code changes here:
I have the delegate in my AppDelegate.h
As Leonardo pointed out I only alloc'd and init'd my AppDelegate. I changed that snippet to this:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
searchQueryM = appDelegate.searchQueryA;
but still no go as searchQueryM still is (null).
This is what I do with searchQueryM
MasterViewController.h
#interface MasterViewController : UITableViewController
{
NSString *searchQueryM;
}
#property (nonatomic, strong) NSString *searchQueryM;
MasterViewController.m
#synthesize searchQueryM;
I'm fairly new to Objective-C (as well as OO-programming) and should probably read a book on it, but it seems to me like there isn't a lot more to it than that. Do correct me if I'm wrong.
EDIT 2
ThirdViewController.h
#interface ThirdViewController : UIViewController {
UITextField *_searchField;
}
#property (nonatomic, strong) IBOutlet UITextField *searchField;
ThirdViewController.m
#synthesize searchField = _searchField;
...
- (IBAction)showDetail:(id)sender {
_code_
NSLog(#"%#", searchField.text);
_code_
If i type in "asd" in the searchField textfield and output it with the log I get "asd".
}
Why are you alloc init your AppDelegate ?
The AppDelegate should be accessed with:
[[UIApplication sharedApplication] delegate]
We should see how you normally initialize searchQueryM, you are getting null, probably because the AppDelegate get only allocated and init, but the logic that initialize its properties never gets called.

iOS: add new cell to tableview from another view

I was wondering what is the best way to go about adding a new cell to a tableview in iOS. Let's say I have a firstviewcontroller and a secondviewcontroller. On the firstviewcontroller I have a tableview already populated with some data, I also have a navigation bar with an add button on the top. Tapping the add button will present a new view and then I want to pass data from that secondviewcontroller to firstviewcontroller and populate my tableview with it.
Thanks,
Sam
You secondViewController should create a delegate protocol. Your firstViewController should then be assigned as its delegate.
Once secondViewController saves the data it calls a method that your firstViewController should implement
A good exemple here:
How do I create delegates in Objective-C?
To get you started: secondViewController.h
#protocol secondViewControllerDelegate;
#interface secondViewController : UIViewController{
id<secondViewControllerDelegate> __unsafe_unretained delegate;
}
#property (nonatomic, unsafe_unretained) id<secondViewControllerDelegate> delegate;
#end
#protocol secondViewControllerDelegate <NSObject>
- (void)dataSaved;
#end
You can add a new class with tableView data source. initiate it with nesessary data (from both View controllers. use delegate to cooperate them) and after anu data chaging call [tableView setDataSource:]:
// DataSourceAtoZ.h
#import <Foundation/Foundation.h>
#import "MallsViewController.h"
#interface DataSourceCategory : NSObject <UITableViewDataSource> {
NSMutableArray *data;
UITableView *tableView;
}
#property (nonatomic, retain) NSMutableArray *data;
- (id)initWithData:(NSMutableArray *)d;
#end
then, anywhere in your code, compose data you wish to be in tableView and set dataSource:
NSMutableArray *dt = [[NSMutableArray alloc] init];
for (int i = 0; i < [categories count]; i++) {
NSMutableArray *names = [[NSMutableArray alloc] init];
[names addObject:[[categories objectAtIndex:i] objectAtIndex:0]];
for (int j = 1; j < [[categories objectAtIndex:i] count]; j++) {
NSRange match = [[[categories objectAtIndex:i] objectAtIndex:j] rangeOfString:[params objectAtIndex:0]];
if (match.length != 0) {
[names addObject:[[categories objectAtIndex:i] objectAtIndex:j]];
}
}
[dt addObject:names];
[names release];
}
dsCategory = [[DataSourceCategory alloc] init];
dsCategory = [dsCategory initWithData:dt];
[dt release];
You should create your arrays in the App delegate and then call them and change them however you want from there..
MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate];
once you have this line you can connect between two classes and call any methods on the delegate for example:
[appDelegate populateMyArray];
you don't add "new cells" like you described it, you use the same cells and populate them with different data.

Copy of string from one view to another view in iphone

hi i am new to iphone development.
I'm trying with sample where I need to copy a string from the textfield of viewController and display it on the next view with a Label.
On the first view there is button bellow the textfield.1
I am not able to fix some issues showing BAD ACESS can anyone help me in solving this.
Let me know what i'm doing Wrong.
Thank you.
//copystring.h
#interface CopystringViewController : UIViewController{
UITextField *myTextField;
NSString *somestring;
}
#property(nonatomic,retain)IBOutlet UITextField *myTextfield;
#property(nonatomic,retain)NSString *somestring;
-(IBAction)next:(id)sender;
//.m file
#synthesize myTextfield,somestring;
-(IBAction)next:(id)sender;
{
NextView * next = [[NextView alloc] initWithNewString: myTextField.text];
[self.navigationController presentModalViewController: next animated: YES];
}
NextView.h
#interface NextView : UIViewController{
UILabel *string2;
}
#property(nonatomic,retain)IBOutlet UILabel *string2;
- (id)initWithNewString:(NSString*)someString;
//.m file
#synthesize string2;
-(id)initWithNewString:(NSString*)someString {
string2 = someString;
return self;
}
Just replace method.it may run.
-(IBAction)next:(id)sender; {
NextView * next = [[NextView alloc] initWithNibName:#"NextView" bundle:nil];
next.string2=myTextField.text;
[self.navigationController presentModalViewController:next animated: YES];
}
hey string2 is a label so try string2.text = somestring;
-(id)initWithNewString:(NSString*)someString {
string2.text = someString;
return self;
}
It looks like the problem is that you're assigning an NSString (someString) to a UILabel (string2).
AppleVijay's answer should do the trick.
If you don't like dot-notation in ObjC you can also write it like this:
[string2 setText:someString]
U can declare ur somestring in to the delagate h/m file that way it wil be the global string. u can use it with appdaligateobj.stringname.
U dont evn need init u can directly add to viewdidload of next view.
string2.text = AppDalegateobj.stringName.
Delegation is the usual way to move data around like this. I wrote a very simple example project to show this in action.
You need init you view and retain you string:
-(id)initWithNewString:(NSString*)someString {
self = [super init];
if (self) {
string2.text = someString;
}
return self;
}
/
/AppDelegate.h
NSString *String1;
#property (nonatomic, retain) NSString * String1;
//AppDelegate.m
#synthesize String1
//ViewController1.h
AppDelegate * objAppDelegate;
UILable *lblstring;
#property (nonatomic, retain) UILable *lblstring;
//ViewController1.m
#synthesize lblstring
//On View Did Load.
objAppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
lblstring.text = objAppDelegate.String1;