Accessing Objects from Class or Method - objective-c

I have 2 classes in my Cocoa project (Xcode). First is AppDelegate class and the second is a Book class.
In my Book class, I set an integer property in the #interface which is the book's chapters. In its #implementation, I have created objects (ex. Book *firstBook = [[Book alloc]init]) and set their properties (In the Book.m file). Those are my data and will not change.
In my app delegate, I have a method that will fetch what the user selected from an interface item, get the title of the selected item, who's name will be identical to one of those in Book.m. Then a for loop will run to create menu items for a popUpButton so the user can select which chapter to jump to.
The problem I am seeing now is that when I try running the for loop to create menu items, I need the limit amount of the loops. That limit amount is based on the selectedObjectByUser's chapter property (listed in Book.m). How do I access that.
I am sure it will work if I can connect these two together because it works when create the object inside this method(under AppDelegate.h) but the problem is that it is too space consuming and it changes often.

I'm not entirely sure what the situation is here, but let's take a look at some sample code first.
//// Book.h
#interface Book : NSObject
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *author;
#property (nonatomic, assign) NSInteger numberOfPages;
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor;
#end
//// Book.m
#implementation Book
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor {
if ( self = [super init] ) {
self.title = aTitle;
self.author = anAuthor;
}
return self;
}
- (void)dealloc {
self.title = nil;
self.author = nil;
[super dealloc];
}
#end
So in this we establish a class and provide it with 3 properties, title and author (which are both NSString's) and numberOfPages (which is an integer). Within the class we can manipulate those values by calling things such as self.propertyName = value.
This is all well and good, but what actually is happening? Well let's update the header a little more:
//// Book.h
#interface Book : NSObject {
#private
NSString *_title;
NSString *_author;
NSInteger _numberOfPages;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *author;
#property (nonatomic, assign) NSInteger numberOfPages;
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor;
#end
In this, we have just explicitly defined something that the compiler will normally infer through the #property construct. These new additions are what we call instance variables, or ivars, and are where the values you assign to your properties are actually stored.
However, manipulating the ivars can be dangerous if you are not yet 100% comfortable with memory management. Even if you are using ARC, you should still understand how that management works.
So we've now exposed where these properties actually store there data, but what about that #private job? What's it all about? #private is part of a family of keywords that help to denote the "Accessibility Scope" of something. The other two keywords in this family are #protected and #public, however the use of the second two is infrequent, if not unusual. These keywords are responsible for saying where you are allowed to access things. Here's a quick definition of them.
#public Freely accessible from anywhere, even outside of the object itself. However accessing an instance variable directly from outside of its own class is generally considered to be extremely bad practice in the Cocoa development world, hence why you'll find very little on how to do it.
#protected Freely accessible within the class and its own subclasses. Can not be accessed outside of the class/object.
#private Freely accessible within the class, but not anywhere else. Can not be accessed outside of the class/object or even in its subclasses.
So now that we've covered what is actually driving the storage behind a property, let's take a look at using our Book object in another part of the app, such as AppDelegate.
//// AppDelegate.m
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
Book *myBook = [[Book alloc] initWithTitle:#"pending title" andAuthor:#"Foo Bar"];
myBook.title = #"My Cool Book";
NSLog(#"%# by %#", myBook.title, myBook.author);
[myBook release];
}
#end
In this we create a new Book object, to put it in more technical terms, we define a variable called myBook with a type of Book and instantiate it. In this we're using the -initWithTitle:andAuthor: method that we created earlier in order to tell the Book object that it should have an initial title and author.
Following this line we then arrive something a little more curious. myBook.title = #"My Cool Book"; You might recall that we had something similar back in Book.m, self.title = aTitle. So what is going on here? Why are we using myBook now rather than self, like we did previously? The reason is because of what self actually is.
self is a keyword provided by the Objective-C runtime, and refers to the current object that you are within. So if we write code inside Book.m, self will refer to the current Book object. If we use self within AppDelegate.m, it will refer to the AppDelegate. So in our earlier code, self was referring to the current Book object much like our myBook object is now referring to a specific Book object. They essentially are equal to each other (not exactly, but thats another area of discussion).
This means any of the properties within Book or methods can be accessed through the myBook variable, much like you would using self inside of Book.m. So we could also do
myBook.title = #"My Book";
myBook.author = #"Baz Quux";
myBook.numberOfPages = 100;
Hope this helps (and answered your question, if not then may it serve as a reference to people wishing to know more about properties and instance variables)

Related

Which one is initialized, property or its instance variable

Suppose I have a property called myPropertyName defined in my class MyClassName. Manual memory management is used throughout this post.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
#private
NSObject* myPropertyName;
#public
}
#property (nonatomic, retain) NSObject* myPropertyName;
// Some methods prototypes are here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
#synthesize myPropertyName;
// Some methods are here
#end
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
This one is calling myPropertyName setter, but I'm not sure what is the name of the instance variable being used in the setter, myPropertyName (since I've declared a #private field named myPropertyName) or _myPropertyName (people say that this one with underbar is the default)?
myPropertyName = [[NSObject alloc] init];
Does this initialize the instance variable of the myPropertyName property? If I don't have #synthesize myPropertyName = _myPropertyName;, would it be wrong since the default instance variable for the property is said to be _myPropertyName.
_myPropertyName = [[NSObject alloc] init];
Is _myPropertyName still declared as the instance variable for my property myPropertyName even if I use #synthesize myPropertyName; and #private NSObject* myPropertyName;?
In my understanding, a property is just a name (such as myPropertyName), there should be some instance variable encapsulated to be used in actual operations in the code, such as assigning values.
First off, I highly recommend reading Apple's documentation on properties, also linked by nhgrif. However, I understand docs can be a bit dense reading material (though Apple's, I find, are not so bad), so I'll give a brief overview of properties here.
I like examples, so I'm going to rewrite your two classes in a bit more current form.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject
#property (nonatomic, strong) NSObject *myPropertyName;
// method prototypes here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
// some methods here
#end
The class MyClassName now has a property called myPropertyName of type NSObject *. The compiler will do a lot of work for you for "free" in this instance. Specifically, it will generate a backing variable, and also generate a setter and getter for myPropertyName. If I were to rewrite the two files, and pretend I'm the compiler, including that stuff, they would look like this:
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
NSObject *_myPropertyName;
}
#property (nonatomic, strong) NSObject *myPropertyName;
- (void)setMyPropertyName:(NSObject *)obj;
- (NSObject *)myPropertyName;
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
- (void)setMyPropertyName:(NSObject *)obj
{
_myPropertyName = obj;
}
- (NSObject *)myPropertyName
{
return _myPropertyName;
}
#end
Again, all of this is happening for "free": I'm just showing you what's happening under the hood. Now for your numbered questions.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
First of all, you should probably be using Automatic Reference Counting, or ARC. If you are, you won't be allowed to call autorelease. Ignoring that part, this works fine. Excluding the autorelease, this is exactly equivalent to:
[self setMyPropertyName:[[NSObject alloc] init]];
Which, if you look at the second .m file I wrote out, above, will basically translate to:
`_myPropertyName = [[NSObject alloc] init];
myPropertyName = [[NSObject alloc] init];
As written, this code will give a compiler error, since there is no variable called myPropertyName in this class. If you really want to access the instance variable underlying (or, "backing") the myPropertyName property, you can, by using its real name:
_myPropertyName = [[NSObject alloc] init]; // note the underscore
But most of the time, it's better to use the setter, as in point 1., since that allows for side effects, and for Key-Value Coding, and other good stuff.
_myPropertyName = [[NSObject alloc] init];
Oh. Well you got it. See point 2.
You mentioned that:
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
In case it hasn't been made clear, a property is something of an abstract concept; its data is stored in a normal instance variable, typically assigned by the compiler. Its access should usually be restricted to the setter and getter, with important exceptions. To keep this answer short, I won't go into more detail than that.
One more thing: as nhgrif mentioned, you don't need to use the #synthesize keyword anymore. That is implicitly understood by the compiler now.
If you're not sure about any of this, post a comment or, better yet, read the docs.
Let's take this example:
#property NSString *fullName;
If in the implementation, we override the setters and getters, and in these setters and getters, we don't use an instance variable fullName, it is never created. For example:
- (NSString *)fullName
{
return [NSString stringWithFormat:#"%# %#", self.firstName, self.lastName];
}
- (void)setFullName:(NSString *)fullName
{
//logic to split fullName into two strings
//self.firstName = etc
//self.lastName = etc.
}
In this example, there is no instance variable for fullName created.
This is according to Apple's Official Documentation
If, however, you don't override both the setter and getter, an instance variable is created.
As a sidenote, you can declare a property readonly, and then simply overriding the getter (without using the variable) will prevent an ivar being created. Likewise, you can declare a property writeonly and just override the setter.

objective-c "generic" type for #property for use with multiple subclasses

i'm not sure of the most eloquent way to state this but i will give it my best. i have created a custom class that is a generic object with some properties. i have created a couple subclasses to extend that and make them more specific than the superclass. so for the sake of example i will throw out some generic example code that may or may not be proper syntax only to illustrate what i would like to accomplish.
#interface Vehicle : NSObject
#property (nonatomic) int wheels;
- (id)initWithNumberOfWheels:(int)wheels;
#end
from there i create some subclasses for same "car" & "truck" which give more detail to the class.
#interface Car : Vehicle
#property (nonatomic) BOOL convertible;
#property etc...
#end
and...
#interface Truck : Vehicle
#property (nonatomic) BOOL is4x4;
#property (nonatomic) int numberOfDoors;
#end
so here is where it gets interesting. i want to create another class that allocates those objects but i want the "type" of vehicle to be determined in the init method but use the same #property variable. so for example (and again, this is all garbage code just to give a visual representation)
Road.h
#import "Car.h"
#import "Truck.h"
#interface Road : NSObject
#property (strong, nonatomic) NotSureWhatToUseHereToMakeThisWork *myRide;
// doesn't work: #property (strong, nonatomic) id myRide;
// doesn't work: #property (strong, nonatomic) Vehicle *myRide;
- (id)initWithCars;
- (id)initWithTrucks;
#end
Road.m
#implementation Road
- (id)initWithCars
{
//standard init code...
myRide = [[Car alloc] initWithNumberOfWheels:4];
myRide.convertable = NO;
}
- (id)initWithTrucks
{
//standard init code...
myRide = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
myRide.is4x4 = YES;
}
#end
the bottom line is if i use the superclass in the #property it doesn't get the subclass properties obviously. basically i want to keep all this as generic and reusable as possible. it doesn't make since to make a special "road" class just for cars & one for trucks. a road is a road after all. is there anyway to do what i am after? is there a better way to do something like this? the primary purpose is to have objects that inherit specific properties for specific situations only. the reason i don't want to make extra #properties is i don't want those visible if they aren't applicable to the situation.
edit:
i added a couple extra snippets to show what i tried before even posting this question that didn't work.
answer: the correct "answer" if anyone is curious is located in CRD's response in the "Addendum". the reason this works is the type "id" can only call methods and does not inherit properties. so rather the workaround (i say it that way, as i was researching this, came to the conclusion this is not good programming and should probably be avoid if possible) would be to use the accessor methods to get/set the property.
id mySomethingObject = [[SomeClass alloc] init...];
[mySomethingObject setPropertyMethod]...; //sets value
[mySomethingObject propertyMethod]...; //gets value
rather than trying to use...
mySomethingObject.property = ; //set
mySomethingObject.property; //get
as stated in the correct answer, if your class you allocated "id" to does not respond to that method your program will crash.
You appear to be confusing a number of issues.
First there is the type of an instance vs. the type of variables which hold references to instances. When an object is created is it of some specific type and that types does not change[*]. Variables also have a type, and that does not change either. Subtyping/inheritance allows you to store a reference to an object of some type, T, in a variable of some other type, S, provided S is a supertype of T.
Second there is static vs. dynamic typing. While Objective-C uses dynamic typing, where the actual type of objects used in some operation is determined at run time, the compiler itself uses static typing, where types are determined during compilation, to aid in writing correct programs. Sometimes the compilers static checking will just produce warnings, but in other cases the compiler will refuse to compile something. In particular property references are compiled based on static typing.
In your example this means you cannot directly reference a property of Car on an object referenced by a variable of type Vehicle *, even if you know the referenced object is a Car - as at compile time all that is known is that is it a Vehicle.
The solution is to first test the actual type of the referenced object and then introduce a local variable of the more precise type, or use a lot of casts. For example:
// (a) create an object of type Car (for a Reliant Robin ;-))
// (b) create a variable of type Car and store in it a reference to the created Car
Car *myCar = [[Car alloc] initWithNumberOfWheels:3];
// Create a variable of type Vehicle and store in it the reference stored in myCar
// The created instance is *still* a Car
Vehicle *myRide = myCar;
// See if myRide is a Car and then do something
if ([myRide isKindOfClass:Car.class])
{
// create a variable of type Car to avoid having to continually cast myRide
Car *myCarRide = (Car *)myRide; // due to if above we know this cast is valid
if (myCarRide.isConvertible) ...
To do this without the intermediate variable you use a cast:
...
// See if myRide is a Car and then do something
if ([myRide isKindOfClass:Car.class])
{
if (((Car *)myCarRide).isConvertible) ...
Which shows why the intermediate variable approach is better!
As a final example, you write your initWithTrucks method like this:
- (id)initWithTrucks
{
//standard init code...
Truck *myTruck = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
myTruck.is4x4 = YES;
// Store the reference to the created Truck in myRide
myRide = myTruck;
}
HTH
Addendum
From your comments it seems you may be looking for dynamic typing and do not wish to the compiler to perform any static typing. This is (partially) supported, but not using the dot notation for properties - you must use the getter and setter methods directly.
First, in Road you declare myRide to be type id:
#interface Road : NSObject
#property id myRide;
The id type means two things (a) any object reference and (b) do not statically check a method exists on the object. However the compiler must know that a called method exists on some object, and it will still perform static type checks on the arguments to the method - so its not complete dynamic typing (however you could pass id typed expressions or declare your methods to take arguments of type id of course...).
Second you make all references to properties use the getter or setter methods directly and do not use the dot notation (for non-property methods you just call them as usual). E.g.:
- (id)initWithTrucks
{
//standard init code...
myRide = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
[myRide setIs4x4:YES];
}
If you make a call such as [myRide setIs4x4:YES] and myRide is referencing a Car object then you will get a runtime error.
The general recommendation is to stick as much as possible with the compiler's static typechecking.
[*] We will ignore any runtime magic, there be dragons. In normal code objects never change type.
You have to use the type "Vehicle" and then cast your object with "Truck" or "Car" to get the specific properties
the most generic architecture would be to create a VehicleProtocol, that any class could implement. you still could have a Vehicle class that implements the protocol and subclass from it (similar to NSObject implementing the NSObject protocol), or let independent classes implement it. the road would have a property #property (strong) id<VehicleProtocol> myRide.
A complete example of the later architecture: no vehicle super class, but all a VehicleProtocol
#import <Foundation/Foundation.h>
#protocol VehicleProtocol <NSObject>
#property (nonatomic) NSUInteger wheels;
#end
#interface Car : NSObject <VehicleProtocol>
#property (nonatomic) BOOL convertible;
#property (nonatomic) NSUInteger wheels;
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels;
#end
#implementation Car
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels
{
if (self = [super init]) {
_wheels = numberOfWheels;
}
return self;
}
#end
#interface Truck : NSObject <VehicleProtocol>
#property (nonatomic) BOOL is4x4;
#property (nonatomic) int numberOfDoors;
#property (nonatomic) NSUInteger wheels;
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels;
#end
#implementation Truck
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels
{
if (self = [super init]) {
_wheels = numberOfWheels;
}
return self;
}
#end
#interface Road : NSObject
#property (strong) id<VehicleProtocol> myRide;
#end
#implementation Road
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *vehicles = #[[[Car alloc] initWithNumberOfWheels:4], [[Car alloc] initWithNumberOfWheels:3], [[Truck alloc] initWithNumberOfWheels:10]] ;
for (id v in vehicles) {
if ([v isKindOfClass:[Truck class]]) {
[v setIs4x4:YES];
}
}
Road *road = [[Road alloc] init];
road.myRide = vehicles[0];
NSLog(#"%#", road.myRide);
road.myRide = vehicles[2];
NSLog(#"%#", road.myRide);
NSObject *obj = [[NSObject alloc] init];
road.myRide = obj; // warning in this line
NSLog(#"%#", road.myRide);
}
return 0;
}
Sure it might have more lines of codes than with "classical subclassing", but there are less dependencies. Instead the classes agree on a contract to fulfill. Here the contract only requires the objects to have any number of wheels.
Note that I create a Road and assign first a car and than a truck (I also show how to identify cars and trucks via -isKindOfClass:), both works without any warning or error, as Car and Truck completely fulfill the contract. Than I assign a plain NSObject. Here the compiler warns, as he recognizes that NSObject does not implement the protocol. Though it is not an compiler error, as the compiler does not know, if you will use any protocol specific method on that object.
In case of a plain NSObject assigned to myRide, this line
NSLog(#"%# %ld", road.myRide, (unsigned long)road.myRide.wheels);
will lead to a runtime crash (as an NSObject instance does not respond to wheel) — but at compile time it will not even trigger a warning.
Storing a Car in a variable of type Vehicle * does not remove the object's Car properties — the Car will still be able to access all of its state normally — it just means that you can't access the properties through that variable.
But that's the basic idea here, isn't it? You want this class to be able to handle all Vehicles, and that's what it's doing — it's only showing you the functionality available to all Vehicles. So you can have the interface necessary for interaction with a generic Vehicle in the Vehicle class, and implement the methods in your subclasses to do the class-appropriate behavior when called, and everything will work.
If the issue is specifically creating new instances of a specific class that you want to treat generically from that point on, you can use a statically typed local variable and assign to the generically typed variable once it's set up.
For example, let's say we have a game where there are human players and AI players, and the human player can give himself an advantage by making AI players take more damage. We could do this:
#interface Combatant : NSObject
#property(nonatomic, strong) NSString *name;
#property(nonatomic) int hitPoints;
- (void)takeDamage:(int)damageAmount;
#end
#implementation Combatant
- (void)takeDamage:(int)damageAmount {
self.hitPoints -= damageAmount;
}
#end
#interface HumanCombatant : Combatant
#property(nonatomic, strong) UserID *userID;
- (id)initWithUserID:(UserID *)theID;
#end
#implementation HumanCombatant
- (id)initWithUserID:(UserID *)theID {
if ((self = [super init])) {
_userID = [theID retain];
}
}
- (void)takeDamage:(int)damageAmount {
[super takeDamage: damageAmount];
NSLog(#"Human took %d damage, has %d health remaining", damageAmount, self.hitPoints);
}
#end
#interface AICombatant : Combatant
#property(nonatomic) double damageMultiplier;
#end
#implementation AICombatant
- (void)takeDamage:(int)damageAmount {
int modifiedDamage = damageAmount * self.damageMultiplier;
[super takeDamage: modifiedDamage];
NSLog("AI took %d damage, has %d health remaining", modifiedDamage, self.hitPoints);
}
#end
Then, in most of our game code, we can use a variable typed as a Combatant *, and when you send it takeDamage:, it will do the right thing for the type of combatant it is. Our external code that calls the object a Combatant * will not be able to directly access an AICombatant's damageMultiplier property, because the other code doesn't know whether the Combatant is an AICombatant, but the object will still have that property and will behave correctly for its class.
Make it a Vehicle* and make each class implement type to return a constant indicating that class's type.
#property (nonatomic, strong) Vehicle* yourRide;
...
if (yourRide.type == VehicleConstant_Truck) {
Truck* yourTruck = (Truck*) yourRide;
NSLog(#"This truck %s a 4x4", yourTruck.is4x4 ? "is" : "isn't");
}
To make #vikingosegundo happy, an alternative approach is to do:
if ([yourRide isKindOfClass:[Truck class]]) {
instead of the if statement above.

Why the setter is called for one property but not the other?

I took this code from the Big Nerd Ranch iOS Programming book. In the code, they are assigning two instance variables, coordinate and title. Why is coordinate assigned directly, and title is set by calling a setter?
Header File
#interface BNRMapPoint : NSObject<MKAnnotation>
-(id)initWithCoordinate:(CLLocationCoordinate2D )c title:(NSString *)t;
#property(nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#end
Implementation File
-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if(self){
coordinate = c;
[self setTitle:t];
}
return self;
}
Two reasons, the most important of which is that there is no setter for the coordinate property. It's declared read-only, so there is only a getter method generated.
The second is that CLLocationCoordinate2D is a struct, not an object. There are memory management actions (copying, in this case) that have to be taken for the title object; the simplest way to make that happen is to use the already-existent setter method. The compiler takes care of moving the data for a POD type like CLLocationCoordinate2D.
If the second were the only reason, however, this would be a poor decision -- that's bad style to use the setter for one property and not for the other.
There is a school of thought that says you should copy NSStrings. They're invoking the setter on the string to get that copy. However, there's no need to copy (or even retain) the coordinate, as Josh points out.

Is there any reason to declare ivars if you're using properties exclusively in Objective-C?

I tend to use properties exclusively in my classes, especially now that you can declare properties in a class extension thanks to the modern Objective-C 2.0 runtime—I use this feature to create "private" properties.
My question is if there is any good reason to ever declare ivars in a class interface anymore. I prefer my public-facing interfaces to be as minimal and clean as possible, only revealing aspects of my class that are pertinent.
For example, I would tend to do the following:
MyClass.h:
#interface MyClass : NSObject
#property (nonatomic, copy) NSString * publicString;
#property (nonatomic, copy, readonly) NSString * readOnlyString;
#end
MyClass.m:
#interface MyClass ()
#property (nonatomic, copy, readwrite) NSString * readOnlyString;
#property (nonatomic, copy) NSString * privateString;
#end
#implementation MyClass
#synthesize publicString = publicString_;
#synthesize readOnlyString = readOnlyString_;
#synthesize privateString = privateString_;
- (void)init
{
self = [super init];
if (self != nil)
{
self.publicString = #"Public String";
self.readOnlyString = #"Read-Only String";
self.privateString = #"Private String";
}
return self;
}
- (void)dealloc
{
[publicString_ release];
[readOnlyString_ release];
[privateString_ release];
[super dealloc];
}
#end
Code style preferences aside, are there any issues with avoiding ivars entirely like this?
I may have found an answer that's suitable enough for me to explicitly back my properties with ivars. It doesn't appear as if the debugger will list any automatically synthesized ivars, so there's no way to just drill through self during debugging and check various values other than manually calling the property accessors, which is tedious. Unless they change this, this is probably more than enough reason for me to just go back to declaring ivars explicitly.
The main issue, if it bothers you at all, is that per Cocoa With Love, dynamic instance variables such as those you're using aren't supported by runtimes other than those for 64bit Intel/PowerPC (fixed per Chuck's comment below) and ARM (for iOS).
I'm not currently able to find an authoritative Apple document on the issue; note that restricting to the latest OS X, v10.6, is not sufficient since it is available for and supported on the 32bit Intel machines that Apple shipped immediately after switching from PowerPC.
Late extra thought: without knowing about any potential changes in Xcode 4, a good reason to declare otherwise private instance variables within the header file is to mark them as IBOutlets and wire them up graphically. That's really only relevant to a very specific type of class and member variable though, admittedly.
I have to agree with LucasTizma on the debugging issue.
When I began using XCode4, I started not explicitly declaring ivars and let them be created for me using #synthesize aVar = _aVar syntax. While trying to debug code, I noticed that I couldn't hover the cursor over the variable and see its value.
For me, this is just unacceptable. I guess it's back to declaring them explicitly.
Beyond Tommy's concern, declaring an ivar is certainly good practice, especially if your code might be reused or if you might come back to your code sometime.

Objective-C setter/getter naming conventions drive me mad?

I have been trying to understand something for several hours and I would like to get your point of view.
I have setter/getter on one of my class properties (I noticed that I MUST add "set" in front of the setter name else the compiler says that there is no setter):
#property (nonatomic, retain, readwrite, setter=setTopString:, getter=TopString) NSString* m_topString;
When I call the setter like this, the compiler is happy:
[secureKeyboardController setTopString:#"This action requires that your enter your authentication code."];
But when I try to use the "dot" convention, then I am rejected by the compiler:
secureKeyboardController.topString = #"This action requires that your enter your authentication code.";
What is really weird is that the dot naming convention works fine with this property:
#property (nonatomic, readwrite, getter=PINMaxLength, setter=setPINMaxLength:) NSInteger m_PINMaxLength;
In this case i can do:
[secureKeyboardController setPINMaxLength:10];enter code here
or
secureKeyboardController.PINMaxLength = 10;
In both cases, the compiler is happy.
I really would like to fall asleep tonigh less stupid than I currently feel now. Thus any explanation would be greatly appreciated.
Regards,
Apple92
What you're doing is declaring properties as if you were declaring instance variables. You should not be using the names in the getter and setter attributes on the #property declaration with dot syntax; that it happens to be working now is not - so far as I know - by design.
The property should be what you use with dot syntax. For some reason - unfamiliarity with Cocoa coding conventions, I expect - you named your properties m_topString and m_PINMaxLength. That means you should use them as someObject.m_topString and someObject.m_PINMaxLength.
If you want to use those names for the instance variables that you've decided to use for the properties' backing storage, you should declare that in the #synthesize directive instead.
This is how your class should look, to be more in line with regular Cocoa and Objective-C coding conventions:
#interface SomeClass : NSObject {
#private
NSString *m_topString;
}
#property (nonatomic, readwrite, copy) NSString *topString;
- (id)initWithTopString:(NSString *)initialTopString;
#end
#implementation SomeClass
#synthesize topString = m_topString;
// this says to use the instance variable m_topString
// for the property topString's storage
- (id)initWithTopString:(NSString *)initialTopString {
if ((self = [super init])) {
m_topString = [initialTopString copy];
// use the ivar directly in -init, not the property
}
return self;
}
- (void)dealloc {
[m_topString release];
// use the ivar directly in -dealloc, not the property
[super dealloc];
}
- (NSString *)description {
return [NSString stringWithFormat:#"SomeClass (%#)", self.topString];
// elsewhere in your class, use the property
// this will call through its getter and setter methods
}
#end
You are trying to fight the compiler, and the compiler fights back.
You are trying to declare a property named m_topString with setter setTopString and getter TopString, and that is plainly stupid. You are writing Objective-C code, not C++. Your code will be a maintenance nightmare (unless the next maintainer is just sensible and changes your code to Objective-C conventions).
Do yourself a favour, start writing Objective-C code. Just call the property topString, don't pick your own names for the setter and getter, don't pick your own names for the instance variable, and everything works just fine.
Capitalize the T in TopString, i.e. secureKeyboardController.TopString
I'm 90% sure that will fix your problem.