Is there any reason to declare ivars if you're using properties exclusively in Objective-C? - 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.

Related

Synthesis and Protected Instance Variables in "Modern" Objective-C?

I want to create a class that serves as a base (or "abstract") class to be extended by subclasses. The best way I can explain what I'm talking about is with a few examples. Here's a possible interface for my superclass:
#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"
#interface MyViewController : NSViewController
#property (nonatomic, weak) id<MyViewModeControllerDelegate> delegate;
#property (nonatomic, copy) NSArray *content;
#end
Writing it like that seems nice and clean, but I can't access the ivars from my subclasses.
After doing some research, I've concluded that a good way to provide subclasses with direct access to ivars is to use the #protected directive and include any declarations in the header file so subclasses can see it:
#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"
#interface MyViewController : NSViewController {
#protected
__weak id<MyViewControllerDelegate> _delegate;
NSMutableArray *_content;
}
#property (nonatomic, weak) id<BSDViewModeControllerDelegate> delegate;
#property (nonatomic, copy) NSArray *content;
#end
I personally don't have an issue with that, and it seems to work the way I want it to (e.g. subclasses can access the ivars directly, but other classes have to use accessors). However, I read blog posts or Stack Overflow answers every day that say instance variables should just be synthesized, or "I don't even touch instance variables anymore."
The thing is, I started learning Objective-C post-ARC, so I'm not fully aware of the ways in which developers had to do things in the past. I personally like the control I have when I implement my own getters/setters, and I like being able to actually see instance variable declarations, but maybe I'm old school. I mean, if one should "just let the compiler synthesize the instance variables," how does one include any sort of logic or "side effects" without implementing a bunch of KVO?
For example, if my instance variables and getters/setters are synthesized, how do I initialize stuff lazily? For example, I sometimes like to do this:
- (NSArray *)myLazyArray
{
if ( _myLazyArray == nil ) {
self.myLazyArray = #[];
}
return _myLazyArray.copy;
}
Or how do I make sure that a value being set isn't the same as the currently set value? I'll sometimes implement a check in my mutator method like this:
- (void)setMyLazyArray:(NSArray *)array
{
if ( [array isEqualToArray:_myLazyArray] )
return;
_myLazyArray = array.mutableCopy;
}
I've read all of Apple's documentation, but half their docs date back to 2008 (or worse in some cases), so I'm not exactly sure they're the best place to get information on the matter.
I guess the gist of my question is this: Is there a preferred "modern" way of handling instance variables, variable synthesis, inheritance, scope, etc. in Objective-C? Bonus points for answers that don't include "Bro, Swift." or "You aren't using Swift?"
Any guidance would be much appreciated. Thanks for reading!
Why do your subclasses need access to your ivars? Ivars are an implementation detail and subclasses shouldn't be concerned with that. There could be all sorts of side effects if the parent class is doing logic in the property setter/getters. Therefore, always access them through the property.
Assuming this is in your subclass and you are overriding a property getter:
- (NSArray *)myLazyArray
{
if ( super.myLazyArray == nil ) {
// do what you need to do to populate the array
// assign it to yourself (or super)
self.myLazyArray = #[];
}
return super.myLazyArray;
}
And then for the setter:
- (void)setMyLazyArray:(NSArray *)array
{
if ( [array isEqualToArray:super.myLazyArray] )
return;
super.myLazyArray = array.mutableCopy;
}

My understanding of instance variables

I think I've been using Objective-C properties incorrectly. Specifically, I've been treating them like instance variables.
Here's an example of a recent interface:
// AIClass.h
#import "AIDataUtils.h"
#interface AIViewController : UIViewController
#property (strong, nonatomic) AIDataUtils *dataUtils;
#end
Then, in my implementation, I would use self.dataUtils as a way for any method in the class to easily access the same thing. No object from the outside would ever be interacting with that property.
What I'm realizing is that what I should have been doing is importing and declaring AIDataUtils in the implementation and not the interface. I think that would look like this:
// AIClass.m
#import "AIDataUtils.h"
#interface AIViewController ()
{
AIDataUtils *dataUtils;
}
#end
#implementation AIViewController
- (void)viewDidLoad
{
[super viewDidLoad];
dataUtils = [[AIDataUtils alloc] init];
...
}
The docs say:
Avoid explicitly declaring public instance variables. Developers should concern themselves with an object’s interface, not with the details of how it stores its data.
My understanding here is if another object has no business touching AIDataUtils, don't put it in the interface. The fact that a property exists in an interface should be a hint that you're supposed to feed or do something with that property.
Am I hot or cold?
My understanding here is if another object has no business touching AIDataUtils, don't put it in the interface.
You're right, but that doesn't mean that you can't keep using properties for internal values too -- just don't declare them in your public interface. Usually, using a class extension as you've suggested is a fine way to have your properties while still keeping internal things (more or less) private.
There was a period in the evolution of Objective-C when properties were very helpful in managing memory -- if you used a property's accessors everywhere, you could worry a lot less about when to retain and when to release something because the accessors would do that for you. Now that we have ARC, the memory management aspect of properties is less important, but a lot of us are still conditioned to use properties even for internal stuff. If nothing else, internal-only properties can make your code a little more consistent-looking.
If you intend dataUtils to be a private implementation detail, then you shouldn't declare it in the #interface in the header file.
Even if you want to keep it private, you can still make it a property in the .m file:
#interface AIViewController ()
#property (strong, nonatomic) AIDataUtils *dataUtils;
#end
Whether to make it a property or just an instance variable is a matter of taste and depends on how you use it. For example, if you only want to allocate the AIDataUtils instance lazily, you might as well make it a property and do the lazy allocation in the getter.
If you decide to make it an instance variable, there's probably no reason to declare it in a class extension. You can just declare it in the #implementation:
#implementation AIViewController {
AIDataUtils *dataUtils;
}
- (void)viewDidLoad {
[super viewDidLoad];
dataUtils = [[AIDataUtils alloc] init];
...
You can learn more about where to declare instance variables in this answer.

Accessing Objects from Class or Method

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)

Do I need to declare a property in the instance variables section, too? What do I gain?

I read some tutorials here about properties ,but i still have some doubts to clarify, is there a difference between
#interface MyClass : NSObject {
}
#property(nonatomic,retain) NSString *temp;
#end
AND
#interface MyClass : NSObject {
NSString *temp;
}
#property(nonatomic,retain) NSString *temp;
#end
The difference is that in the first version, the compiler will automatically create an instance variable (IIRC, it will be named _temp but I don't know for sure). This is only supported on iOS and Mac 64 bit.
In the second example, you provide the variable.
There's actually a way to tell the compiler which variable to use for the property, which I use a lot:
#interface MyClass : NSObject {
NSString *temp_;
}
#property(nonatomic,retain) NSString *temp;
#end
#implementation MyClass
#synthesize temp = temp_;
#end
This way the variable and the property have different names and you can't confuse them (e.g. by forgetting to prefix self.).
Minor side-note: it's often desirable to use copy instead of retain for NSString *, since you might assign an NSMutableString * to the property. Now if you would change that mutable string unexpected things might happen.
Does the first one even work? If there is no instance variable its a bit hard to have a property to access it.
#properties are meant for you, so you can be lazy, they write the following 2 methods for you ( if not set to readonly ):
- (void)setYourVariable:(id)new;
- (id)yourVariable;
it also allows you to use "someClass.itsVariable;" instead of "[someClass itsVariable];"
Another thing, when you create your header files make sure that the biggest variables ( like pointers ) are on the top and the smallest on the bottom, this saves ram.
thus:
NSObject *someObject;
NSObject *someOtherObject;
int anInt;
short aShort;
BOOL fakeBool;
instead of:
BOOL fakeBool;
NSObject *someObject;
short aShort;
NSObject *someOtherObject;
int anInt;
This has to do with the compiler, you can check this by using sizeof()
In the modern runtime (Objective-C 2.0) it is the same because the compiler will generate the variable for you. See Question about #synthesize
Quoting The Objective-C Programming Language > Declared Properties > Property Implementation Directives:
There are differences in the behavior of accessor synthesis that
depend on the runtime:
For the legacy runtimes, instance variables must already be declared in the #interface block of the current class. If an instance
variable of the same name as the property exists, and if its type is
compatible with the property’s type, it is used—otherwise, you get a
compiler error.
For the modern runtimes, instance variables are synthesized as needed. If an instance variable of the same name already exists, it is
used.
The practical difference that I've found is that the debugger doesn't appear to show you the value of properties, just instance variables.
Therefore, your first example, which (assuming you use the #synthesize directive to create your getter/setter) automatically creates the ivar, will not have a value that you can easily retrieve during debug. You'll end up having to send a lot of NSLog messages, rather than just looking at the values while stepping through your code.
As an aside, which seems to relate to this topic, I typically prepend my ivars with "iv" and change my color settings in XCode preferences so that I'm never unsure whether I'm accessing a property or an ivar.
Example
#interface MyClass : NSObject {
NSString *ivName;
NSString *ivTitle;
}
#property (nonatomic, copy) NSString *Name;
#property (nonatomic, copy) NSString *Title;
#end
Now, this then requires a small trick (to tie the two together) when synthesizing the properties, which I show below:
#implementation MyClass
#synthesize Name = ivName;
#synthesize Title = ivTitle;
This way, it's always very easy for me to know exactly what's going on at a glance. Yes, context can also tell you whether you're accessing an ivar/property, but why not make it easier?

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.