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.
Related
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().
The vague overview is that I'm writing a method in an NSArray Category that will take a Class and filter an Array down to elements that are members of that class. Something like:
#implementation NSArray(filter)
-(NSArray*)objectsOfClass:(Class)aClass {
NSMutableArray *ret = [[NSMutableArray alloc] init];
for (id obj in self)
if ([obj isMemberOfClass:aClass])
[ret addObject:obj];
return [NSArray arrayWithArray:ret];
}
#end
Sooo, with that out of the way, on to my question. NSObject.h shows that isMemberOfClass: has the following signature:
-(BOOL)isMemberOfClass:(Class)aClass;
When I type this method in XCode, the autocompletion hints a method signature that looks like:
[self isMemberOfClass:(__unsafe_unretained Class)]
My questions are:
1) Why the discrepancy between the method prototype in NSObject.h and XCode's autocompletion?
2) In my own method (shown at the start of the this question), should I include the __unsafe_unretained modifier? If so, why? If not, why not?
Thanks!
In the absence of an explicit ownership qualification one is inferred; this is usually __strong but in the case of Class it is __unsafe_unretained. This makes sense as Class objects are immortal and need not be memory managed by your code.
So Xcode is just making the implicit explicit and you do not need to do this yourself.
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).
I am very, very new to Obj-C, and will have a ton of questions. (I have the book "iPhone Programming, The Big Nerd Ranch Guide", but it doesn't address the differences between C# and Obj-C. Does anyone know of a doc that does address the differences?).
Anyway, my question is above...
In Objective-C, object allocation and initialization are separate operations, but it's common and a good practice to see them called in the context of the same expression:
MyClass *myInstance = [[MyClass alloc] init];
// ...
[myInstance release];
In C#, allocation and initialization happen when you use new:
MyClass myInstance = new MyClass();
The runtime allocates the instance and then calls the constructor.
So yes, the C# constructor is equivalent to the Objective-C initializer, but the usage is different.
Apart from this ... init in Objective-C is just a normal instance method, without any special semantics. You can call it at any point. In C#, constructors are very special static-like methods treated differently by the runtime and with special rules. For example, the C# compiler enforces calls to the base class constructor.
They are similar only as much as you can compare two completely different methods for creating an object. Checkout this information on the Objective-C Runtime.
The following is a very simple (but hopefully not misleading) explanation:
Objective-C
id object = [MyObject alloc]; // allocates the memory and returns a pointer. Factory-like method from NSObject (unless your class overrides it)
MyObject *myObj = [object init]; // initializes the object by calling `-(id)init`. You'll want to override this, or a similar init method for all your classes.
Usually written like this:
MyObject *myObj = [[MyObject alloc] init];
From what I know, the C# constructor allocates the memory and calls the appropriate constructor function to initialize the object.
A difference is that in C# you can't call an inherited constructor (see the bottom of the link above) but in Obj-C this will compile, but will give you wrong results.
#interface ClassA : NSObject
- (id) initWithInteger:(int)num;
#end
#interface ClassB : ClassA
- (id) init;
#end
#implementation ClassB
- (id) init
{
self = [supere initWithInteger:10];
return self;
}
// main
ClassA *a = [[ClassA alloc] initWithInteger:10]; //valid
ClassB *a = [[ClassB alloc] initWithInteger:10]; // will call init from classA, bypassing and not calling init for classB.
Just be careful with weak/dynamic typed language of Objective-C
They're similar, but not identical. Technically, a constructor fully creates and initializes an instance, while an initializer takes an already constructed instance (usually gotten through alloc) and sets the instance up so that it's ready to be used.
As for the differences between Objective-C and C#: They're two different and mostly unrelated languages. When you're learning a new language, trying to think of it as "Like this language I already know, but with these differences" can actually make it harder to learn, because there are a lot of differences and they're often subtle, so going in with assumptions from another language will confuse you. If you search around Stack Overflow, you'll find a lot of PHP programmers who start to learn a new language and immediately wonder "How do I do variable variables in this language?" It's like looking for a list of the differences between English and Chinese — you're better off not trying to treat one like the other. Keep in mind what you already know, but try not to assume any of it is the same in Objective-C.
I'm teaching myself Objective-C from a book (Cocoa programming for mac OS X) and am about halfway through however I have two questions that aren't answered or defined in the book.
When defining class methods what is the difference between (assuming there in a .h file):
- (int) population;
+ (int) population;
The way I see it at the moment is that - methods require the class to be allocated and initialized first however + can be called statically without requiring allocation and initialization. E.g. (in a function in another class)
// Using -
Earth *world = [[Earth alloc] init];
int population = [world population];
// Using +
int population = [Earth population];
If that is correct, when should I use static methods and are they're any disadvantages with doing so.
When defining a var in either a function paramater or as an actual var in a function, does the use of * mean the var will be an object? e.g. (again in a header file.)
- (void) setPopulation: (NSNumber *) population; //Use of * as population is of NSNumber
- (void) setPopulation: (int) population; // population isn't a class so doesn't need *
Sorry if any of my terms don't make sense in the land of Objective-C such as static methods, etc. I'm a PHP and Ruby Programmer.
The -/+ in method declarations for Objective-C simply denote whether the method is a class method or an instance method. For example, with Objective-C, you cannot send an instance a message that was declared as a class method. For example:
#interface MyObject : NSObject
-(void)myInstanceMethod;
+(void)myClassMethod;
#end
// ...
MyObject* obj = [[MyObject alloc] init];
[obj myInstanceMethod]; // this is okay
[obj myClassMethod]; // this will fail
[[obj class] myClassMethod]; // this is okay
[MyObject myClassMethod]; // this is okay
[MyObject myInstanceMethod]; // this will fail
As to the second part of your question, Objective-C is a strict super-set of C. It adds classes but they are really C data structures whose implementations are hidden from you by the Objective-C runtime. Because of this, classes are always represented as pointers. In C, the * means that the variable is being declared as a pointer to some memory address. You can use pointers with primitive types in C as well, but Objective-C objects must always be referred to by pointers.
There are many great tutorials/introductions to pointers out there. I would suggest simply googling for C tutorial and pointers to learn more.
The + declaration is a class method, you need no instance to call it. Constructors/factory methods need to be class methods. The - declared an instance method, operation on a single instance. Each instance has its own independent state (member variables). This is a fundamental difference in OO programming! In general make most methods instance methods, except for utility classes.
You can see some discussion of when to use static methods in When should I write Static Methods?