Does Objective-C have an equivalent to java annotations? - objective-c

Does Objective-C have an equivalent to java annotations?
What's I'm trying to do is create a property and be able to somehow access some metadata about it.
I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.
//Put some sort of annotation giving a class name.
#property (strong) NSArray *myArray;

You said:
I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.
There are a few ways to do this sort of thing in Objective-C. Apple's frameworks do this sort of thing by adding a class method that returns the required information. Examples: dependent keys in KVO, +[CALayer needsDisplayForKey:] and related methods.
So, let's create a class method that returns an array of classes that can go into your container property, given the property name. First, we'll add a category to NSObject to implement a generic version of the method:
#interface NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name;
#end
#implementation NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if (class_getProperty(self, name.UTF8String)) {
return #[ [NSObject class] ];
} else {
[NSException raise:NSInvalidArgumentException
format:#"%s called for non-existent property %#", __func__, name];
abort();
}
}
#end
As you can see, this default version of the method doesn't do anything particularly useful. But adding it to NSObject means we can send the message to any class without worrying about whether that class implements the method.
To make the message return something useful, we override it in our own classes. For example:
#implementation MyViewController
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if ([name isEqualToString:#"myArray"]) {
return #[ [UIButton class], [UIImageView class] ];
} else {
return [super allowedClassesForContainerPropertyWithName:name];
}
}
...
We can use it like this:
SomeViewController *vc = ...;
SomeObject *object = ...;
if ([[vc.class allowedClassesForContainerPropertyWithName:#"bucket"] containsObject:object.class]) {
[vc.bucket addObject:object];
} else {
// oops, not supposed to put object in vc.bucket
}

There is no native support of this functionality, but you may to take a look at following solution — https://github.com/epam/lib-obj-c-attr/ It is compile time implementation of attributes. Definition of attributes based on defines but not on comments as in other solutions like ObjectiveCAnnotate.

Objective C does not support generics like in Java but ofcourse the language is very flexible that you can accomplish almost anything with simple tricks and knowledge. To implement a generic like feature you could create a category on NSArray class and create your own method to initialize the array and then check to see if the object is really the type of the object you want.
I would write a simple category on NSArray to have such functionality. Say suppose, I want my array to hold objects of class MyClass only then my category would look like,
#interface NSArray(MyCategory)
#end
#implementation NSArray(MyCategory)
-(NSArray*)arrayWithMyClasses:(NSArray*)classes{
if([classes count] > 0){
NSMutableArray *array = [[NSMutableArray alloc] init];
for(id anObj in classes){
NSAssert([anObj isKindOfClass:[MyClass class]], #"My array supports only objetcts of type MyClass");
[array addObject:anObj];
}
return array;
}
return nil;
}
#end
Of course, there is some limitations to it. Since you have created your own category, you should use your own method to initialize and create your own array.

No, Objective-C has no annotation or generics support.
A way to implement such a thing would be to hack Clang to read comments and associate a metadata object to the original object. But, you would be tied to your hacked compiler.
NSString *v1 = [[NSString alloc] init];
// associate
static char key;
NSString *v2 = [[NSString alloc] init];
objc_setAssociatedObject (
v1,
&key,
v2,
OBJC_ASSOCIATION_RETAIN
);
// retrieve
NSString *associate = (NSString *)objc_getAssociatedObject(v1, &key);
Qualifying with a protocol wouldn't be much trouble, and you could test if the collection implements it, but along the way you would need to create a category for each type on the same collection. This would require a different collection at compile time using macros. Overly complicated.
#interface Tomato:NSObject #end
#implementation Tomato #end
#protocol TomatoNSArray <NSObject>
- (Tomato*)objectAtIndexedSubscript:(NSUInteger)index;
- (void)setObject:(Tomato*)tomato atIndexedSubscript:(NSUInteger)index;
#end
// here is the problem, you would need to create one of this for each type
#interface NSMutableArray (TomatoNSArray) <TomatoNSArray>
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSMutableArray<TomatoNSArray> *tomatoes = [[NSMutableArray alloc] initWithCapacity:2];
tomatoes[0] = [Tomato new];
tomatoes[1] = [NSObject new]; // warning: incompatible pointer types
}
}

Does Objective-C have an equivalent to java annotations?
Not exactly an equivalent, but there is, and it's better. In Objective-C, the compiler has to store some type and name information in the compiled code (because the language is highly dynamic, a lot of things happen at runtime as opposed to compile time), for example method names ("selectors"), method type signatures, data about properties, protocols, etc. The Objective-C runtime library then has access to this data. For example, you can get the list of properties an object has by writing
id object = // obtain an object somehow
unsigned count;
objc_property_t *props = class_copyPropertyList([object class], &count);
Or you can check what class an object belongs to:
if ([object isKindOfClass:[NSArray class]]) {
// do stuff
}
(Yes, part of the runtime library is itself wrapped into some methods of NSObject for convenience, others only have C function APIs.)
If you specifically want to store custom metadata about an object or a class, you can do that using associated references.

I expect it should be clear now, the answer is NO, not at the moment.
Some people found some alternatives which seem to work in their specific use cases.
But in general there is no comparable feature yet in objective-c. IMHO clang metadata seems to provide a good foundations for this, but as long as there is not support from Apple this will not help, as far as i understood it.
Btw. I guess it should be clear, but just to repeat for all: two changes are required to support annotations as provided in java.
The language need an extension the annotate e.g. methodes, properites, classes, ... in the source code.
A standard interface is required to access the annotated information. This can only provide by apple.
Most alternativ soltuions move the annotation information into runtime and define their own interface. The objective-c runtime provide a standard interface but only with some trick you can annotate properties and still the isse of runtime population.
The typical use case for suche a feature is an IOC container (in Java e.g. Spring) which use the annotated information to inject other objects.
I would suggest to open an feature requrest for Apple to support this.

The answer to your question is that Objective-C does not have a direct equivalent of annotations as found in Java/C#, and though as some have suggested you might be able to engineer something along the same lines it probably is either far too much work or won't pass muster.
To address your particular need see this answer which shows how to construct an array which holds objects of only one type; enforcement is dynamic and not static as with parametric types/generics, but that is what you'd be getting with your annotation so it probably matches your particular need in this case. HTH.

What you need maybe a metadata parser for Objective-C. I have used ObjectiveCAnnotate (compile time retrievable) and ROAnnotation(runtime retrievable).

Related

Can NSUUID be extended by inheritance? How?

Recently (reviewing some code) I stumbled upon an oddity that results in a bug in our program.
An API we are using has the following implementation (that I am going to write in Swift, even though the original code is in Objective-C)
internal class MyUUID: NSUUID { }
Which is completely useless as it always returns an empty instance.
I am going to paste the code from my playground here for explanation purposes.
For example: creating a simple NSUUID would be something like this:
let a = NSUUID()
a.description //this creates a valid uuid
While creating a MyUUID should be similar
let b = MyUUID()
b.description //it returns an instance, but is completely empty.
But it doesn't work.
Inspecting a little bit more, reveals the NSUUID initialiser creates a __NSConcreteUUID instance, while MyUUID doesn't and it doesn't matter what I try to do, it won't create an appropriate UUID.
So, my question: Is it possible to be able to create a child implementation of NSUUID?
Your evidence would appear empirically to answer your own question: it's not possible. NSUUID would appear to be a class cluster rather than a single class, which effectively prevents subclassing.
An alternative idea to Aaron's:
Implement an object that has an NSUUID rather than that is one. Implement -forwardingTargetForSelector: and return your instance of NSUUID. Consider overriding -isKindOfClass:, but ideally don't unless you have to. Then you should be able to pass your class as though it were an NSUUID to anyone that expects one without their knowing the difference.
Given that the solution depends upon the fallback mechanism built into dynamic messaging, I suspect there's no Swift equivalent; however if you define your class as Objective-C then it should be equally usable from Swift.
You could use class_setSuperclass to change the superclass of MyUUID at runtime. This approach would be illegal in Swift, due to type safety, but you could still do it in Objective-C.
Depending on your actual goals you may be able to use CFUUIDRef instead.
As requested, here's an example of the class_setSuperclass approach. Just drop this in to a new single view project.
#import <objc/runtime.h>
#interface MyUUID : NSUUID
- (void) UUIDWithHello;
#end
#implementation MyUUID
- (void) UUIDWithHello {
NSLog(#"Hello! %#", self.UUIDString);
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Make a UUID that you want to subclass
NSUUID *uuid = [[NSUUID alloc] init];
NSLog(#"Initial UUID: %#", uuid.UUIDString);
// Ignore deprecation warnings, since class_setSuperclass is deprecated
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// Change MyUUID to inherit from the NSUUID's hidden subclass instead of NSUUID
class_setSuperclass([MyUUID class], [uuid class]); // [uuid class] is __NSConcreteUUID
// Turn deprecation warnings back on
#pragma GCC diagnostic pop
// Make a new myUUID and print it
MyUUID *myUuid = [[MyUUID alloc] init];
[myUuid UUIDWithHello];
}
#end
Note that this is a bit dangerous. If whatever secret subclass NSUUID has additional instance variables, it will require more memory, which [MyUUID alloc] won't request. This could cause a crash later when something requests these instance variables.
To get around this, you could instead instantiate your MyUUID instance like this:
NSLog(#"Initial UUID's class: %#", NSStringFromClass(uuid.class));
Class topSecretUUIDSubclass = uuid.class; // __NSConcreteUUID
MyUUID *myUuid2 = [[topSecretUUIDSubclass alloc] init];
[myUuid2 UUIDWithHello];
object_setClass(myUuid2, [MyUUID class]);
Basically this will make myUuid2 a __NSConcreteUUID and then change it to a MyUUID. However, this will only work if MyUUID doesn't add any instance variables.
If MyUUID does need to add its own instance variables, it will need to override +alloc to provide additional memory for these instance variables, using class_createInstance().

Is there a way to wrap protocol buffers into Objective-C and still take advantage of inheritance?

I want to use Protocol Buffers in an iOS project. I'm trying to avoid making the whole project into an Objective-C++ fiasco, so I want to wrap the C++ protobuf classes into Objective-C ones. I have several dozen protobuf messages, and while I have done this successfully one class at a time, ideally I would like to use inheritance to minimize the repeated code. I'm new to Objective-C and I haven't used what little I knew of C++ in 10 years, so this has mostly been an exercise in frustration. Below is an example of how I have wrapped a single message.
Code
.proto:
message MessageA {
optional string value = 1;
}
MessageAWrapper.h:
#import <Foundation/Foundation.h>
#interface MessageAWrapper : NSObject
#property (nonatomic) NSString *value;
+ (id)fromString:(NSString *)string;
- (NSString *)serialize;
#end
MessageAWrapper.mm:
#import "MessageA.h"
#import "message.pb.h"
#interface MessageAWrapper ()
#property (nonatomic) MessageA *message;
#end
#implementation MessageAWrapper
- (id)init
{
self = [super init];
if (self) {
self.message = new MessageA();
}
return self;
}
- (void)dealloc {
delete self.message;
self.message = NULL;
}
- (NSString *)value {
return [NSString stringWithUTF8String:self.message->value().c_str()];
}
- (void)setValue:(NSString *)value {
self.message->set_value([value UTF8String]);
}
- (NSString *)serialize {
std::string output;
self.message->SerializeToString(&output);
return [NSString stringWithUTF8String:output.c_str()];
}
+ (id)fromString:(NSString *)string {
MessageA *message = new MessageA();
message->ParseFromString([string UTF8String]);
MessageAWrapper *wrapper = [[MessageAWrapper alloc] init];
wrapper.message = message;
return wrapper;
}
#end
Goal
There is a lot of code here that will be repeated dozens of times in which the only variation is the wrapped class type (init, dealloc, serialize, fromString), so ideally I would like to put it on a parent ProtobufMesssage class instead. Unfortunately I've had no success in making this work because I can't find a way for the parent class to know the class its children are using, which is required for example in init and fromString.
Things I've attempted
struct
template class
void*
Obstacles I've encountered
can't find a way to store a reference to a class/type
can't have any C++ headers or code in the .h file (as this requires the whole project to be Objective-C++)
difficulty keeping references to the protobuf message parents (Message or MessageLite) because they are abstract
As I said I have very little understanding of C++ or Objective-C; most of my experience is with much higher level languages like Python and Java (though I do mostly understand basic C things like pointers).
Is this perhaps not even possible? Am I approaching it wrong or missing something obvious? Any help would be much appreciated. Thanks.
I don't know much about C++ at all, but can't you declare the Objective-C property to be a Message *?
You've already separated the C++ code from the header by declaring the property in the .mm file, the problem you will have is with instance methods named by the compiler (value() and set_value()) and only being valid methods for the subclass. It might help to use the Reflection class to get and set fields by their name. Here is an excerpt from Google's message.h showing this:
Message* foo = new Foo;
const Descriptor* descriptor = foo->GetDescriptor();
const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
assert(text_field != NULL);
assert(text_field->type() == FieldDescriptor::TYPE_STRING);
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
const Reflection* reflection = foo->GetReflection();
assert(reflection->GetString(foo, text_field) == "Hello World!");
You could create Objective-C -objectForKey: and -setObject:forKey: instance methods that typecheck and get or set the value (confusingly, the key in the case of MessageAWrapper would be #"value"). Your subclasses would not even need to be aware of the C++ code.
You can also separate the creator function in -init and +fromString: method into something like, +_createNewInstance;
+(Message*)_createNewInstance{ return new MessageA(); }
allowing your subclasses of MessageWrapper to reuse all code except for creating the C++ object.
While Objective C has very powerful instrospection capabilities, C++ is more limited. You do have RTTI (Run time type information), but it's not even as powerful as the Objective C counterpart.
However, it might be enough for you. Within your Objective C++ class, you might find the type of you message object with the typeid operator:
if( (typeid(self.message) == typed(foo)){
//doSomething
else if( (typeid(self.message) == typed(bar)){
// doSomething else
}
Maybe the best option is to add another indirection level. Make an Objective C class hierarchy that wraps all your protocol buffer C++ classes and then create another Objective C that uses those classes (as delegates maybe). I believe this might be a better option. Use C++ only for those unavoidable cases.
Good luck!

What is the actual use of categories instead of inheritance?

I'm trying to understand the actual use of categories as opposed to inheritance in Objective-C. When should I prefer to use a category? A real-life example with code would be helpful.
When you need to add functionality to an existing class.
For example, your app is working with NSDate or NSString instances and you want to add some functionality. You cannot add the functionality to a subclass because you can't force system methods to return the subclass.
Just look into the examples in the API:
1/ NSDictionary is used to hold file attributes and has a method that returns file size.
2/ NSString has a UI category that extends it with drawing. Note that you don't want a separate subclass of string that can be drawn. You want all strings to have the ability to be drawn.
I used categories when I need to add some convenient functions that I will use repeatedly to the existing class without having a need to subclass to overwrite some existing functions of that class.
For example, when I want to check for an empty string, or remove all leading and trailing spaces of a string:
.h file:
#interface NSString (Extension)
-(BOOL)isEmptyString;
-(NSString *)trimLeadingAndTrailingWhiteSpaces;
#end
.m file:
#implementation NSString (Extension)
-(BOOL)isEmptyString
{
NSString *myString = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (myString.length == 0)
return TRUE;
else
return FALSE;
}
-(NSString *)trimLeadingAndTrailingWhiteSpaces
{
NSString *myString = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return myString;
}
#end
To use it:
someString = [someString trimLeadingAndTrailingWhiteSpaces];
if ([someString isEmptyString])
{
//someString is empty, do whatever!
}
I see categories as a sort of easier way of achieving some of the functionality provided by inheritance. There are other things categories do which are not provided by inheritance. Categories allow you to extend the functionality of a existing class without subclassing them. You can also use them to replace existing methods in classes. A category method is sort of bolted onto the existing class unlike a subclass which direct descendant of the original class. Once category method is added to a objective c class it is available to all instances of the class including the ones not created by you.
For example , if you have to encryption function which you need to use on all data in your project and say most your data uses only NString for saving and manipulation. One of the ways you can go about it is to create a category for NSString
NSString-Encryption.h
#interface NSString (Encryption)
-(NSString*) encrypt;
#end
NSString-Encryption.m
#import "NSString-Encryption.h"
#implementation NSString (Encryption)
-(NSString*) encrypt
{
// your encryption method here
return encryptedString;
}
#end
UseNSString-encryption.m
NSString *testString = #"this is test";
NSString *encryptedString = [testString encrypt];
As you can see that the category is easier to use than subclass. This method can be called from NSMutableString also as it inherits from NSString. So it is powerful.
You can also use category to replace existing methods on classes.
Another use of a category is that it can be used for private methods as objective c does not have a formal private designation for methods. This done by putting a category in a .m file instead of .h file.
Phone.h
#interface Phone:NSObject
-(void) call;
#end
Phone.m
#interface Phone(Private)
-(void) validatePhoneEntry:(NSString*) phoneNumber;
#end
#implementation Phone
-(void) validatePhoneEntry:(NSString*) phoneNumber
{
}
-(void) call
{
}
#end
The disadvantage of categories is that you cant use them if you need to add member variable to classes.
Sulthan explains it well. Here is a code example of extending the functionality of NSString by adding a category. You can use categories this way to extend classes that you don't have the implementations for without subclassing them.
If you want to add methods to a class, use a category. If you want to change functionality of existing methods in a class, create a subclass.
It's kinda/sorta possible to use a category to replace an existing method, sort of like overriding in a subclass, but you shouldn't use categories for this. There are three reasons: 1) you lose access to the original method; 2) you won't break existing code; 3) if more than one category attempts to "override" the same method, the method that the class will end up with is undefined. Basically, the class will end up with the method from the last category applied to the class, but the order in which categories are applied can't be relied on. It's a recipe for a mess, so just don't do it.
So, you could use a category to add methods to NSData such as +(NSData*)dataWithCryptographicallyRandomBytes:(NSUInteger)length or -(void)base64Decode. But if you wanted to change the behavior of an existing method, like -writeToFile:atomically:, you should create a subclass of NSData and implement your new functionality there. For one thing, you might still want to use the existing behavior in your override, and subclassing lets you do that by calling [super writeToFile:file atmoically:YES]. Also, using a subclass here means that your new behavior will only affect your own code -- it won't affect uses of NSData elsewhere in the framework that may not expect your new functionality.
Categories are similar to Java interfaces (in java the implementation is not optional) - a way to group methods and make objects respond to a particular API - independent of the class type. Inheritance makes sense if you need to add additional ivars and the new class matches a isa relation (student isa person). Adding a few utility methods does not make an isa case - this is usualy done with protocols. Categories are often used with delegates where the methods in question are optional.

Should I subclass the NSMutableArray class

I have an NSMutableArray object that I want to add custom methods to. I tried subclassing NSMutableArray but then I get an error saying "method only defined for abstract class" when trying to get the number of objects with the count method. Why is the count method not inherited?
I read somewhere else that I will have to import some NSMutableArray methods into my custom class if I want to use them. I just want to add a custom method to the NSMutableArray class. So should I subclass NSMutableArray, or should I do something else?
NSMutableArray is not a concrete class, it is just the abstract superclass of a class cluster. The documentation for NSMutableArray does have information about how to subclass, but also strongly advises you not to! Only subclass if you have a special need for actual storage.
A class cluster means that the actual class will be chosen at run-time. An array created empty, may not use the same class as an array created with 1000 items. The run-time can do smart choices of what implementation to use for you. In practice NSMutableArray will be a bridged CFArray. Nothing you need to worry about, but you might see it if you inspect the type of your arrays in the debugger, you will never see NSArray, but quite often NSCFArray.
As mentioned before, subclassing is not the same as extending a class. Objective-C has the concept of categories. A category is similar to what other programming languages call mix-ins.
If you for example want a convenience method on NSMutableArray to sort all members on a property, then define the category interface in a .h file as such:
#interface NSMutableArray (CWFirstnameSort)
-(void)sortObjectsByProperty:(NSString*)propertyName;
#end
And the implementation would be:
#implementation NSMutableArray (CWFirstnameSort)
-(void)sortObjectsByProperty:(NSString*)propertyName;
{
NSSortDescriptor* sortDesc = [NSSortDescriptor sortDescriptorWithKey:propertName ascending:YES];
[self sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
}
#end
Then use it simply as:
[people sortObjectsByProperty:#"firstName"];
If you're just adding a custom method, use a category on NSMutableArray. It's a class cluster, so the implementation is provided by undocumented subclasses. You need to provide a few methods to generate your own subclass. However, if you just add a category then your custom method will work on all NSMutableArrays in your app.
For comparison, here's an example I wrote a while back of implementing a custom NSMutableArray subclass.
Objective-C has a mechanism for adding methods to existing classes called Categories. That way you don't have to create your own subclass.
This is an old post, but thought I'd add my experience. #PayloW's answer is a good answer and I think answers your question perfectly, however, no one really answered your question the other way around, so I'll do that here.
Should you subclass NSMutableArray (or NSArray)? Depends on what you want to achieve. If you only want to add a method to extend an array's BASIC functionality, like sorting, then #PayloW's answer Categories are the way. However, if you want to create a custom class that behaves like an array then yes, subclassing NSMutableArray is quite easy. But because it's a Class Cluster it doesn't exactly subclass as you'd expect. Normally in subclassing the methods available in the Super Class are available to your subclass or you may override them. With Class Clusters you MUST instead include the Super's methods that you're going to use and provide a _backend instance of the super class to wrap those methods around.
Below is an example of how you'd subclass NSMutableArray (or any Class Cluster):
The interface:
#interface MyCustomArrayClass : NSMutableArray {
// Backend instance your class will be using
NSMutableArray *_backendArray;
}
// *** YOUR CUSTOM METHODS HERE (no need to put the Super's methods here) ***
-(bool)isEmpty;
-(id)nameAtIndex:(int)index;
-(int)rowAtIndex:(int)index;
-(int)columnAtIndex:(int)index;
#end
The implementation:
#implementation MyCustomArrayClass
-(instancetype)init {
if (self = [super init]) {
_backendArray = [#[] mutableCopy];
}
return self;
}
// *** Super's Required Methods (because you're going to use them) ***
-(void)addObject:(id)anObject {
[_backendArray addObject:anObject];
}
-(void)insertObject:(id)anObject atIndex:(NSUInteger)index {
[_backendArray insertObject:anObject atIndex:index];
}
-(void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
[_backendArray replaceObjectAtIndex:index withObject:anObject];
}
-(id)objectAtIndex:(NSUInteger)index {
return [_backendArray objectAtIndex:index];
}
-(NSUInteger)count {
return _backendArray.count;
}
-(void)removeObject:(id)anObject {
[_backendArray removeObject:anObject];
}
-(void)removeLastObject {
[_backendArray removeLastObject];
}
-(void)removeAllObjects {
[_backendArray removeAllObjects];
}
-(void)removeObjectAtIndex:(NSUInteger)index {
[_backendArray removeObjectAtIndex:index];
}
// *** YOUR CUSTOM METHODS ***
-(bool)isEmpty {
return _backendArray.count == 0;
}
-(id)nameAtIndex:(int)index {
return ((MyObject *)_backendArray[index]).name;
}
-(int)rowAtIndex:(int)index {
return ((MyObject *)_backendArray[index]).row;
}
-(int)columnAtIndex:(int)index {
return ((MyObject *)_backendArray[index]).column;
}
#end
Then to use like so:
MyCustomArrayClass *customArray = [[MyCustomArrayClass alloc] init];
// Your custom method
int row = [customArray rowAtIndex:10];
// NSMutableArray method
[customArray removeLastObject];
// Your custom class used just like an array !!!
index = 20;
MyObject *obj = customArray[index];
It all works very nicely, is clean and actually pretty cool to implement and use.
Hope it helps.
I have to agree with both node ninja and PeyloW because technically they have both right. Actually, that does not help me much.
Preamble:
There are many arrays in code that all to one contain only one but different type of data e.g. classA, classB, classC.
Problem:
I can easily mix arrays by passing wrong one to e.g. some selector because they are all NSMutableArray. There is no static check, only runtime one.
Solution - 1st try:
Make subclass of NSMutableArray so compiler makes static check and warns about wrong data type.
That is good because compiler warns you even when you pass wrong type to -addObject or -objectAtIndex when you overload that ones.
That is bad because you cannot instantiate NSMutableArray superclass this way.
Solution - 2nd try:
Make new (proxy) class of some type e.g. NSObject as for NSMutableArray and add class member of type NSMutableArray.
This is good because you can instantiate NSMutableClass and compiler checks when you pass wrong type to -addObject or -objectAtIndex when you overload that ones.
The bad side of that is that you need to overload every selector of the NSMutableArray that you use, not only that ones that differs in class that array contains.
Conclusion:
When you build some sophisticated code that has many class types in its arrays, believe me it is worth to try. Simply by doing this compiler showed me several errors that I would not recognize until I will face it in runtime. Or even worse, when end user would face it.
From the Apple reference for NSArray, in the Methods to Override section:
Any subclass of NSArray must override the primitive instance methods count and objectAtIndex:. These methods must operate on the backing store that you provide for the elements of the collection. For this backing store you can use a static array, a standard NSArray object, or some other data type or mechanism. You may also choose to override, partially or fully, any other NSArray method for which you want to provide an alternative implementation.
As a side note, in Objective-C, there is no actual feature that allows you to declare a class as an abstract class, per se, as in Java, for instance. So, what they do instead is call something like the code below, from within some method that they want to force to be overridden by a subclass. In effect, they give the class 'abstract class' semantics.
This method definition acts as an abstract method, which raises an Exception if not overridden, with the following output:
-someAbstractFooMethod only defined for abstract class. Define -[YourClassName someAbstractFooMethod]!
- (void) someAbstractFooMethod
{
//Force subclassers to override this method
NSString *methodName = NSStringFromSelector(_cmd);
NSString *className = [self className];
[NSException raise:NSInvalidArgumentException
format:#"-%# only defined for abstract class. Define -[%# %#]!", methodName, className, methodName];
}

Building Dynamic Classes in Objective C

I'm a somewhat competent ruby programmer. Yesterday I decided to finally try my hand with Apple's Cocoa frameworks. Help me see things the ObjC way?
I'm trying to get my head around objc_allocateClassPair and objc_registerClassPair. My goal is to dynamically generate a few classes and then be able to use them as I would any other class. Does this work in Obj C?
Having allocated and registered class A, I get a compile error when calling [[A alloc] init]; (it says 'A' Undeclared). I can only instantiate A using runtime's objc_getClass method. Is there any way to tell the compiler about A and pass it messages like I would NSString? A compiler flag or something?
I have 10 or so other classes (B, C, …), all with the same superclass. I want to message them directly in code ([A classMethod], [B classMethod], …) without needing objc_getClass. Am I trying to be too dynamic here or just botching my implementation? It looks something like this…
NSString *name = #"test";
Class newClass = objc_allocateClassPair([NSString class], [name UTF8String], 0);
objc_registerClassPair(newClass);
id a = [[objc_getClass("A") alloc] init];
NSLog(#"new class: %# superclass: %#", a, [a superclass]);
//[[A alloc] init]; blows up.
The reason that [[A alloc] init]; blows up is that the compiler has no clue what A means. The compiler never knows that A is even there.
Edit: Also, it looks like what you want is:
#interface A : NSObject {
NSString *myString;
}
- (id)initWithString:(NSString *)string;
- (void)doItToIt;
#end
or perhaps
#interface NSString (MyPrivateExtension)
- (void)doItToIt;
#end
When you define a class in the Objective-C language, the compiler defines a new type. When you create a class dynamically, the compiler has no knowledge of that type, so your only choice is to use the class as an id, and send messages to it dynamically. Ruby is a dynamically typed language that likely uses the same mechanisms as the compiler when defining classes at runtime.
Have a look at http://www.mikeash.com/pyblog/friday-qa-2010-11-6-creating-classes-at-runtime-in-objective-c.html and https://github.com/mikeash/MAObjCRuntime
It describes just what you're trying to achieve and provides a nice abstraction over raw Objective-C runtime calls.
Have a look at the fabulous F-Script and FSClass which can do this and are open source. FSClass defines a meta-class that can be subclassed at runtime.
It does work by using objc_allocateClassPair and objc_registerClassPair but there is alot of other stuff going on (beyond me!) that would probably help.