How to access NSArray in another View - objective-c

I have some problems with my XML parser, written in obj-c.
The parser itself is fine but I cant access the result Array in the DetailView.
I need the values of the array created by the Parser Class in my Master and DetailViewController.
In MasterViewController I do this:
MasterViewController.h
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "TouchXML.h"
#import "Parser.h"
#class Parser;
#interface MasterViewController : UITableViewController{
Parser *theParser;
}
MasterViewController.m
- (void)viewDidLoad
{
theParser = [[Parser alloc] init];
[theParser startParser:xmlPath]; //Now the parser runs and parses all needed values into arrays
}
Then I push on click the DetailView and I want to access the values there too.
UniViewController.h
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Parser.h"
#interface UniViewController : UITableViewController{
Parser *theParser;
}
UniViewController.m
- (void)viewDidLoad
{
NSLog(#"Name: %#",[[theParser.listArray objectAtIndex: 0]valueForKey:#"name"]);
}
Here I want to access the the Array from the parser but I always get the value (null) ?
In the debugger I saw that theParser has 0x0000 which cant be right...
After I do theParser = [[Parser alloc] init]; here, it has an hex value but I still get the (null).
How can I access the Array values from the DetailView?
Would be really nice if someone could explain me the problem here.
Thanks.

Your detail view has to have a pointer to the array that your MasterView creates (via the parser), try this:
(void)viewDidLoad
{
aParser = [[Parser alloc] init];
[aParser startParser:xmlPath];
myUniView.theParser = aParser; //myUniView is just the detail view you're pushing
and then after this you can push your detail view.

Related

passing data between tabs in iOS

it is my first app that I am trying to do on my own and I have some questions. I want to have 4 tabs, and in the first one named "HomeView" I am parsing JSON data (this is done so far).
But what I want is some of the data that are being parsed to be visible in other tabs (and not have to parse them again).
So parts of my code of HomeView is here:
#import "HomeView.h"
#interface HomeView ()
#end
#implementation HomeView
//other code
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//data fetched
parsed_date=[res objectForKey:#"date"];
NSLog(#"Date:%#",parsed_date);
[UIAppDelegate.myArray addObject:parsed_date];
}
and I can see the "parsed_date" being printed out correctly.
So I want this parsed_date to be visible in OtherView.
This is my code but I cannot print it out.
OtherView.m
#import "OtherView.h"
#import "HomeView.h"
#import "AppDelegate.h"
#interface OtherView ()
#end
#implementation OtherView
#synthesize tracks_date;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//preview value of other class
tracks_date = [UIAppDelegate.myArray objectAtIndex:0];
NSLog(#"Dated previed in OtherView: %#", tracks_date);
}
and (null) is being printed out.
added code of app delegate.h
#import <UIKit/UIKit.h>
#define UIAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) NSArray *myArray;
#end
So can you suggest me a sollution?
Add the property to your Application Delegate instead.
When assigning the property do something like:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
delegate.myProperty = #"My Value";
then, in your different tabs, you can retrieve this property in the same manner:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *valueInTab = delegate.myProperty;
Uh, when you create a HomeView in your last code segment there, you're creating a new object -- a new instance of the class. It will not contain the data from connectionDidFinishLoading unless that method is executed in that instance of the class.
You basically need to use some sort of persistence mechanism to do what you want, either the AppDelegate or static storage along the lines of a "singleton".
While this may not be the best method of doing this, it is easy and effective.
Save your data in your app delegate and retrieve it from there. You can create a shortcut to your app delegate shared application. Then just access the values there.
AppDelegate.h
#define UIAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
#property (nonatomic, strong) NSArray *myArray;
TabView1.m
#import "AppDelegate.h"
SomeObject *myObject = [UIAppDelegate.myArray objectAtIndex:0];
Like I said, it might not be the best way to organize your data for your application, this method does work for small amounts of data needing to be shared at the application level. Hope this helps.
this happens because you create an instance of HomeView yourself.
it has simply no connections to anything.
your first example works because it is the created and initialized from your nib.
i think the best way is to use an IBOutlet and then connect both 'Views' in InterfaceBuilder.
#interface OtherView ()
IBOutlet HomeView *homeView;
#end
#implementation OtherView
#synthesize tracks_date;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Dated previed in OtherView: %#", homeView.parsed_date);
}
- (void)dealloc:
{
[homeView release];
}
have a look here, it will demonstrate it much more
In InterfaceBuilder you can manage your Objects and connect them (via IBOutlets and IBAction, ...) together.
I think this video is a good demonstration how this concept work.

No access to global instance (build by factory) on iOS

this is a follow-up question to my last one here: iOS: Initialise object at start of application for all controllers to use .
I have set my application up as follows (ignore the DB Prefix):
DBFactoryClass // Built a DataManaging Object for later use in the app
DBDataModel // Is created by the factory, holds all data & access methods
DBViewControllerA // Will show some of the data that DBDataModel holds
moreViewControllers that will need access to the same DBDataModel Object
i will go step by step through the application, and then post the problem in the end
AppDelegate.h
#import "DBFactoryClass.h"
AppDelegate.m
- (BOOL)...didFinishLaunching...
{
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
return YES;
}
DBFactoryClass.h
#import <Foundation/Foundation.h>
#import "DBDataModel.h"
#interface DBFactoryClass : NSObject
#property (strong) DBDataModel *DATAMODEL;
#end
DBFactoryClass.m
#import "DBFactoryClass.h"
#implementation DBFactoryClass
#synthesize DATAMODEL;
-(id)init{
self = [super init];
[self setDATAMODEL:[[DBDataModel alloc]init ]];
return self;
}
#end
ViewControllerA.h
#import <UIKit/UIKit.h>
#import "DBDataModel.h"
#class DBDataModel;
#interface todayViewController : UIViewController
#property (strong)DBDataModel *DATAMODEL;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
ViewControllerA.m
#import "todayViewController.h"
#implementation todayViewController
#synthesize testLabel;
#synthesize DATAMODEL;
- (void)viewDidLoad
{
todaySpentLabel.text = [[DATAMODEL test]stringValue]; // read testdata
}
#end
DBDataModel.h
#import <Foundation/Foundation.h>
#interface DBDataModel : NSObject
#property (nonatomic, retain) NSNumber* test;
#end
DBDataModel.m
#import "DBDataModel.h"
#implementation DBDataModel
#synthesize test;
-(id)init{
test = [[NSNumber alloc]initWithInt:4]; // only a testvalue
return self;
}
#end
the app builds fine, and starts up but the label stays blank. so either the object does not exist (but i guess this would result in an error message), or something else is wrong with my setup. any thoughts?
Two notes:
Your have a shotgun approach to asking questions: everytime you hit a stumbling block, you ask a question and if the answer does not work immediately, you ask another one. You have to spend some energy in between the questions debugging and poking into the code on your own, otherwise you will depend on the external help forever.
Use the common coding style please. CAPS are reserved for macros.
Now to the code:
- (BOOL) …didFinishLaunching…
{
DBFactoryClass *factory = [[DBFactoryClass alloc] init];
return YES;
}
This simply creates an instance of the DBFactoryClass and then throws it away. In other words, it’s essentially a no-op. Judging by the comments in the previous answer you create the controllers using the Storyboard feature. How are they supposed to receive the reference to the data model? The reference isn’t going to show up by magic, you have to assign it somewhere.
I’m not familiar with the Storyboard feature. The way I would do it is to create the view controllers using separate XIB files, then you can create the controller instances in the Factory class and pass them the needed reference to the model. In the end the application delegate would create the factory, ask it to assemble the main controller and then set it as the root view controller for the window. Just like in my sample project. It’s possible that there’s a way to make it work with storyboards, but as I said, I am not familiar with them.

Getting an error while trying to access property from an extern Controller in Xcode 4.2

In a first controller, I create an instance variable for my model, because I want to edit its content from a controller and then access the same object from another controller.
In the second controller, I get an error when trying to access the object:
Property 'levels' not found on object of type FirstController.
Model.h
#imports....
#property (readwrite,copy) NSMutableString *answersString;
FirstController.h
#import <UIKit/UIKit.h>
#import "Model.h"
#interface FirstController : UIViewController{
// some declarations
}
#property (nonatomic, retain) LevelsCompleted *levels;
#end
FirstController.m
#import "FirstController.h"
#interface FirstController(){
//stuff
}
#end
#implementation FirstController
#synthesize levels;
//stuff
- (IBAction)backButton:(id)sender { // This is the changeAnswerString method
if (levels ==nil) self.levels = [[LevelsCompleted alloc]init];
self.levels.answersString=#"1";
[self dismissModalViewControllerAnimated:NO];
}
#end
SecondController.m
#import "SecondController.h"
#import "FirstController.h"
#interface SecondController(){
//stuff
}
#end
#implementation SecondController
-(void) viewWillAppear:(BOOL)animated{
NSLog(#"%#",FirstController.levels.answersString);
// the line above gives me the error "Property 'levels' not found on object of type FirstController
}
#end
Can someone tell me what I am doing wrong here? I have tried to create a FirstController object in the SecondController.h, but this does not give me the same property and hence I do not get the right value of the NSString I modified in the first view.
levels is a instance variable so you cannot access it without instantiating an object first.
You should do something like
FirstController *controller = [[FirstController alloc] initWithNibName:#"First" bundle:nil];
NSLog(#"%#",controller.levels.answersString);
[controller release]
You cannot access another viewcontroller from current viewcontroller directly. Define Level in AppDelagte method and then you can access it from anywhere.
What about moving/adding the LevelsCompleted *levels property to the secondviewcontroller and fill SecondViewcontroller.levels.answerstring when you use backbutton: in you first controller?
As a advice try NSUSERDEFAULT to access it,.,
By Doing Things As Below you can Achive as You want
Ddeclare NSMutableString As in your viewController Class As Global variable.
1) LevelsCompleted.h Class
#import <UIKit/UIKit.h>
NSMutableString *answersString;// In this way this answersString would accessible through out the Application and No Need to make property & synthesiz answersString .
#interface LevelsCompleted : UIViewController{
}
LevelsCompleted.m Class
//First create that NSMutableString object in its LevelsCompleted.m class
#import"LevelsCompleted.h"
#interface LevelsCompleted
-(void)viewDidLoad{
answersString=[NSMutableString alloc]init];//here created answersString object
}
#end //end of LevelsCompleted
2)FirstController.h class
#import <UIKit/UIKit.h>
extern NSMutableString *answersString;
#interface FirstController : UIViewController{
// some declarations
}
#end
FirstController.m class
#import "FirstController.h"
#implementation FirstController
- (IBAction)backButton:(id)sender {
// Because i have created that answersString Global in LevelsCompleted.h class
//we can directly Access and can set the any string Value to that answersString as Below
answersString=#"1";
[self dismissModalViewControllerAnimated:NO];
}
#end
SecondController.h class
extern NSMutableString *answersString;// please do this carefully fro getting access the answersString instance
#interface SecondController:UIViewController{
//stuff
}
#end
SecondController.m class
#implementation SecondController
-(void) viewWillAppear:(BOOL)animated{
NSLog(#"%#",answersString);//here you may access easily.
}
#end
In above code everything would work because i have done the same thing in my app
just try to catch the concept of extern, global variable .

Singleton data out of scope problem

I am trying to pass data between the viewcontrollers of a uitabbarcontroller using a singleton class as below:
#import <Foundation/Foundation.h>
#interface AppSingleton : NSObject {
NSMutableString *selectedStr;
}
#property(nonatomic,retain) NSMutableString *selectedStr;
+(AppSingleton*) sharedAppInstance;
#end
Here is my implementation file:
#import "AppSingleton.h"
#implementation AppSingleton
#synthesize selectedStr;
+(AppSingleton*) sharedAppInstance{
static AppSingleton *sharedAppInstance;
#synchronized(self){
if(!sharedAppInstance){
sharedAppInstance = [[AppSingleton alloc] init];
}
}
return sharedAppInstance;
}
-(void)dealloc{
[selectedStr release];
[super dealloc];
}
#end
I try to set the selectedStr in one of my viewcontrollers as below and print it in the NSLog however I get a null:
AppSingleton *sharedAppInstance;//in the header
sharedAppInstance = [AppSingleton sharedAppInstance];//in viewdidload
[sharedAppInstance setSelectedStr:self.someStr];
NSLog(#"selectedStr is: %#", sharedAppInstance.selectedStr);
When I debug this, the sharedAppInstance.selectedStr seems to be out of scope.
I would like to know where I am making a mistake.
Thank you.
I changed the placing of the setting/getting of my variable within the viewcontroller and it worked..
[sharedAppInstance setSelectedStr:self.someStr];
NSLog(#"selectedStr is: %#", sharedAppInstance.selectedStr);

Memory leak for object in array

I've started cleaning up my app before publication - using "Instruments" Leak analyzer.
I found a leak I can't plug. So I built a simple project to illustrate the problem. Please see code below. I put a button on the view to test fire the procedure "test". It always generates a leak.
First the header and code for an object named "theObj"
#import <Foundation/Foundation.h>
#interface theObj : NSObject {
NSString* theWord;
}
#property (nonatomic,retain) NSString* theWord;
#end
#import "theObj.h"
#implementation theObj
#synthesize theWord;
-(id) initWithObjects: (NSString *) aWord;
{
if (self = [super init]){
self.theWord = aWord;
}
return self;
}
-(void) dealloc{
[theWord release];
[super dealloc];
}
#end
Now the view controller
#import <UIKit/UIKit.h>
#import "theObj.h"
#interface LeakAnObjectViewController : UIViewController {
NSMutableArray* arrObjects;
}
- (IBAction)test;
#end
#import "LeakAnObjectViewController.h"
#implementation LeakAnObjectViewController
- (IBAction)test {
if (arrObjects == nil)
arrObjects = [[NSMutableArray alloc] init];
NSString* aStr = #"first";
[arrObjects addObject:[[theObj alloc] initWithObjects:aStr]];
[arrObjects removeAllObjects];
}
You alloc the object, which means you own it. Then you give it to the array, which means the array owns it as well. Then the array removes it, so you are the only owner. But you don't have a reference to the object anymore, so you can't release it, so it's just leaked.
Someone really needs to learn the rules around memory management. Specifically as it pertains to ownership, etc.