Objective C: Getter Methods vs Class.ivarName - getter

I am quite confused on how to access variables across files.
For example:
I have 3 files: Apple, Fruit, and Eat
Fruit.h
#interface Fruit
{
NSString *name;
}
#property (nonatomic, retain) NSString *name;
#end
Fruit.m
#implementation Fruit
#import "Fruit.h"
{
#synthesize name;
-(id) init
{
self = [super init];
if (self) {
name = [[NSMutableArray alloc] init];
}
return self;
}
}
#end
Apple.h
#interface Apple
#import Fruit.h
{
Fruit *apple;
}
#property (nonatomic, retain) Fruit *apple;
#end
Apple.m
#import Apple.h
#implementation Apple
#synthesize apple;
apple = [[Fruit alloc] init];
apple.name = #"apple";
#end
//my Eat.h is practically empty because I don't think I need it
Eat.m
#implementation Eat
#import Apple.h
//why is this not working?
NSLog(#"I am eating %#", apple.name);
I wrote these just as examples from scratch. So ignore silly syntax errors such as missing semi-colons, and obvious things I missed. I'm just mirroring something I am struggling with.
I guess my confusion is that in Apple.m, you can access the Fruit's name ivar with the period symbol (.). But in Eat.m, I cannot access apple's name ivar with a (.). I know I should/could write a getter method, but is there a way to directly access variables in the way I am trying to across files? I know its probably bad programming technique (if it can even be done), but I am just confused why the functionality isn't the same.

If Apple is a type of Fruit then it will inherit the 'name' property. Your example implementation does not show Apple as a type of Fruit but I assume you meant it to be (and more on that later).
The variable 'apple' is used in Eat.m, is assigned in Apple.m but is not exported anywhere. The compilation of Eat.m should have failed with "variable 'apple' is unknown".
The Fruit field of 'name' is assigned a NSMutableArray but it is actually a string. The compiler should have warned about this. And, you don't have a Fruit 'init' routine that assigns an initial name to a fruit.
Here is a version that works:
/* Fruit.h */
#interface Fruit : NSObject { NSString *name; };
#property (retain) NSString *name;
- (Fruit *) initWithName: (NSString *) name;
#end
/* Fruit.m */
/* exercise for the reader */
/* Apple.h */
# import "Fruit.h"
#interface Apple : Fruit {};
#end
/* Apple.m */
/* exercise for the reader - should be empty */
/* main.c - for example */
#import "Apple.h"
int main () {
Apple apple = [[Apple alloc] initWithName: #"Bruised Gala"];
printf ("Apple named: %#", apple.name);
}

Related

Not accessing value from Object

I have a NSObject called GettingHere which has a NSString *content.
I then have a UIViewController on which I create a button programatically as follows (this button working as intended):
byAirButton = [UIButton buttonWithType:UIButtonTypeCustom];
byAirButton.tag = 1;
byAirButton.frame = CGRectMake(25, 140, 280.f, 40.f);
UIImage *airButton = [UIImage imageNamed:#"gettingHereByAirButton.png"];
[byAirButton setBackgroundImage:airButton forState:UIControlStateNormal];
[self.view addSubview:byAirButton];
[byAirButton addTarget:self action:#selector(byAirButtonClicked) forControlEvents:UIControlEventTouchUpInside];
For the action:#selector(byAirButtonClicked), I do the following. gettingHere is an instance of the GettingHere object.
- (void) byAirButtonClicked
{
gettingHere.content = #"This is how to get here by Air";
NSLog(#"Content: %#", gettingHere.content);
[self performSegueWithIdentifier:#"gettingHereSegue" sender:self];
}
The idea is to set the content for my GettingHere object and then just call that from the next view (GettingHereViewController) when the user clicks the byAirButton.
This NSLog shows that content is being set.
In my prepareForSegue, I do the following:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"gettingHereSegue"])
{
NSLog(#"Content to be passed: %#", gettingHere.content);
GettingHereViewController *vc = (GettingHereViewController *)segue.destinationViewController;
vc.gettingHere.content = gettingHere.content;
}
}
The segue works fine, but the NSLog shows my gettingHere object values as being (null).
Can anyone tell me where I am going wrong please? I have stepped through it several times but can't figure out where I am going wrong.
EDIT: Here is how I instantiate the GettingHere Object.
In the SubNavViewController.h
#import "GettingHereContent.h"
#interface SubNavViewController : UIViewController
#property GettingHereContent *gettingHere;
In the SubNavViewController.m
#import "SubNavViewController.h"
#import "GettingHereViewController.h"
#import "GettingHereContent.h"
#interface SubNavViewController ()
#end
#implementation SubNavViewController
#synthesize gettingHere;
And here is how I create the GettingHere Object:
GettingHere.h
#import <Foundation/Foundation.h>
#interface GettingHereContent : NSObject
#property (nonatomic, strong) NSString *content;
#end
GettingHere.m
#import "GettingHereContent.h"
#implementation GettingHereContent
#synthesize content;
#end
You never alloc init your gettingHere property. Try this in your init method of your VC
gettingHere = [[GettingHereContent alloc] init];
Also don't forget to release it: answer from here: alloc + init with synthesized property - does it cause retain count to increase by two?
#interface Foo : Bar {
SomeClass* bla;
}
#property (nonatomic, retain) SomeClass* bla;
#end
#implementation Foo
#synthesize bla;
-(id)init {
...
bla = [[SomeClass alloc] init];
...
}
-(void)dealloc {
[bla release];
...
[super dealloc];
}

NSManagedObject's #synthesize attribute stays faulted after modifying a relationship

I'm using code derived from Apple's DateSectionTitles example code. In my class Appointment I have a relationship to Location. Furthermore I generate a section identifier used by a UITableViewController.
#class Location;
#interface Appointment : NSManagedObject
#property (nonatomic, retain) NSDate * begin;
#property (nonatomic, retain) NSDate * end;
#property (nonatomic, retain) Location * location;
#property (nonatomic, retain) NSString *sectionIdentifier;
#property (nonatomic, retain) NSString *primitiveSectionIdentifier;
#end
#implementation Appointment
#synthesize begin = _begin;
#dynamic end;
#dynamic location;
#dynamic primitiveSectionIdentifier;
#dynamic sectionIdentifier;
#pragma mark -
#pragma mark Transient properties
- (NSString *)sectionIdentifier {
// Create and cache the section identifier on demand.
[self willAccessValueForKey:#"sectionIdentifier"];
NSString *tmp = [self primitiveSectionIdentifier];
[self didAccessValueForKey:#"sectionIdentifier"];
if (!tmp) {
/*
Sections are organized by month and year. Create the section identifier as a string representing the number (year * 1000) + month; this way they will be correctly ordered chronologically regardless of the actual name of the month.
*/
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:[self begin]];
tmp = [NSString stringWithFormat:#"%d", ([components year] * 10000) + [components month] * 100 + [components day]];
[self setPrimitiveSectionIdentifier:tmp];
}
return tmp;
}
#pragma mark -
#pragma mark Begin setter
- (void)setBegin:(NSDate *)begin
{
// If the time stamp changes, the section identifier become invalid.
[self willChangeValueForKey:#"begin"];
[self willChangeValueForKey:#"primitiveSectionIdentifier"];
_begin = begin;
[self setPrimitiveSectionIdentifier:nil];
[self didChangeValueForKey:#"begin"];
[self didChangeValueForKey:#"primitiveSectionIdentifier"];
}
#end
The problem: After altering the location the data stays faulted.
Before modifying location the object looks like this:
<Appointment: 0x837d570> (entity: Appointment; id: 0x837c900 <x-coredata://83B2187C-00B3-4029-B4C5-4EB69C18FC59/Appointment/p1> ; data: {
begin = "2013-07-27 16:00:00 +0000";
end = "2013-07-27 18:00:00 +0000";
location = "0x837e6c0 <x-coredata://83B2187C-00B3-4029-B4C5-4EB69C18FC59/Location/p1>";
})
After altering the property location:
<Appointment: 0x9b7b1f0> (entity: Appointment; id: 0x9b7ab50 <x-coredata://83B2187C-00B3-4029-B4C5-4EB69C18FC59/Appointment/p1> ; data: <fault>)
If I relinquish from generating a section identifier and using a #dynamic instead of a #synthesized property it still works. What's the cause of this and how can I overcome this?
Thanks to Martin R who pointed me in the right direction I've found the problem in my code.
What I didn't know was the fact that Core Data automatically generates additional primitive properties for you:
For example, given an entity with an attribute firstName, Core Data
automatically generates firstName, setFirstName:, primitiveFirstName,
and setPrimitiveFirstName:. Core Data does this even for entities
represented by NSManagedObject. To suppress compiler warnings when you
invoke these methods, you should use the Objective-C 2.0 declared
properties feature, as described in “Declaration.”
(Source)
The fact that I wasn't aware of this leaded me to adopt the example code in a wrong way. The way it works for me is now:
#class Location;
#interface Appointment : NSManagedObject
#property (nonatomic, retain) NSDate * primitiveBegin;
#property (nonatomic, retain) NSDate * begin;
#property (nonatomic, retain) NSDate * end;
#property (nonatomic, retain) Location * location;
#property (nonatomic, retain) NSString *sectionIdentifier;
#property (nonatomic, retain) NSString *primitiveSectionIdentifier;
#end
#implementation Appointment
#dynamic primitiveBegin;
#dynamic begin;
#dynamic end;
#dynamic location;
#dynamic primitiveSectionIdentifier;
#dynamic sectionIdentifier;
#pragma mark -
#pragma mark Transient properties
- (NSString *)sectionIdentifier {
// Create and cache the section identifier on demand.
[self willAccessValueForKey:#"sectionIdentifier"];
NSString *tmp = [self primitiveSectionIdentifier];
[self didAccessValueForKey:#"sectionIdentifier"];
if (!tmp) {
/*
Sections are organized by month and year. Create the section identifier as a string representing the number (year * 1000) + month; this way they will be correctly ordered chronologically regardless of the actual name of the month.
*/
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:[self begin]];
tmp = [NSString stringWithFormat:#"%d", ([components year] * 10000) + [components month] * 100 + [components day]];
[self setPrimitiveSectionIdentifier:tmp];
}
return tmp;
}
#pragma mark -
#pragma mark Begin setter
- (void)setBegin:(NSDate *)begin
{
// If the time stamp changes, the section identifier become invalid.
[self willChangeValueForKey:#"begin"];
[self setPrimitiveBegin:begin];
[self didChangeValueForKey:#"begin"];
[self setPrimitiveSectionIdentifier:nil];
}
#pragma mark -
#pragma mark Key path dependencies
+ (NSSet *)keyPathsForValuesAffectingSectionIdentifier
{
// If the value of timeStamp changes, the section identifier may change as well.
return [NSSet setWithObject:#"begin"];
}
#end

How do I access properties of an object when inside another custom object in Xcode / Obj C?

As I newbie I sort of understand how to create and access properties for an object with dot notation.. eg I have an object golfCourse with a property courseName so golfCourse.courseName=#"My Course" works OK. My problem is that if I create a "holeObject" containing Par and Distance and create Hole1, Hole2 etc inside my Course Object trying to access them by golfCourse.Hole1.Par is returning null... My various searches have not found me any clarity.. Can someone point me in the right direction?
Many thanks
HoleObject.h
#import <Foundation/Foundation.h>
#interface HoleObject : NSObject
#property(nonatomic,strong) NSString* par;
#property(nonatomic,weak) NSString* yellowDistance;
#end
HoleObject.m
#import "HoleObject.h"
#implementation HoleObject
#synthesize
par=_par,
yellowDistance=_yellowDistance,
-(void) encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.par forKey:#"Par"];
[encoder encodeObject:self.yellowDistance forKey:#"YellowDistance"];
}
-(id) initWithCoder:(NSCoder*)decoder
{
if((self=[super init]))
{
self.par=[decoder decodeObjectForKey:#"Par"];
self.yellowDistance=[decoder decodeObjectForKey:#"YellowDistance"];
}
return self;
}
#end
CourseObject.h
#import <Foundation/Foundation.h>
#import "HoleObject.h"
#interface CourseObject : NSObject
#property(nonatomic,strong)NSString* courseName;
#property(nonatomic,strong)NSString* courseAddress;
#property(nonatomic,strong)HoleObject* hole1;
#property(nonatomic,weak)HoleObject* hole2;
etc...
#end
CourseObject.m
#import "CourseObject.h"
#implementation CourseObject
#synthesize
courseName=_courseName,
courseAddress=_courseAddress,
hole1=_hole1,
etc;
-(void) encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.courseName forKey:#"CourseName"];
[encoder encodeObject:self.courseName forKey:#"CourseAddress"];
[encoder encodeObject:self.hole1 forKey:#"Hole1"];
etc;
}
-(id) initWithCoder:(NSCoder*)decoder
{
if((self = [super init]))
{
self.courseName=[decoder decodeObjectForKey:#"CourseName"];
self.courseAddress=[decoder decodeObjectForKey:#"CourseAddress"];
self.hole1 = [decoder decodeObjectForKey:#"Hole1"];
self.hole2 = [decoder decodeObjectForKey:#"Hole2"];
etc;
}
return self;
}
#end
Then in my main View Controller..
- (void)viewDidLoad
{
[super viewDidLoad];
allCourses=[[NSMutableArray alloc] initWithCapacity:2];
CourseObject*thisCourse;
thisCourse=[[CourseObject alloc]init];
thisCourse.courseName=#"Branston";
thisCourse.courseAddress=#"The World";
thisCourse.hole1.par=#"4";
thisCourse.hole1.yellowDistance=#"336";
but if I then try and NSLog thisCourse.hole1.par Im getting null?
Thanks for looking.
Spent some time trying different things with this as it was pretty clear that the Null was showing the object was not being created properly.. Found that [[CourseObject alloc]init] does not actually do anything for the objects "sub-Objects" and I needed to do course.hole1=[[HoleObject alloc] init] for all 18 holes as well... bit fiddly but seems to work..

NSMutableArray Add/Remove Objects (Inherited File)

Okay, so I'm pretty new to xcode but I cannot find something specific to this issue anywhere. So I declare the array and instantiate it in the following files:
//xmlToUrl.h
#import <Foundation/Foundation.h>
#interface xmlToUrl : NSObject {
NSMutableArray *field;
NSMutableArray *name;
}
#property(nonatomic, retain)NSMutableArray *field;
#property(nonatomic, retain)NSMutableArray *name;
#end
and
//xmlToUrl.m
#import "xmlToUrl.h"
#implementation xmlToUrl
#synthesize field;
#synthesize name;
-(void)dealloc
{
[field release];
[name release];
[super dealloc];
}
#end
So this is where I am confused. I don't know how to correctly "alloc" or "init" the mutable arrays, nor how to handle the add/remove operations from another file which inherits xmlToUrl.h.
The code (in the other file) as I have it now just prints null. Its listed below. What am I doing wrong?!?
//nodeContent is just a NSMutableString
[xmlToUrlObject.name addObject:nodeContent];
NSLog(#"xml Name = %#", xmlToUrlObject.name);
//I omitted all the operational code here but if I NSLog nodeContent it prints the correct values
[xmlToUrlObject.field addObject:nodeContent];
NSLog(#"xml Field = %#", xmlToUrlObject.field);
You need an init function in your implementation file, it would look similar to the following
-(id) init
{
self = [super init];
if (self) {
field = [[NSMutableArray alloc] init];
name = [[NSMutableArray alloc] init];
}
return self;
}
Then whenever you create an instance of your xmlToUrl class via [[xmlToUrl alloc] init] you will have an instance of your class that has already initialized your two NSMutableArrays

My custom class object gets released even after retaining it

I have been trying to debug this error like for days and still can't seem to grasp what really is going on with my object.
The code goes like this.
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
// extract data from clicked link
SongObject *Data = [[SongObject alloc] init];
[Data retain];
selectedSong = Data;
}
selectedSong is public variable in the main class, now the crazy thing is that using the above method works everywhere else but shoulStartLoadWithRequest.
Trying to deubg it gives me "Out Of Scope", could it be by some crazy reason that "shouldStartLoadWithRequest" is autoreleasing my object even when I say don't?
Any idea's?
Edit: This is the H and M file which selectedSong is suppose to hold.
#import <Foundation/Foundation.h>
#import "SongObject.h"
#interface SongObject : NSObject<NSCopying> {
NSString *artist;
NSString *titel;
NSString *album;
NSString *genre;
NSString *songUrl;
NSString *rating;
NSString *image;
BOOL local;
}
#property (readonly) NSString *getArtist;
#property (readonly) NSString *getTitle;
#property (readonly) NSString *getAlbum;
#property (readonly) NSString *getGenre;
#property (readonly) NSString *getSongURL;
#property (readonly) NSString *getRating;
#property (readonly) NSString *getImage;
#property (readonly) BOOL isLocal;
-(void) setInfo:(NSString *) a: (NSString*) t: (NSString*) ab: (NSString*)g: (NSString*)sU: (NSString*)r: (NSString*) i: (BOOL) loc;
#end
#import "SongObject.h"
#implementation SongObject
-(id)init
{
if(self =[super init])
{
NSLog(#"Init songobject");
}
return self;
}
-(id) copyWithZone: (NSZone *) zone {
SongObject *newSong = [[SongObject allocWithZone:zone] init];
NSLog(#"_copy: %#", [newSong self]);
[newSong setInfo:[self getArtist] :[self getTitle] :[self getAlbum] :[self getGenre] :[self getSongURL] :[self getRating] :[self getImage] :[self isLocal]];
return(newSong);
}
-(void)dealloc
{
NSLog(#"Songobject deallocted from memory...");
[super dealloc];
}
-(void) setInfo:(NSString *) a: (NSString*) t: (NSString*) ab: (NSString*)g: (NSString*)sU: (NSString*)r: (NSString*) i: (BOOL) loc{
artist = a;
titel = t;
album = ab;
genre = g;
songUrl = sU;
rating = r;
image = i;
local = loc;
}
-(NSString*)getArtist
{
return artist;
}
-(NSString*)getTitle
{
return titel;
}
-(NSString*)getAlbum
{
return album;
}
-(NSString*)getGenre
{
return genre;
}
-(NSString*)getSongURL
{
return songUrl;
}
-(NSString*)getRating
{
return rating;
}
-(NSString*)getImage
{
return image;
}
-(BOOL)isLocal{
return local;
}
#end
That doesn't seem possible. Be careful, cause you're increasing the reference count twice. Once in the alloc, and again with the retain. What does selectedSong looks like? is it a property with automated retain?
Also, sometimes I cannot read the object in the debugger and I use NSLog. What do you see then?
What about overriding -dealloc. Did you try setting a breakpoint there?
I finally found the problem the SongObject class with the NSString variables was never retained. So the selectedSong was actually never released but the variables within the class it self.
Fixed it by using NSString alloc initWithString and then overriding the dealloc method and releasing them in there.

Resources