Access variables from another class - objective-c

I'm a beginner at Objective-C programming and I need to access data stored in a NSMutableArray from another class for populating a TableView, however I only get null.
The variables I need to access are in the class below:
FunctionsController.h
#import <UIKit/UIKit.h>
#interface FunctionsController : UIView {
#public NSMutableArray *placesNames;
NSMutableArray *placesAdresses;
NSMutableArray *placesReferences;
NSMutableArray *placesLatitudes;
NSMutableArray *placesLongitudes;
NSArray *list;
}
#end
In this other class I'm trying to access the data but I only get null as result.
SimpleSplitController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
FunctionsController *arrays = [[FunctionsController alloc] init];
NSMutableArray *names = [arrays->placesNames];
// Set up the cell...
cell.textLabel.text = [names objectAtIndex:indexPath.row];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.font = [UIFont systemFontOfSize:12];
cell.textLabel.minimumFontSize = 10;
cell.textLabel.numberOfLines = 4;
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
return cell;
}

The problem is here:
FunctionsController *arrays = [[FunctionsController alloc] init];
NSMutableArray *names = [arrays->placesNames];
First you are allocating the FunctionsController again. That gives you a clean new instance with no data in its variables. If that 'init' is not putting that in those variables you aren't gonna get anything from them.
A second problem I see is that you are accessing the variable directly. I would use properties instead. You declare a property by doing this in your FunctionsController.h:
#property (nonatomic, retain) NSMutableArray *placesNames;
And adding this to your FunctionsController.m:
#synthesize placesNames;
And then you access the property by doing this:
NSMutableArray *names = arrays.placesNames;
Finally I would recommend you to use Core Data for storing that data instead because it seems that it should belong to a SQL database. More about Core Data here: http://developer.apple.com/library/ios/#DOCUMENTATION/DataManagement/Conceptual/iPhoneCoreData01/Introduction/Introduction.html

Here's your problem:
FunctionsController *arrays = [[FunctionsController alloc] init];
NSMutableArray *names = [arrays->placesNames];
Unless you're setting up placesNames in the init method of FunctionsController then it will either be empty or nil.
Take a look at singletons on objective-c.

Related

Create an array of custom Object to fill it and take his content to fill a UITableView

I have a Class called Product that contains some propeties, I wanna make that my class will be the base for an list of Product called Products. And this list can access in a UITableView to fill it with the content of Products.
Also, the content of each product will be filled by a web service.
My code is:
#interface Product : NSObject
{
int identifier;
NSString* title;
NSString* quantity;
float price;
UIImage* image;
}
#property (nonatomic, assign) int identifier;
#property (nonatomic, retain) NSString* title;
#property (nonatomic, retain) NSString* quantity;
#property (nonatomic, assign) float price;
#property (nonatomic, retain) UIImage *image;
-(id)initWithProduct:(int) identifier withTitle:(NSString*)title numberUses:(NSString*)uses withPrice:(float)price withImage:(UIImage*)image;
#end
With his .m
#implementation Product
#synthesize identifier = _identifier;
#synthesize title = _title;
#synthesize price = _price;
#synthesize quantity = _quantity;
#synthesize image = _image;
- (void)dealloc {
NSLog(#"article dealloc \n");
[self.title release];
[self.quantity release];
[self.image release];
[super dealloc];
}
- (id)init {
self = [super init];
if(self) {
self.title = [[[NSMutableString alloc] init] autorelease];
self.identifier = 0;
self.price = 45.0;
self.quantity = [[[NSMutableString alloc] init] autorelease];
self.image = [[[UIImage alloc] init] autorelease];
}
return self;
}
-(id)initWithProduct:(int) inIdentifier withTitle:(NSString*)inTitle numberUses:(NSString*)inQuantity withPrice:(float)inPrice withImage:(UIImage*)inImage
{
self = [super init];
if (self) {
if (title!= nil) {
self.title = inTitle;
}
if (quantity!= nil) {
self.quantity = inTitle;
}
if (image!= nil) {
self.title = inTitle;
}
self.price = inPrice;
self.identifier = inIdentifier;
}
return self;
}
#end
My UITableView header is:
#interface TableView : UIViewController
< UITableViewDataSource
, UITableViewDelegate
>{
NSMutableArray *products;
}
in the m. I have:
EDIT
Now the Title of my cell is shows as (null)
- (void)viewDidLoad
{
[super viewDidLoad];
products = [[NSMutableArray alloc] init];
[products addObject:[[Product alloc] initWithProduct:1 withTitle:#"df" numberUses:#"dsf" withPrice:12.3 withImage:[UIImage imageNamed:#"btn_invite"]]];
[products addObject:[[Product alloc] initWithProduct:1 withTitle:#"2" numberUses:#"dsf" withPrice:12.3 withImage:[UIImage imageNamed:#"btn_invite"]]];
[products addObject:[[Product alloc] initWithProduct:1 withTitle:#"4" numberUses:#"dsf" withPrice:12.3 withImage:[UIImage imageNamed:#"btn_invite"]]];
[products addObject:[[Product alloc] initWithProduct:1 withTitle:#"4" numberUses:#"dsf" withPrice:12.3 withImage:[UIImage imageNamed:#"btn_invite"]]];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Controller *cell = (Controller*)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSString* nameNib = UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM() ? #"Controller" : #"ControllerIph";
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:nameNib owner:self options:nil];
cell = [nib objectAtIndex:0];
}
Product* obj = [products objectAtIndex:indexPath.row];
cell.title.text = [NSString stringWithFormat:#"%#", obj.title];
return cell;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 4;
}
Thanks in advance!
Not an answer to your question, but a few comments regarding your code:
You have 4 memory leaks when you add the 4 new instances of Product to your array. The array retains the objects you add to it, so you should autorelease the Product instances when you add them.
In dealloc you should say self.title = nil instead of [self.title release]. Although your version works, it leaves you with instance variables that contain references to deallocated objects (= dangling pointers). Because this happens in dealloc and the Product object is going away soon, it won't hurt you now, but you will get bitten at some point in the future if you keep to this style.
You don't need to declare the instance variables, and you don't need to synthesize the properties. The compiler does all this for you.
In initWithProduct you must not check things like if (title!= nil) - just say self.title = inTitle straightaway. After all, initWithProduct is an initializer just like init, so title cannot contain anything at this point.
Hope this helps.
EDIT
Actually, the last point is probably why you see "(null)" for the title of your cells. Your check if (title!= nil) is never true because the instance variable title is nil during the initializer, so the assignment self.title = inTitle never happens.
In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath you do not initialize cells for your TableView. Add the below code to this method before the code that you already have
static NSString *CellIdentifier = #"Cell Identifier";
UITableViewCell *cell;
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
and make sure you return cell; at the end of that method
Also make sure you implement the rest of the necessary TableView delegate methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

Displaying data retrieved from Parse in UITableView

After all progress i made with your answers, my issue changed. So i am changing my question with clearer way. I have an UITableView which is showing my retrieved data from Parse.com. So i made a NSMutableArray for adding objects to that array when they are retrieved. But my problem is even i add objects to NSMutableArray, my table does not show anything but default screen of UITableView. I thing the issue is UITableView is formed before my NSMutableArray got its objects. Here is my code:
Note: The PropertyClass is the class which has the properties of my objects.
At MyTableViewController.h
#interface MyTableViewController : UITableViewController <CLLocationManagerDelegate> {
PFObject *object;
}
#property (strong, nonatomic) IBOutlet UITableView *MyTableView;
#end
At UITableViewController.m
#interface MyTableViewController ()
#property(strong)NSMutableArray *myNSMutableArray;
#end
#implementation MyTableViewController
#synthesize myNSMutableArray,MyTableView;
-(void) retrievingDataFromParse{
PFQuery *query = [PFQuery queryWithClassName:#"MyObjectsClass"];
[query whereKey:#"ObjectsNumber" lessThanOrEqualTo:10];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
if (objects.count==0) {
NSString *objectError = #"There no object retrieved from Parse";
PropertiesClass *PC = [[PropertiesClass alloc]initWithPropert1:objectError Propert2:nil Propert3:nil Propert4:nil];
[myNSMutableArray addObject:PC];
}
for (int i = 0; i < objects.count; i++) {
object = [objects objectAtIndex:i];
NSString *Propert1 = [object objectForKey:#"Propert1"];
NSNumber *Propert2 = [object objectForKey:#"Propert2"];
NSNumber *Propert3 = [object objectForKey:#"Propert3"];
NSString *Propert4 = [object objectForKey:#"Propert4"];
PropertiesClass *PC = [[PropertiesClass alloc]initWithPropert1:Propert1 Propert2:Propert2 Propert3:Propert3 Propert4:Propert4];
[myNSMutableArray addObject:PC];
};
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.myNSMutableArray = [NSMutableArray array];
[self retrievingDataFromParse];
[MyTableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [myNSMutableArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PropertiesClass *PC= [myNSMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text=PC.Propert1;
return cell;
}
Looking at your code i see that you never create a UITableViewCell, you should change this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PropertyClass *PC = [myMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = PC.x;
return cell;
}
with this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (nil == cell){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
PropertyClass *PC = [myMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = PC.x;
return cell;
}
the method dequeueReusableCellWithIdentifier:forIndexPath: return a UITableViewCell only if there are unused, but already allocated, cells in your table view. otherwise it returns nil.
Also when you update the mutable array containing all your data you should call [yourTableView reloadData] to force the table view to reload its content.
Your code is quite cryptic. Few suggestions here.
First, rename variables and methods with camelCaseNotation (camel case notation). For example, MyMutableArray should be myMutableArray. RetrievingDataFromParse should be retrievingDataFromParse (and so on). Start upper case letter are for classes.
Second, what does this code mean (I put comment on your code)?
for (int i = 0; i < objects.count; i++) {
// where do you have defined object?
object = [objects objectAtIndex:i];
NSString *x = [object objectForKey:#"x"];
NSNumber *y = [object objectForKey:#"y"];
NSNumber *z = [object objectForKey:#"z"];
NSString *t = [object objectForKey:#"t"];
// is Mekan a subclass of PropertiyClass or what else?
PropertiyClass *Properties = [[Mekan alloc]initWithx:x y:y z:z t:t]
// what's MekanKalibi? Maybe you need to add Properties
[MyMutableArray addObject:MekanKalibi];
}
Edit
If you don't use iOS6 - (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier you should alloc-init cells.
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(!cell) {
// alloc-init a new cell here...
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// or if you don't use ARC
// cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
PropertyClass *PC = [myMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = PC.x;
return cell;
Edit 2
I don't know how parse works but I suppose it manages async requests. So, at the end of your for loop, just call reload data in the table.
Parse states:
The InBackground methods are asynchronous, so any code after this will run immediately. Any code that depends on the query result should be moved inside the completion block above.
I had the same problem. When you reload the table, you need to move it so it is inside the block. Worked for me.
I'm not 100% sure how the asynchronous parts affect it so. I know that the start of my viewDidload and the end occured then this block, hence the problem.
People should probably up this as this solves the issue.
Cheers.
All you have to do is reload tableView in the block... this will show data.
for (int i = 0; i < objects.count; i++) {
object = [objects objectAtIndex:i];
NSString *Propert1 = [object objectForKey:#"Propert1"];
NSNumber *Propert2 = [object objectForKey:#"Propert2"];
NSNumber *Propert3 = [object objectForKey:#"Propert3"];
NSString *Propert4 = [object objectForKey:#"Propert4"];
PropertiesClass *PC = [[PropertiesClass alloc]initWithPropert1:Propert1 Propert2:Propert2 Propert3:Propert3 Propert4:Propert4];
[myNSMutableArray addObject:PC];
};
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
**[MyTableView reloadData];**
}];

Annotations and Table Views

I am trying populate my table view using my array of annotations but XCode seems to give me a breakpoint any time I add this code.
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSMutableArray *annotations = [[NSMutableArray alloc] init];
if(indexPath.section == 0)
{
for(Location *annotation in [(MKMapView *)self annotations])
{
if(![annotation isKindOfClass:[MKUserLocation class]])
{
}
}
cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];
}
return cell;
My annotations:
CLLocationCoordinate2D thecoordinate59;
thecoordinate59.latitude = 51.520504;
thecoordinate59.longitude = -0.106725;
Location *ann1 = [[Location alloc] init];
ann1.title =#"Antwerp";
ann1.coordinate = thecoordinate1;
NSMutableArray *annotations = [NSMutableArray arraywithObjects: ann.. ann59, nil];
[map addAnnotations:annotations];
In cellForRowAtIndexPath, you are declaring a new, local variable named annotations which has nothing to do with the annotations array you are creating in viewDidLoad (I assume that's where you're adding the annotations).
Then in cellForRowAtIndexPath, this line:
for(Location *annotation in [(MKMapView *)self annotations])
fails because there is no annotations property in self. In viewDidLoad, you declared a local variable named annotations but it is not visible or accessible outside that method.
The other issue with the above line is that you're casting self as an MKMapView *. Most likely self is a UIViewController. It contains a map view but is not itself one.
You need to first declare your annotations array at the detail view's class level so it's available across all methods. In the detail view .h file:
#property (nonatomic, retain) NSMutableArray *annotations;
By the way, I'd name it something different so it's not confused with the map view's own annotations property.
In the .m, synthesize it:
#synthesize annotations;
In viewDidLoad, create it like this:
self.annotations = [NSMutableArray arraywithObjects...
[map addAnnotations:self.annotations];
In the numberOfRowsInSection method, return the array's count:
return self.annotations.count;
Then in cellForRowAtIndexPath:
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if(indexPath.section == 0)
{
cell.textLabel.text = [[self.annotations objectAtIndex:indexPath.row] title];
}
return cell;
You are reporting a crash (i assume) on that line
the problem that I see is crash reason would be
cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];
annotations array is just initialized locally few statements above which does not hold any values..??

UITableView crashes when scroll down

I know there's a lot of questions about this topic but I have not be able to solve my problem...
Well, I have detected the problem, it's the contactsArray that's global. If I comment that lines, the table works fine.
The code is this:
#interface ContactsView : UIViewController <UITableViewDelegate, UITableViewDataSource>{
IBOutlet UITableView *table;
NSMutableArray * contactsArray;
}
#property (nonatomic, retain) NSMutableArray *contactsArray;
#property (nonatomic, retain) IBOutlet UITableView *table;
In viewDidLoad I do:
contactsArray = [[NSMutableArray alloc] init];
And here the implementation of each cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ContactsCell";
ContactsCell *cell = (ContactsCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"ContactsCell" owner:self options:nil];
for(id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (ContactsCell *) currentObject;
break;
}
}
}
// Configure the cell...
Person *persona = [[Person alloc] init];
persona=[contactsArray objectAtIndex:indexPath.row];
[cell setCellNames:[persona name]];
[cell setCellStates:#"En Donosti"];
[persona release];
return cell;
}
If I comment the persona=[contactsArray objectAtIndex:indexPath.row]; and [cell setCellNames:[persona name]];
So, I'm pretty sure that the problem is with contactsArray
Any idea why is it crashing?
Thanks!
You must not release persona object as you just get it from array. Also the Person *persona = [[Person alloc] init]; has no effect as you immediately overwrite object you create with object from array. Fixed code should look like:
Person *persona = [contactsArray objectAtIndex:indexPath.row];
[cell setCellNames:[persona name]];
[cell setCellStates:#"En Donosti"];
return cell;

Loading data in NSUserDefaults

i have done the coding to save the highscore in NSuserdefaults, but i am not sure how can i load the data from the nsuserdefaults and display it in a table. PLease help.
NSString *name;
name = nametextbox.text;
NSDictionary *player = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithFormat:#"%#", name], #"name",[NSString stringWithFormat:#"%d", myScore], #"score",nil];
[highScore addObject:player];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"score" ascending:NO];
[highScore sortUsingDescriptors:[NSArray arrayWithObject:sort]];
[sort release];
[[NSUserDefaults standardUserDefaults] setObject:highScore forKey:#"highScore"];
You should be able to load it just the way you'd expect (like accessing a value in an NSDictionary):
NSArray *highScore = [[NSUserDefaults standardUserDefaults] objectForKey:#"highScore"];
Update
To display the data from this array in a table view, you'll need to create a view controller and use the array as your data source. The easiest way to do this is by subclassing UITableViewController. This should get you started on the implementation of that controller:
// HighScoreViewController.h
#interface HighScoreViewController : UITableViewController {
NSArray *highScores;
}
#property (nonatomic, retain) NSArray *highScores;
#end
.
// HighScoreViewController.m
#import HighScoreViewController.h
static const NSInteger kNameLabelTag = 1337;
static const NSInteger kScoreLabelTag = 5555;
#implementation HighScoreViewController
#synthesize highScores;
- (void)viewDidLoad {
[self setHighScores:[[NSUserDefaults standardUserDefaults]
objectForKey:#"highScore"]];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [self.highScores count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"PlayerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cel == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier] autorelease];
// Create UILabels for name and score and add them to your cell
UILabel *nameLabel = [[UILabel new] autorelease];
[nameLabel setTag:kNameLabelTag];
[cell.contentView addSubview:nameLabel];
UILabel *scoreLabel = [[UILabel new] autorelease];
[scoreLabel setTag:kScoreLabelTag];
[cell.contentView addSubview:scoreLabel];
// Set other attributes common to all of your cells here
// You will also need to set the frames of these labels (nameLabel.frame = CGRectMake(...))
}
NSDictionary *player = [self.highScores objectAtIndex:indexPath.row];
NSString *name = [player objectForKey:#"name"];
NSString *score = [player objectForKey:#"score"];
[(UILabel *)[cell.contentView viewWithTag:kNameLabelTag] setText:name];
[(UILabel *)[cell.contentView viewWithTag:kScoreLabelTag] setText:score];
return cell;
}
#end
A key thing to remember with UITableView is that cells get reused, so you need to be careful about where you initialize/configure your cell's subviews.