4

Before so-called "Modern Objective-C", when creating a new property in category, we needed to implement setter and getter methods. Now, we don't have to do @synthesize; the compiler will automatically create the methods and an instance variable.

But normally, we cannot add instance variables to a category, so what happens if we add a new property in a category with modern Objective-C? Does the compiler create an ivar for us?

jscs
  • 63,694
  • 13
  • 151
  • 195
IPaPa
  • 368
  • 2
  • 12
  • 2
    @BoltClock I'm sure OP meant Objective-C 2.0 with all the nifty-gifty Clang extensions, such as automatic properties. –  Oct 16 '12 at 18:05
  • @BoltClock I expect that the OP was referring to the modern Obj-C runtime, though he/she is conflating a number of things here. The modern runtime came long before automatic property synthesis, for example. – Caleb Oct 16 '12 at 18:07
  • Apple started referring to current ObjC as "Modern" sometime around the introduction of ARC, I believe. One wonders what Post-Modern ObjC will look like. Hopefully not like Perl. @Bolt – jscs Oct 16 '12 at 18:07
  • @JoshCaswell: Years prior to ARC, actually. The "modern runtime" was introduced with 64-bit PowerPC support. – Jonathan Grynspan Oct 16 '12 at 18:10
  • @Johnathan: Unless I'm totally misremembering, they're not just talking about the 2.0 runtime -- there's language additions (the ones that H2CO3 mentions) that they've labelled "(even more) modern". I recall seeing this in WWDC videos from the past two years. – jscs Oct 16 '12 at 18:13
  • I'm thinking Objective-C was "modern" in about 1973. – Hot Licks Oct 16 '12 at 18:18
  • @JoshCaswell Yes, but the term is specifically used by Apple to refer to the "modern runtime" and the features it allows. – Jonathan Grynspan Oct 16 '12 at 18:27

3 Answers3

7

You can declare a property in a category, which is equivalent to declaring the getter and (if readwrite) setter selectors.

The compiler will not automatically synthesize the getter and setter methods in your category implementation. If you don't explicitly define them in the category implementation, the compiler will issue a warning. You can use @dynamic in the category implementation to suppress the warning. You cannot use @synthesize in the category implementation; the compiler will issue an error if you try.

The compiler will not add an instance variable for a property declared in a category. You cannot explicitly add instance variables in a category, and you can't trick the compiler into doing it using a property.

I tested my claims using Xcode 4.5.1 targetting iOS 6.0.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
1

Actually I don't know when we were able to add property in categories.

From Apple Docs:

A category allows you to add methods to an existing class—even to one for which you do not have the source.

and

Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main @implementation block for the corresponding class. Using the Clang/LLVM 2.0 compiler, you can also declare properties and instance variables in a class extension.

and this method is used to add storage to an object without modifying the class declaration (in case you couldn't modify or don't have access to source codes of class)

Associative references, available starting in OS X v10.6, simulate the addition of object instance variables to an existing class. Using associative references, you can add storage to an object without modifying the class declaration. This may be useful if you do not have access to the source code for the class, or if for binary-compatibility reasons you cannot alter the layout of the object.

So your question for me seems to be incorrect.

Source: Apple Docs - The Objective-C Programming Language

Nekto
  • 17,837
  • 1
  • 55
  • 65
0

As others have said, the way to do this is with Associative References. They are implemented much like CALayer's value / key-pair paradigm.. in that basically.. you can "associate" anything, with any "property", or "thing"…

So in your category header… if all you want to do is read a value…

@property (readonly) NSString *uniqueID;

and then write your getter…

- (NSString*) uniqueID { return @"You're not special"; }

But say.. you can't just come up with the value from within your getter.. and you need storage for either an external setter… or the class' own implementation to use… you HAVE to write a setter like...

- (void) setUniqueID:(NSString*)uId 

It need not be public, necessarily… but this is where the "magic" happens.

 …
[self setAssociatedValue:uId forKey:@"yourInternalStorageName"
                  policy:OBJC_ASSOCIATION_RETAIN_NONATOMIC];

I realized after looking at this, that I'm using some "personal categories" to help ease the setting and getting etc. of these values.. so I've posted them to this gist, as they are VERY useful.. and include such little gems as…

- (id) associatedValueForKey:(NSString*)key 
                     orSetTo:(id)anObject 
                      policy:(objc_AssociationPolicy) policy;

The secret to "getting it" is the "policy" portion.. These values…

OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403

capture the same "personality" traits as are expressed when describing your properties in a "normal" declaration. You must tell the compiler how to "store" your values with those same rules, and you'll be good to go.

Alex Gray
  • 16,007
  • 9
  • 96
  • 118