4

I know that we can't add instance variables in class category, but we can add in class-continuation, can some one tell me why or give me some detail about it. I know that we can use associate in category, I want to know the detail about the implementation cause this. Thanks a lot .

billwang1990
  • 627
  • 2
  • 6
  • 16
  • Maybe this will help http://stackoverflow.com/questions/10301661/what-is-an-objective-c-class-continuation – Popeye Apr 09 '14 at 09:06
  • The creator of Obj-C must have thought about this, as if you add an instance variable through a category then all the descendent class will get the same!!! But in case of class-continuation/extension it creates a private variable which will never get inherited. – Anoop Vaidya Apr 09 '14 at 09:27
  • @AnoopVaidya it's not a matter of inheritance. Adding ivars to an existing class would break all of its subclasses because it changes the class layout. This was true until 64-bit OSX and iPhone runtimes. – Gabriele Petronella Apr 09 '14 at 09:46

2 Answers2

6

tl;dr

Class extensions only modify classes you own, whereas categories can modify any existing class.

Adding ivars to existing classes can break binary compatibility in old runtimes (prior to iOS or OSX 64-bit), that's why is forbidden.

Adding methods does not suffer from this problem, since method resolution has always been dynamic.


discussion

Because class extensions (what clang calls class continuations) are not categories, although they have something in common.

From Apple documentation

A class extension bears some similarity to a category, but it can only be added to a class for which you have the source code at compile time (the class is compiled at the same time as the class extension). The methods declared by a class extension are implemented in the @implementation block for the original class so you can’t, for example, declare a class extension on a framework class, such as a Cocoa or Cocoa Touch class like NSString.

A class extensions extends the interface of a class at compile time: it's a simple matter of code organization and visibility (it is useful, for instance, to declare private properties).

You are simply breaking the @interface declaration into multiple parts, but you cannot add anything to an existing class which you don't own.

Adding an ivar is naturally supported for this reason. Roughly you can do:

@interface MyClass : NSObject {
    NSInteger a;
    NSInteger b;
}
@end

or

@interface MyClass : NSObject {
    NSInteger a;
}
@end

@interface MyClass() {
    NSInteger b;
}
@end

and it's almost equivalent (if you place the class extension in a private .m file then b will be private).

On the other hand, with a class category you can modify any class.

This is crucial, since when categories were designed, Objective-C had fragile base ivars.

What does it mean? It means that once a class is compiled, the ivars layout is fixed forever in the binary and you cannot modify it without breaking binary compatibility with any subclass of the class.

Therefore, adding an ivar to, say, NSObject would break (almost) every class in every Framework ever compiled.

Conversely, methods are dynamically resolved so you can safely add a method to an existing class, as long as you don't have name clashes.

The fragile ivar problem has been tackled since the first iOS (iPhone OS at the time) and 64-bit OSX with the use of dynamic ivars, but Objective-C cannot take advantage of this feature without breaking the compatibility with 32-bit Macs.


References

http://www.sealiesoftware.com/blog/archive/2009/01/27/objc_explain_Non-fragile_ivars.html http://www.cocoawithlove.com/2010/03/dynamic-ivars-solving-fragile-base.html

Community
  • 1
  • 1
Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
  • Minor remark: Definitions in a class extension are not necessarily private. You can define the class extension interface in a separate header file and include that from other files. (I just noted this because I got that wrong myself in a now deleted answer.) – Martin R Apr 09 '14 at 10:07
  • So, it seems that class extensions added at the compile time, category load in runtime, so category can binary compatibility but extension can not? – billwang1990 Apr 10 '14 at 01:51
  • And in your reference http://www.cocoawithlove.com/2010/03/dynamic-ivars-solving-fragile-base.html, it said in "modern" runtime, we have dynamic **ivars**, is that means we can add **ivars** in category? – billwang1990 Apr 10 '14 at 02:53
  • @billwang1990 as I said at the bottom of my answer, no. Allowding to add ivars in categories would break the compatibility with old runtimes, which is something the Objective-C designers decided not to do. But - technically - you could. – Gabriele Petronella Apr 10 '14 at 08:58
  • @billwang1990 the real point is that categories can add to existing (precompiled) classes, whereas extensions require the whole source code to be available at compile time, so the whole class is recompiled and it won't break. – Gabriele Petronella Apr 10 '14 at 09:00
-1

Simply because class extension is there to accomplish this job.

@interface SimpleClass : NSObject
@property int someProperty;
@end

@interface Foo()
@property float aNewProperty; // added through class extension 
@end

PS: Don't go on asking questions like this in Objective-C. Because Objective-C is different, and different here means really different. Have you ever seen Abstract or Protected keywords in Objective-C? No. Why? Objective-C is different.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
  • 2
    That's not an ivar, and the rest of the answer doesn't really say anything meaninful. The fact that Objective-C differs from Java, isn't really a reason not to ask questions. – Gabriele Petronella Apr 09 '14 at 09:29