How do I make methods only available to properties in Obj-C? - objective-c

I'm still new to Objective-C and I recently learned how to make properties, so far so good, but one thing that bothers me is that the setter and getter methods are still publicly available even after the property is made.
let's say I have the following code:
// myClass.h
#interface myClass : NSObject {
int _startPos;
}
#property (assign, readwrite, setter = setStartPos:, getter = getStartPos) int startPos;
-(void) setStartPos: (int) pos;
-(int) getStartPos;
#end
the implementation file should be rather self-explanatory, I'm not trying to do anything specific.
Now, I read somewhere, and tried it in practice that if you make a category in the implementation file, and add some methods to that, it's possible to make those methods invisible (aka private) to things outside of the myClass.m file.
"Alright" I think, and decide to try it out:
//myClass.m
#import <Foundation/Foundation.h>
#import "myClass.h"
#interface myClass (hidden)
-(void) setHiddenStartPos: (int) hPos;
-(int) getHiddenStartPos;
#end
#implementation myClass (hidden)
-(void) setHiddenStartPos: (int) hPos {
_startPos = hPos;
}
-(int) getHiddenStartPos {
return _startPos;
}
#end
#implementation myClass
-(void) setStartPos: (int) Pos {
[self setHiddenStartPos: Pos];
}
-(int) getStartPos {
return [self getHiddenStartPos]; //this is to see if I can get the value from the hidden methods through the non-hidden ones
}
#end
that's all fine, and testing it in main() I can see that the methods with "hidden" in their name are in fact inaccessible, and therefore act as if they are private.
Then I tried to add this to the header file:
#property (assign, readwrite, setter = setHiddenStartPos:, getter = getHiddenStartPos) int
to see if I could access the hidden methods through the property
but when I did that, the hidden methods became accessible in main() and the whole plan with making the methods only accessible through the property went down the drain
So I ask you, is there a way to make methods inaccessible to anything BUT the property and/or the object itself?
Edit: I realize that getters don't usually have get in the name, so please stop commenting on it?
also to emphasise what I meant:
I wanted to make properties like in c#, where the content of the setters and getters are private to the property itself
public int exampleProperty
{
set{...}
get{...}
}
it doesn't use methods as getters and setters, and therefore the code in the setters and getters are accessible to only the property, JUST like the code within a method is local to the method itself

Add a class continuation in your .m file. i.e.:
#interface myClass ()
#property (assign, readwrite, setter = setHiddenStartPos:, getter = getHiddenStartPos) int hiddenStartPos;
#end
#implimentation myClass
#synthesize hiddenStartPos = _hiddenStartPos;
...
#end
Have a look at: What is an Objective-C "class continuation"?
PS: Your getters should just be hiddenStartPos rather than getHiddenStartPos...

It seems to me that the your confusion comes from misunderstanding exactly what an #property declaration is. It is essentially a declaration that setter and getter methods exist.
So, this
#property int hiddenStartPos;
is the same as this
- (int)hiddenStartPos;
- (void)setHiddenStartPos;
So, the implementation of these two methods is the implementation of the property. By decaring the property in the .h file, you're advertising to anyone who imports the .h that the class in question implements these two methods (the getter and the setter, respectively).
I also want to reemphasize that getter methods should not be prefixed with "get" in Objective-C.

You're over-thinking what "private" means. In ObjC, "private" just means "not visible." It doesn't mean "not callable." The way you make a method private is to not put it in your .h file, which declares your public interface.
There is no way to control who passes a message. This is a key fact of ObjC and cannot (and should not) be changed. ObjC is a dynamic language. At runtime, I am free to generate selectors and call performSelector: on any object I want. Anything that stopped that would either (a) introduce significant performance penalties, or (b) break many very useful and common techniques in ObjC (probably both). ObjC is not Java or C#. It's not even C or C++. It's Smalltalk on top of C. It's a highly dynamic language and that has a lot of strengths. Unlearning other languages is the first step towards becoming a good Cocoa developer.
It would be nice to have a compiler-checked #private for methods (of which properties are just a special case), and it would especially be awesome to have a compiler-checked #protected for methods (these exist for ivars). These would make it slightly simpler to avoid some kinds of mistakes. But that's the only way you should be thinking about this. The goal is not to protect one part of the code from another part of the code. The other code is not the enemy. It's all written by people who want the program to work. The goal is to avoid mistakes. Correct naming, consistency, and the absolute elimination of warnings is how you achieve that in ObjC.
So yes, I'd love to be able to put #protected in front of my #property declarations occasionally. Today you can't, and there is no real equivalent (I sometimes use a +Protected category in a separate header, but it's generally more trouble than its worth). But that said, having it wouldn't change very much, and I only find a case where I would even use this a few times a year. I can't think of single case where #private for a method would have been really useful, though.

Related

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.

Where to put iVars in "modern" Objective-C?

The book "iOS6 by Tutorials" by Ray Wenderlich has a very nice chapter about writing more "modern" Objective-C code. In one section the books describes how to move iVars from the header of the class into the implementation file.
Since all iVars should be private this seems to be the right thing to do.
But so far I found 3 ways of doing so. Everyone is doing it differently.
1.) Put iVars under #implementantion inside a block of curly braces (This is how it is done in the book).
2.) Put iVars under #implementantion without block of curly braces
3.) Put iVars inside private Interface above the #implementantion (a class extension)
All these solutions seems to work fine and so far I haven't noticed any difference in the behavior of my application.
I guess there is no "right" way of doing it but I need to write some tutorials and I want to choose only one way for my code.
Which way should I go?
Edit: I am only talking about iVars here. Not properties. Only additional variables the object needs only for itself and that should not be exposed to the outside.
Code Samples
1)
#import "Person.h"
#implementation Person
{
int age;
NSString *name;
}
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = #"Holli";
}
return self;
}
#end
2)
#import "Person.h"
#implementation Person
int age;
NSString *name;
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = #"Holli";
}
return self;
}
#end
3)
#import "Person.h"
#interface Person()
{
int age;
NSString *name;
}
#end
#implementation Person
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = #"Holli";
}
return self;
}
#end
The ability to put instance variables in the #implementation block, or in a class extension, is a feature of the “modern Objective-C runtime”, which is used by every version of iOS, and by 64-bit Mac OS X programs.
If you want to write 32-bit Mac OS X apps, you must put your instance variables in the #interface declaration. Chances are you don't need to support a 32-bit version of your app, though. OS X has supported 64-bit apps since version 10.5 (Leopard), which was released over five years ago.
So, let's assume you are only writing apps that will use the modern runtime. Where should you put your ivars?
Option 0: In the #interface (Don't Do It)
First, let's go over why we don't want to put instance variables in an #interface declaration.
Putting instance variables in an #interface exposes details of the implementation to users of the class. This may lead those users (even yourself when using your own classes!) to rely on implementation details that they should not. (This is independent of whether we declare the ivars #private.)
Putting instance variables in an #interface makes compiling take longer, because any time we add, change, or remove an ivar declaration, we have to recompile every .m file that imports the interface.
So we don't want to put instance variables in the #interface. Where should we put them?
Option 2: In the #implementation without braces (Don't Do It)
Next, let's discuss your option 2, “Put iVars under #implementantion without block of curly braces”. This does not declare instance variables! You are talking about this:
#implementation Person
int age;
NSString *name;
...
That code defines two global variables. It does not declare any instance variables.
It's fine to define global variables in your .m file, even in your #implementation, if you need global variables - for example, because you want all of your instances to share some state, like a cache. But you can't use this option to declare ivars, because it doesn't declare ivars. (Also, global variables private to your implementation should usually be declared static to avoid polluting the global namespace and risking link-time errors.)
That leaves your options 1 and 3.
Option 1: In the #implementation with braces (Do It)
Usually we want to use option 1: put them in your main #implementation block, in braces, like this:
#implementation Person {
int age;
NSString *name;
}
We put them here because it keeps their existence private, preventing the problems I described earlier, and because there's usually no reason to put them in a class extension.
So when do we want to use your option 3, putting them in a class extension?
Option 3: In a class extension (Do It Only When Necessary)
There's almost never a reason to put them in a class extension in the same file as the class's #implementation. We might as well just put them in the #implementation in that case.
But occasionally we might write a class that's big enough that we want to divide up its source code into multiple files. We can do that using categories. For example, if we were implementing UICollectionView (a rather big class), we might decide that we want to put the code that manages the queues of reusable views (cells and supplementary views) in a separate source file. We could do that by separating out those messages into a category:
// UICollectionView.h
#interface UICollectionView : UIScrollView
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
#property (nonatomic, retain) UICollectionView *collectionViewLayout;
// etc.
#end
#interface UICollectionView (ReusableViews)
- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;
- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
- (id)dequeueReusableSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
#end
OK, now we can implement the main UICollectionView methods in UICollectionView.m and we can implement the methods that manage reusable views in UICollectionView+ReusableViews.m, which makes our source code a little more manageable.
But our reusable view management code needs some instance variables. Those variables have to be exposed to the main class #implementation in UICollectionView.m, so the compiler will emit them in the .o file. And we also need to expose those instance variables to the code in UICollectionView+ReusableViews.m, so those methods can use the ivars.
This is where we need a class extension. We can put the reusable-view-management ivars in a class extension in a private header file:
// UICollectionView_ReusableViewsSupport.h
#interface UICollectionView () {
NSMutableDictionary *registeredCellSources;
NSMutableDictionary *spareCellsByIdentifier;
NSMutableDictionary *registeredSupplementaryViewSources;
NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}
- (void)initReusableViewSupport;
#end
We won't ship this header file to users of our library. We'll just import it in UICollectionView.m and in UICollectionView+ReusableViews.m, so that everything that needs to see these ivars can see them. We've also thrown in a method that we want the main init method to call to initialize the reusable-view-management code. We'll call that method from -[UICollectionView initWithFrame:collectionViewLayout:] in UICollectionView.m, and we'll implement it in UICollectionView+ReusableViews.m.
Option 2 is flat out wrong. Those are global variables, not instance variables.
Options 1 and 3 are essentially identical. It makes absolutely no difference.
The choice is whether to put instance variables in the header file or the implementation file. The advantage of using the header file is that you have a quick and easy keyboard shortcut (Command + Control + Up in Xcode) to view and edit your instance variables and interface declaration.
The disadvantage is that you expose the private details of your class in a public header. That's not desirable is some cases, particularly if you're writing code for others to use. Another potential problem is that if you're using Objective-C++, it's good to avoid putting any C++ data types in your header file.
Implementation instance variables are great option for certain situations, but for most of my code I still put the instance variables in the header simply because it's more convenient for me as a coder working in Xcode. My advice is to do whatever you feel is more convenient for you.
Largely it has to do with the visibility of the ivar to subclasses. Subclasses will not be able to access instance variables defined in the #implementation block.
For reusable code that I plan to distribute (e.g. library or framework code) where I prefer not expose instance variables for public inspection, then I'm inclined to place the ivars in the implementation block (your option 1).
You should put instance variables in a private interface above the implementation. Option 3.
The documentation to read on this is the Programming in Objective-C guide.
From the documentation:
You Can Define Instance Variables without Properties
It’s best practice to use a property on an object any time you need to keep track of a value or another object.
If you do need to define your own instance variables without declaring a property, you can add them inside braces at the top of the class interface or implementation, like this:
Public ivars should really be declared properties in the #interface (likely what you're thinking of in 1). Private ivars, if you're running the latest Xcode and using the modern runtime (64-bit OS X or iOS), can be declared in the #implementation (2), rather than in a class extension, which is likely what you're thinking of in 3.

Objective-C: Compiler error when overriding a superclass getter and trying to access ivar

I'm working on building an iOS 6 app.
I have a class TDBeam which inherits from superclass TDWeapon.
The superclass TDWeapon declares a #property in the TDWeapon.h file:
#interface TDWeapon : UIView
#property (nonatomic) int damage;
#end
I do not explicitly #synthesize the property, as I'm letting Xcode automatically do so.
In the subclass TDBeam I override the getter in the TDBeam.m file:
#import "TDBeam.h"
#implementation TDBeam
- (int)damage {
return _damage;
}
#end
Xcode auto-completes the getter method name, as expected. But when I attempt to reference the _damage instance variable (inherited from the superclass), I get a compiler error:
Use of undeclared identifier '_damage'
What am I doing wrong here? I've tried explicitly adding #synthesize, and changing the name of the _damage ivar, but the compiler doesn't "see" it or any other ivars from the superclass. I thought ivars were visible and accessible from subclasses?
Synthesized ivars are not visible to subclasses, whether they are explicitly or automatically created: What is the visibility of #synthesized instance variables? Since they are effectively declared in the implementation file, their declaration isn't included in the "translation unit" that includes the subclass.
If you really want to access that ivar directly, you'll have to explicitly declare it (in its default "protected" form) somewhere that the subclass can see it, such as a class extension of the superclass in a private header.
There are a lot of posts on this topic on Stack Overflow, none of which offer simple concrete advice, but this topic sums it up most succinctly, and Josh's answer is the best in any.
What he kinda stops short of saying outright, is, if this is the kind of thing you want to do, don't use #property at all. Declare your regular protected variable in your base class as he says, and write you're own setters and getters if you need them. The ivar will be visible to any subclasses who can then write their own setters/getters.
At least that's where i've landed on the issue, although I'd a total newb to subclassing.
The idea of creating private headers to host your anonymous category and re-#sythesizing your ivars in your subclass just seems wrong on so many levels. I'm also sure I've probably missed some fundamental point somewhere.
Edit
Okay after some lost sleep, and inspired by Stanford's 2013 iTunes U course, here I believe is an example solution to this problem.
MYFoo.h
#import <Foundation/Foundation.h>
#interface MYFoo : NSObject
// Optional, depending on your class
#property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
#end
MYFoo.m
#import "MYFoo.h"
#interface MYFoo ()
#property (strong, nonatomic, readwrite) NSString * myProperty;
#end
#implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
if (!_myProperty) {
_myProperty = [self makeValueForNewMyProperty];
}
return _myProperty;
}
// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
// If this is an abstract base class, we'd return nil and/or throw an exception
NSString * newMyProperty = [[NSString alloc]init];
// Do stuff to make the property the way you need it...
return newMyProperty;
}
#end
Then you just replace makeValueForNewMyProperty in your subclass with whatever custom logic you need. Your property is 'protected' in the base class but you have control over how it is created, which is basically what you are trying to achieve in most cases.
If your makeValueForNewMyProperty method requires access to other ivars of the base class, they will, at the very least, have to be be public readonly properties (or just naked ivars).
Not exactly 'over-ridding a getter' but it achieves the same sort of thing, with a little thought. My apologies if, in trying to make the example generic, some elegance and clarity has been lost.

Proper way to perform additional code when setting properties

This might seem like a basic question but I'm still getting a handle on properties so please bear with me.
I have a custom NSView subclass that does its own drawing. I've set up support for different styles with a #property for setters and a typedef enum for human-readable integers. It works great, but the view won't redraw after setting its style unless I manually call setNeedsDisplay:YES on the control or resize its parent window.
Logically one would think the solution would be to simply do a [self setNeedsDisplay:YES] in the classes' setStyle: method, but I cannot for the life of me figure out how to properly do it. Whenever I try to override setStyle: it just complains, "Writable atomic property 'style' cannot pair a synthesized getter with a user defined setter".
What should be done in this situation?
Ideally, you would just declare your actual ivar/storage as a private property, then manually implement the setter setStyle:. In the implementation of setStyle:, set your private property/state, and perform your updates. So you just abstract the data from the client's interface. There are other ways to approach this, such as directly setting the ivar.
So an implementation may take the form:
MONThing.h
#interface MONThing : NSObject
- (void)setStyle:(t_style)pStyle; // << the client's interface
#end
MONThing.m
#interface MONThing ()
#property (nonatomic, assign, readwrite) t_style userStyle; // << the actual storage
#end
#implementation MONThing
- (void)setStyle:(t_style)pStyle
{
// validate parameter
// set our data
self.userStyle = pStyle;
// perform effects
[self setNeedsDisplay:true];
}
Over time, you will learn multiple ways to accomplish this, and when you would favor one over the other.
If you a setting your own setter then do not use #synthesize and #property. These are for automatic creation of the setter and getter methods. Declaring the variable in the interface file is enough.
Take a look at this question. To copy over the answer from the other question:
If you declare a #property to be atomic then do one of the following:
use #dynamic or;
use #synthesize and keep the synthesized setter and getter or;
provide a manual implementation of both the setter and the getter (without using one of the above directives).

What is the difference between ivars and properties in Objective-C

What is the semantic difference between these 3 ways of using ivars and properties in Objective-C?
1.
#class MyOtherObject;
#interface MyObject {
}
#property (nonatomic, retain) MyOtherObject *otherObj;
2.
#import "MyOtherObject.h"
#interface MyObject {
MyOtherObject *otherObj;
}
#property (nonatomic, retain) MyOtherObject *otherObj;
3.
#import "MyOtherObject.h"
#interface MyObject {
MyOtherObject *otherObj;
}
Number 1 differs from the other two by forward declaring the MyOtherObject class to minimize the amount of code seen by the compiler and linker and also potentially avoid circular references. If you do it this way remember to put the #import into the .m file.
By declaring an #property, (and matching #synthesize in the .m) file, you auto-generate accessor methods with the memory semantics handled how you specify. The rule of thumb for most objects is Retain, but NSStrings, for instance should use Copy. Whereas Singletons and Delegates should usually use Assign. Hand-writing accessors is tedious and error-prone so this saves a lot of typing and dumb bugs.
Also, declaring a synthesized property lets you call an accessor method using dot notation like this:
self.otherObj = someOtherNewObject; // set it
MyOtherObject *thingee = self.otherObj; // get it
Instead of the normal, message-passing way:
[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it
Behind the scenes you're really calling a method that looks like this:
- (void) setOtherObj:(MyOtherObject *)anOtherObject {
if (otherObject == anOtherObject) {
return;
}
MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
otherObject = [anOtherObject retain]; // put the new value in
[oldOtherObject release]; // let go of the old object
} // set it
…or this
- (MyOtherObject *) otherObject {
return otherObject;
} // get it
Total pain in the butt, right. Now do that for every ivar in the class. If you don't do it exactly right, you get a memory leak. Best to just let the compiler do the work.
I see that Number 1 doesn't have an ivar. Assuming that's not a typo, it's fine because the #property / #synthesize directives will declare an ivar for you as well, behind the scenes. I believe this is new for Mac OS X - Snow Leopard and iOS4.
Number 3 does not have those accessors generated so you have to write them yourself. If you want your accessor methods to have side effects, you do your standard memory management dance, as shown above, then do whatever side work you need to, inside the accessor method. If you synthesize a property as well as write your own, then your version has priority.
Did I cover everything?
Back in the old days you had ivars, and if you wanted to let some other class set or read them then you had to define a getter (i.e., -(NSString *)foo) and a setter (i.e., -(void)setFoo:(NSString *)aFoo;).
What properties give you is the setter and getter for free (almost!) along with an ivar. So when you define a property now, you can set the atomicity (do you want to allow multiple setting actions from multiple threads, for instance), as well as assign/retain/copy semantics (that is, should the setter copy the new value or just save the current value - important if another class is trying to set your string property with a mutable string which might get changed later).
This is what #synthesize does. Many people leave the ivar name the same, but you can change it when you write your synthesize statement (i.e., #synthesize foo=_foo; means make an ivar named _foo for the property foo, so if you want to read or write this property and you do not use self.foo, you will have to use _foo = ... - it just helps you catch direct references to the ivar if you wanted to only go through the setter and getter).
As of Xcode 4.6, you do not need to use the #synthesize statement - the compiler will do it automatically and by default will prepend the ivar's name with _.