Crystal
Crystal

Reputation: 29518

Private properties and methods in Objective-C

In looking at one of Apple's examples, in the TableViewController.m, they have this:

// Private TableViewController properties and methods.
@interface TableViewController ()

@property (nonatomic, retain) NSMutableArray* sectionInfoArray;
@property (nonatomic, retain) NSIndexPath* pinchedIndexPath;
@property (nonatomic, assign) NSInteger openSectionIndex;
@property (nonatomic, assign) CGFloat initialPinchHeight;
... more properties and methods
@end

@implementation TableViewController
... usual stuff

I'm wondering why they put these properties in the .m file and how this is private. It seems like anyone who imports the TableViewController.m file can use these properties and methods right? Why not use the @private in the .h file?

Upvotes: 6

Views: 465

Answers (7)

Steven Fisher
Steven Fisher

Reputation: 44886

They're not private. They're anonymous properties, since they're part of an anonymous category.

One of the things properties are good for is putting the memory management semantics for an owned object in a single place. Consider this:

@property (nonatomic, assigned) NSString *assigned;
@property (nonatomic, copy) NSString *copied;
@property (nonatomic, retain) NSString *retained;

In all three cases, you can assign to them like this without knowing what their memory semantic is:

self.assigned = stringParameter; // assigns to instance variable
self.copied = stringParameter; // copies, assigns copy to instance variable
self.retained = stringParameter; // retains, assigns to instance variable

And in all three cases, you can free clean up using the same code:

self.assigned = nil; // this just nils the instance variable
self.copied = nil; // releases copy in ivar, nils instance variable
self.retained = nil; // releases ivar (same as original object),
                     // nils instance variable

This is why you'll often see local properties: It lets the coder skip writing all the memory management logic each time they want to assign to the instance variable. This is a major advantage in that you can change the memory management logic throughout the entire class just by changing the @property.

Another use of anonymous properties is to extend a property declared as readonly to outside code as read/write to the class itself.

In .h:

@property (nonatomic, readonly, retain) NSError *lastError;

In .m, in an anonymous category:

@property (nonatomic, readwrite, retain) NSError *lastError;

Elsewhere in .m code:

self.lastError = error;

Again, this is mostly done for memory management reasons.

An example, that pertains to either use of anonymous properties.

Here's what each assignment to a _lastError instance variable looks like without properties.

Assume we have a NSError called _lastError defined in the .h file.

With retain:

[_lastError release];
_lastError = [error retain];

With copy:

[_lastError release];
_lastError = [error copy];

With assign:

_lastError = error;

In the first two cases, you need this in your dealloc:

[_lastError release];

But in the last case, you must put nothing in the dealloc or you'll get a crash.

So let's add what we need to use a property instead:

Add this in an anonymous category:

@property (nonatomic, readwrite, retain) NSError *lastError;

Add this in the @implementation:

@synthesize lastError = _lastError;

Note, also, that at this point on the "modern" Cocoa runtime (64 bit Mac or iOS), you can remove the NSError *_lastError from your header. The compiler can figure out you want that based on the @synthesize.

Here's how that changes our code:

Each assignment:

self.lastError = error; // works regardless of storage specifier

In daelloc:

self.lastError = nil; // works regardless of storage specifier

Upvotes: 3

Jhaliya - Praveen Sharma
Jhaliya - Praveen Sharma

Reputation: 31730

you can't import the implementation file TableViewController.m, Only the .h file of TableViewController could be imported,

Although, you could have the reference of these property outside your TableViewController class with a warning that shows the "not respond" note.

Upvotes: 0

Carter
Carter

Reputation: 3093

There are no private methods or variables in objective c, the @private flag is mainly there just so when other developers look at it, they know it's supposed to be private. What your seeing in the apple code is an example of a category, a way to fake private methods and variables in objective c. Because outside classes will import the .h file only, they will never see the added methods and variables in the .m file.

Upvotes: 1

Seva Alekseyev
Seva Alekseyev

Reputation: 61398

First, you typically cannot import an .m file - not without numerous compiler/linker errors. Second, the properties are private so that Apple is free to change them in subsequent releases.

Yes, you can get to them via reflection. But that's a slippery slope, blah blah proceed at your own risk, will break in later versions blah blah reflection bad unless you know exactly what you're doing.

Upvotes: 1

justadreamer
justadreamer

Reputation: 2450

AFAIK

a) You can not mark properties as @private in .h - this works only for ivars.

b) You will not be able to reference your class if you just import .m file (without interface definition in .h file). and if you do - you will get duplicate symbols during linking.

c) So yes these properties are private in the sense they are not accessible as regular properties from outside - these properties are accessible only using explicit messages - however you'll get warnings from compiler in this case or you could use KVC

Upvotes: 2

Toastor
Toastor

Reputation: 8990

What they're doing is declaring a category on the class, but since this is done in the .m file, the effect is that those methods are "invisible".

This doesn't mean however that those methods cannot be called from the outside. This is due to the fact that there is no real privacy in objective c, because we're dealing with messages, not method calls. This means you can send an object a message even if you do not know if that object actually implements the method you're trying to call. The receiving object will determine at runtime if it can handle this call, maybe it will even forward it, and it will make no difference whether the method was known to the calling object or not.

This is one of the reasons why it is possible to call private APIs and get rejected for it.

Upvotes: 4

Peter DeWeese
Peter DeWeese

Reputation: 18343

Using an anonymous category black boxes internal properties and methods that other classes should not know about. Although the compiler doesn't know about them when this class is referenced from other classes, you could technically access any of these properties from that other class using key value coding.

Upvotes: 0

Related Questions