Undeclared identifier Objective C - iphone

I can't seem to get round this error; use of undeclared identifier 'ageBy'.
I dont understand why am getting it as i have the import Person.h in my code.
Thanks for your time and any help.
Person.h
#interface Person : NSObject
{
int _age;
int _years;
NSString *_name;
NSString *_job;
}
-(void)setAge:(int)age;
-(int)age;
-(void)setName:(NSString *)name;
-(NSString *)name;
-(void)setJob:(NSString *)job;
-(NSString *)job;
-(NSString *)summaryString;
-(void)ageBy:(int)years;
#end
Person.m
#import "Person.h"
#implementation Person
-(void)setAge:(int)age{
_age = age;
}
-(int)age{
return _age;
}
-(void)setName:(NSString *)name{
_name = name;
}
-(NSString *)name{
return _name; }
-(void)setJob:(NSString *)job{
_job = job;
}
-(NSString *)job{
return _job;
}
-(NSString *)summaryString{
return [NSString stringWithFormat:#"The Person %# is %d years old and is a %#",_name,_age,_job];
-(void)ageBy:(int)years{
_years = years;
_age = years + _age;
}
}
#end

Your ageBy: is defined inside summaryString. You probably want to move the curly bracket just before #end so that it is above -(void)ageBy:(int)years. So:
-(NSString *)summaryString{
return [NSString stringWithFormat:#"The Person %# is %d years old and is a %#",_name,_age,_job];
}
-(void)ageBy:(int)years{
_years = years;
_age = years + _age;
}
Also as a style note, if summaryString is merely for debugging then you'd possibly be better off declaring it as description. The latter is the standard form for getting an implementation-dependand string description of an Objective-C object, with the net effect that collection objects like NSArray know to call description on all their child objects in order to create the correct output.

As was stated, the problem is caused by the ageBy: method being embedded in the summaryString method.
I wanted to demonstrate how this class could be written using modern Objective-C:
// Person.h
#interface Person : NSObject
#property (nonatomic, assign) int age;
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *job;
- (void)ageBy:(int)years;
#end
// Person.m
#implementation Person
- (NSString *)description {
return [NSString stringWithFormat:#"The Person %# is %d years old and is a %#", self.name, self.age, self.job];
}
- (void)ageBy:(int)years {
self.age = self.age + years;
}
#end

Related

Archiving and retrieving array from a class in Objective-c [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Hi i am trying to save data in a file with the help of a class that is saved to disk. It is saving the data but not retrieving correct data. Plz help me
Here is my ViewController.h
#interface MIGViewController : UIViewController
- (IBAction)hideKeyboard:(id)sender;
#property (strong, nonatomic) NSMutableArray * myArray;
#property (strong, nonatomic) NSString * pathToFile;
#property (weak, nonatomic) IBOutlet UITextField *nameField;
#property (weak, nonatomic) IBOutlet UITextField *idField;
#property (weak, nonatomic) IBOutlet UITextField *addressField;
#property (weak, nonatomic) IBOutlet UITextField *phoneField;
- (IBAction)addButtonTapped:(id)sender;
- (IBAction)saveButtonTapped:(id)sender;
#end
Here is view Controller.m
#import "MIGViewController.h"
#import "MIGStudent.h"
#interface MIGViewController ()
#end
#implementation MIGViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentsPath = [paths objectAtIndex:0];
self.pathToFile = [documentsPath stringByAppendingPathComponent:#"students.sukh"];
NSFileManager * manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:self.pathToFile])
{
//File exists
self.myArray = [NSKeyedUnarchiver unarchiveObjectWithFile:self.pathToFile];
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:#"Students array" message:[self.myArray description]delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil, nil];
[alert show];
}
else
{
//File doesn't exist
self.myArray = [NSMutableArray array];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)addButtonTapped:(id)sender {
NSString * name =self.nameField.text;
NSString * address = self.addressField.text;
int studentID = [self.idField.text intValue];
int phoneNumber = [self.phoneField.text intValue];
MIGStudent * student = [[MIGStudent alloc] initWithName:name address:address studentID:studentID phoneNumber:phoneNumber];
[self.myArray addObject:student];
self.nameField.text = #"";
self.addressField.text = #"";
self.idField.text = #"";
self.phoneField.text = #"";
}
- (IBAction)saveButtonTapped:(id)sender {
[NSKeyedArchiver archiveRootObject:self.myArray toFile:self.pathToFile];
}
- (IBAction)hideKeyboard:(id)sender {
[self resignFirstResponder];
}
#end
Here is my class Student.h
#interface MIGStudent : NSObject <NSCoding>
#property (strong, nonatomic) NSString * name;
#property (strong, nonatomic) NSString * address;
#property (nonatomic) int studentID;
#property (nonatomic) int phoneNumber;
-(id)initWithName:(NSString *) name address:(NSString *)address studentID: (int)studentID phoneNumber:(int) phoneNumber;
#end
And here is Student.m
#import "MIGStudent.h"
#implementation MIGStudent
-(id) initWithName:(NSString *)name address:(NSString *)address studentID:(int)studentID phoneNumber:(int)phoneNumber
{
if (self=[super init])
{
self.name = name;
self.address = address;
self.phoneNumber = phoneNumber;
self.studentID = studentID;
}
return self;
}
-(void) encodeWithCoder:(NSCoder *)aCoder
{
//Used when saving to disk
[aCoder encodeObject:self.name forKey:#"name"];
[aCoder encodeObject:self.address forKey:#"address"];
[aCoder encodeInt:self.phoneNumber forKey:#"phoneNumber"];
[aCoder encodeInt:self.studentID forKey:#"studentID"];
}
-(id) initWithCoder:(NSCoder *)aDecoder
{
//Used when reading from disk
self.name = [aDecoder decodeObjectForKey:#"name"];
self.address = [aDecoder decodeObjectForKey:#"address"];
self.phoneNumber = [aDecoder decodeIntForKey:#"phoneNumber"];
self.studentID = [aDecoder decodeIntForKey:#"studentID"];
return self;
}
#end
And here is what i get output every time
I think everythings is working properly but there is some problem while retrieving the data
Thanks in advance
That's not a problem with your implementation of NSCoding, that's actually not even a problem at all! That's the way an NSArray prints itself literally (the result of the -description method). The fact that it does this indicates that the archiving/de-archiving process went smoothly. The array is the set of parenthesis (), and the objects within are in the format <Class : memory address>. If you had an array of invalid objects, then your array would most likely refuse to print, or crash when the students objects were added to it.
You can take advantage of this in your MIGStudent class and override -description to print a friendlier format. For example:
-(NSString*)description {
return [NSString stringWithFormat:#"<%# : %p Student named: %# - who lives at: %# With the ID number: %d and the phone number: %d>", NSStringFromClass(self.class), self, self.name, self.address, self.studentID, self.phoneNumber];
}
As a sidenote, initializers always call through to super. Your initWithCoder: method will always return nil.
Your initWithCoder: method is incorrect it will fail as currently it will return nil or some garbage value, it should be:
-(id) initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self)
{
//Used when reading from disk
self.name = [aDecoder decodeObjectForKey:#"name"];
self.address = [aDecoder decodeObjectForKey:#"address"];
self.phoneNumber = [aDecoder decodeIntForKey:#"phoneNumber"];
self.studentID = [aDecoder decodeIntForKey:#"studentID"];
}
return self;
}
Secondly you can either override description or debugDescription method of your class to return custom information about that class.

add data to my data member

Hello I'm new to iPhone development.
I try to add move data from NSDictionary to data member of calls that i created.
When i "setWeightMeasure" nothing happened.
any suggestions?
the code that don't work:
NSDictionary *responseBodyProfile = [responseBody objectFromJSONString];
NSLog(#"%#",responseBodyProfile);
// the output is :
"{ "profile": {"goal_weight_kg": "77.0000", "height_cm": "179.00",
"height_measure": "Cm", "last_weight_date_int": "15452",
"last_weight_kg": "99.0000", "weight_measure": "Kg" }}""
[responseBody release];
if (responseBodyProfile != nil ){
NSDictionary *profile =[responseBodyProfile valueForKey:#"profile"];
NSLog(#"%#\n",[profile objectForKey:#"weight_measure"]);// Output : "kg"
[self.myUser setWeightMeasure:[profile objectForKey:#"weight_measure"]];
NSLog(#"%#", [self.myUser WeightMeasure]); // Output : "(null)"
}
the H file properyty:
#property (nonatomic, retain) UserData* myUser;
UserData.h:
#import <Foundation/Foundation.h>
#interface UserData : NSObject{
NSString* Weight;
NSString* Height;
NSString* GolWeight;
NSString* WeightMeasure;
}
#property (nonatomic, retain) NSString* Weight;
#property (nonatomic, retain) NSString* Height;
#property (nonatomic, retain) NSString* GolWeight;
#property (nonatomic, retain) NSString* WeightMeasure;
#end
UserData.m
#import "UserData.h"
#implementation UserData
#synthesize Weight, Height, GolWeight, WeightMeasure;
-(id)init{
self.Weight = #"0";
self.Height = #"0";
self.GolWeight = #"0";
self.WeightMeasure = #"0";
return self;
}
-(void)dealloc{
[Weight release];
[Height release];
[GolWeight release];
[WeightMeasure release];
[super dealloc];
}
#end
Use valueForKey instead of objectForKey in this line:
[self.myUser setWeightMeasure:[profile objectForKey:#"weight_measure"]];
like this:
[self.myUser setWeightMeasure:[profile valueForKey:#"weight_measure"]];
You might also want to use, since the values could be read as NSNumbers
[self.myUser setWeightMeasure:[[profile valueForKey:#"weight_measure"] stringValue]];
And why do you use strings instead of floats? Wouldn't that make your life easier when you'd need to perform some comparisons?
Also check if you have allocated memory for "myUser", that might be the case as well.
As Eugene mentioned, you should use valueForKey instead of objectForKey
The other thing is you might wanna use property and dot notation whenever you reference your object members, as Apple recommend. It is generally good for you to manage memory.
The previous answer about not initialize your string members in your -init() was totally wrong, if that cause some confusion, I do apologize for it.

Loop through all object properties at runtime

I want to create an Objective-C base class that performs an operation on all properties (of varying types) at runtime. Since the names and types of the properties will not always be known, how can I do something like this?
#implementation SomeBaseClass
- (NSString *)checkAllProperties
{
for (property in properties) {
// Perform a check on the property
}
}
EDIT: This would be particularly useful in a custom - (NSString *)description: override.
To expand on mvds' answer (started writing this before I saw his), here's a little sample program that uses the Objective-C runtime API to loop through and print information about each property in a class:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface TestClass : NSObject
#property (nonatomic, retain) NSString *firstName;
#property (nonatomic, retain) NSString *lastName;
#property (nonatomic) NSInteger *age;
#end
#implementation TestClass
#synthesize firstName;
#synthesize lastName;
#synthesize age;
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
unsigned int numberOfProperties = 0;
objc_property_t *propertyArray = class_copyPropertyList([TestClass class], &numberOfProperties);
for (NSUInteger i = 0; i < numberOfProperties; i++)
{
objc_property_t property = propertyArray[i];
NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)];
NSString *attributesString = [[NSString alloc] initWithUTF8String:property_getAttributes(property)];
NSLog(#"Property %# attributes: %#", name, attributesString);
}
free(propertyArray);
}
}
Output:
Property age attributes: T^q,Vage
Property lastName attributes: T#"NSString",&,N,VlastName
Property firstName attributes: T#"NSString",&,N,VfirstName
Note that this program needs to be compiled with ARC turned on.
Use
objc_property_t * class_copyPropertyList(Class cls, unsigned int *outCount)
and read https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html on how to do this exactly.
Some code to get you going:
#import <objc/runtime.h>
unsigned int count=0;
objc_property_t *props = class_copyPropertyList([self class],&count);
for ( int i=0;i<count;i++ )
{
const char *name = property_getName(props[i]);
NSLog(#"property %d: %s",i,name);
}
Adding some detial to #mvds:
unsigned int count=0;
objc_property_t *props = class_copyPropertyList([self class],&count);
for ( int i=0;i<count;i++ )
{
const char *name = property_getName(props[i]);
NSString* dataToGet = [NSString swf:#"%s",name];
#try { // in case of this pair not key value coding-compliant
id value = [barButton valueForKey:dataToGet];
NSLog(#"prop %d: %s %#",i,name, value);
} #catch (NSException *exception) {
// NSLog(#"Exception:%#",exception);
}
#finally {
// Display Alternative
}
}
Please give #mvds the upvote.

Variables emptying or erasing on didSelectRowAtIndexPath

For some reason, I can't access any of my variables after the first IF Statement in the following code. For instance, if index path is [0,0], then the variable phoneText spits out a phone number. But if its [1,0] or [2,0], I get a "null" return. Why is my variable being erased?
The following function in mapviewcontroller.m sets the values. I do actually have an error here that says "instance method setDetails not found".
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
//this determines what kind of item was selected
if ([control isKindOfClass:[UIButton class]]) {
NSLog(#"Trying to load VenueIdentifier...");
FinderAnnotation *clicked = view.annotation;
FinderViewController *fvi = [self.storyboard instantiateViewControllerWithIdentifier:#"FinderDetail"];
NSString* latitude = [NSString stringWithFormat:#"%f",clicked.coordinate.latitude];
NSString* longitude = [NSString stringWithFormat:#"%f",clicked.coordinate.longitude];
NSLog(#"lat: %#",latitude);
NSLog(#"lon: %#",longitude);
[fvi setDetails:clicked.title phone:clicked.phone address:clicked.address beersavailable:clicked.beersavailable latitude:latitude longitude:longitude];
[self.navigationController pushViewController:fvi animated:YES];
}
}
Then my finderdetail.h creates these variables:
#interface FinderDetail : UITableViewController{
UITableViewCell *phone;
UITableViewCell *address;
UITableViewCell *directions;
UILabel *venueLabel;
NSString *phoneText;
NSString *addressText;
NSString *venueText;
NSString *beersavailable;
NSString *latitudeText;
NSString *longitudeText;
}
#property (nonatomic, retain) IBOutlet UITableViewCell *phone;
#property (nonatomic, retain) IBOutlet UITableViewCell *address;
#property (nonatomic, retain) IBOutlet UITableViewCell *directions;
#property (nonatomic, retain) IBOutlet UILabel *venueLabel;
#property (nonatomic, retain) NSString *phoneText;
#property (nonatomic, retain) NSString *addressText;
#property (nonatomic, retain) NSString *venueText;
#property (nonatomic, retain) NSString *beersavailble;
#property (nonatomic, retain) NSString *latitudeText;
#property (nonatomic, retain) NSString *longitudeText;
#end
Lastly, finderdetail.m grabs these values, assigns them to the variables, and spits them into the table:
#implementation FinderDetail
#synthesize venueLabel, phone, address, directions;
#synthesize phoneText, addressText, venueText, beersavailble, latitudeText, longitudeText;
NSString *notlisted;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
-(void)setDetails:(NSString *)v phone:(NSString *)p address:(NSString *)a beersavailable:(NSString *)ba latitude:(NSString *)lat longitude:(NSString *)lon
{
NSLog(#"venue: %#",v);
NSLog(#"phone: %#",p);
NSLog(#"address: %#",a);
NSLog(#"beersavailable: %#",ba);
NSLog(#"%#",lat);
NSLog(#"%#",lon);
latitudeText = lat;
longitudeText = lon;
phoneText = p;
addressText = a;
venueText = v;
beersavailble = ba;
NSLog(#"%#", latitudeText);
NSLog(#"%#", longitudeText);
notlisted = #"Not Listed";
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Latitude: %#", latitudeText);
NSLog(#"Longitude: %#", longitudeText);
phone.detailTextLabel.text = phoneText;
address.detailTextLabel.text = addressText;
self.venueLabel.text = venueText;
if(phoneText == nil){
phone.detailTextLabel.text = notlisted;
}
if(addressText == nil){
address.detailTextLabel.text = notlisted;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
if(section ==0)
return 1;
else
if(section ==1)
return 1;
else
if(section ==2)
return 1;
else
return 0;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",indexPath);
if((indexPath.section==0) && (indexPath.row ==0))
{
NSLog(#"%#",phoneText);
}
if((indexPath.section==1) && (indexPath.row ==0))
{
NSLog(#"%#",addressText);
}
if((indexPath.section==2) && (indexPath.row ==0))
{
NSLog(#"%#",latitudeText);
NSLog(#"%#",longitudeText);
}
}
The initial phoneText will display in an NSLog, but the addressText and latitudeText and longitudeText return null. I can put phoneText in one of those lower if statements and it too returns null. Thanks!!!
You aren't actually using your #property when you are doing the following:
latitudeText = lat;
longitudeText = lon;
phoneText = p;
addressText = a;
venueText = v;
beersavailble = ba;
Also, you are leaking memory every time those assignments are performed after the initial time (when they were still nil).
What you really want is:
self.latitudeText = lat;
self.longitudeText = lon;
self.phoneText = p;
self.addressText = a;
self.venueText = v;
self.beersavailble = ba;
Also, with a NSString (also NSData, NSSet, etc.) #property, it is better to define them as a copy, since it would be perfectly valid to pass in a NSMutableString instead (since it is a subclass of NSString), which then the contents could be altered externally of this object:
#property (nonatomic, copy) NSString *phoneText;
#property (nonatomic, copy) NSString *addressText;
#property (nonatomic, copy) NSString *venueText;
#property (nonatomic, copy) NSString *beersavailble;
#property (nonatomic, copy) NSString *latitudeText;
#property (nonatomic, copy) NSString *longitudeText;
Finally, the fact that you get (NULL) outputted by NSLog suggests the ivars are getting set to nil (and most likely released), and you are using ARC (Automatic Reference Counting), instead of manual retain/release/autorelease.
In setDetails you need to use the properties in order to retain the objects and release previous objects. Assigning directly to the ivars subverts the properties setters/getters and the memory management they provide is lost. Basically if properties are defined use them every time.
Since the objects are not being retained their memory can be reused and unpredictable results can occur such as the values becoming nil.
One way to find such problems is to turn on NSZombies in the simulator runs. I do this occasionally even when I am not having problems just as a check.
To fix the problem rewrite setDetails as:
-(void)setDetails:(NSString *)v phone:(NSString *)p address:(NSString *)a beersavailable:(NSString *)ba latitude:(NSString *)lat longitude:(NSString *)lon
{
self.latitudeText = lat;
self.longitudeText = lon;
self.phoneText = p;
self.addressText = a;
self.venueText = v;
self.beersavailble = ba;
self.notlisted = #"Not Listed";
}
One way to insure that properties are not inadvertently not used is to define the ivars with a slightly different name than the properties. The synthesize statement supports this. Here is how:
in the #interface:
NSString *_latitudeText;
...
#property (nonatomic, retain) NSString *latitudeText;
in the #implementation
#synthesize latitudeText = _latitudeText;

Converting HTML to Plain Text for MapKit Annotations

I have a problem when I use an annotation to see information with MapKit.
I ran into a similar issue. You're not crazy. I believe it's a bug in the MapKit code. The Annotation object doesn't create it's own copy of the strings you pass to it. When your string goes out of scope, the map makes a bad reference. Try re-allocating the strings before you pass them. Like so:
NSString *tempT = [[NSString alloc] initWithString:itemT];
NSString *tempA = [[NSString alloc] initWithString:itemA];
addAnnotation = [[MapAnnotation alloc] initWithCoordinate:essai :tempT :tempA];
And then don't release them until you're finished displaying the map.
I ran into the exact same problem, as Jonesy mentioned, but there is a fix. I'm not sure what kind of class you have for your annotations, but I use this:
Annotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#interface LocationAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString* title;
NSString* subtitle;
}
#property (nonatomic, assign) MKPinAnnotationColor pinColor;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* subtitle;
- (id)initWithCoordinate:(CLLocationCoordinate2D) c
title:(NSString*) t
subtitle:(NSString*) st;
- (void)moveAnnotation:(CLLocationCoordinate2D) newCoordinate;
- (NSString*)subtitle;
- (NSString*)title;
#end
And Annotation.m:
#import "LocationAnnotation.h"
#implementation LocationAnnotation
#synthesize coordinate, pinColor, title, subtitle;
- (NSString *)subtitle {
return subtitle;
}
- (NSString *)title {
return title;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D) c
title:(NSString*)t
subtitle:(NSString*)st
{
coordinate = c;
self.title = t;
self.subtitle = st;
return self;
}
- (void)moveAnnotation:(CLLocationCoordinate2D)newCoordinate
{
coordinate = newCoordinate;
}
- (void)dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
#end
To implement it:
Annotation* ann = [[[Annotation alloc] initWithCoordinate:startLocation title:someStringAutoreleasedOrNot subtitle:someOtherStringAutoreleasedOrNot] autorelease];
[yourMapView addAnnotation:ann];
Really, the key here is that in the annotation class, the title and subtitle properties are declared as type copy. This makes a new copy of the string you assign it, so it can be released without causing the crash that you are having.
I dont see stringByStandardizingWhitespace method call in the above code you pasted... It would be helpful if you can post the code which has the error. Use debugger to know where the error is occuring...
Also one error which is not related to the syntax/error you specified but would effect the logic later:
you are assigning the gps_long tag tpo lat and vice versa ...