I have a strange task. I need to get an array that contains all the functions in an objective c object. I then need to be able to tell if each function is a class method or not. Then I need to get the names (preferably an NSString) of each parameter and the type each parameter takes. Is there a way to do this? If not, does anyone know how to access the keys and values coded in the NSCoding Protocol function -(void)encodeWithCoder:(NSCoder*)aCoder; without using NSKeyedArchiver? What I am trying to do here is display a list of properties required to initialize an object. All my objects use class methods to initialize themselves. I am making a level editor that allows me to edit properties that differ between objects and I don't feel like writing getPropertyList and initWithProperties functions for every single object since I have already done this by implementing the NSCoding protocol.
I need to get an array that contains all the functions in an objective c object. I then need to be able to tell if each function is a class method or not.
Easy enough: you want class_copyMethodList(), which gets you just the instance methods for that class. To get the class methods, pass the class object, e.g. class_copyMethodList(object_getClass([NSString class]), &count);
Then I need to get the names (preferably an NSString) of each parameter and the type each parameter takes.
The parameter name part is probably not possible. They're not included in the method's metadata, and I'm pretty sure that they don't survive compilation at all; digging them out of the executable if they're there would certainly not be easy.
The types, however, are easily accessible via one of two runtime functions: either method_getTypeEncoding(), which gets you the signature string for the method's return and arguments, or method_getArgumentType(), which will let you loop over the argument types (the returned strings use the same code as the full type string).
If not, does anyone know how to access the keys and values coded in the NSCoding Protocol function -(void)encodeWithCoder:(NSCoder*)aCoder without using NSKeyedArchiver?
Are you talking about the particular implementation that you've made for encodeWithCoder:? You want the list of ivars implied by [coder encodeObject:firstIvar forKey:#"firstIvar"]; [coder encodeObject:secondIvar forKey:#"secondIvar"];? I'm not sure what that has to do with method signatures, but if so, you could make an NSCoder subclass that creates a dictionary from when you pass it as the coder and send encodeWithCoder: to your objects (see this answer I posted the other day).
What I am trying to do here is display a list of properties required to initialize an object.
What about a class method that returns an array with the names of the properties?
+ (NSArray *)essentialPropertyNames {
return [NSArray arrayWithObjects:#"firstIvar", #"secondIvar", nil];
}
That would probably be less effort than picking through the runtime/class metadata and wouldn't be any less odd.
All my objects use class methods to initialize themselves.
That sounds unusual at best. In Cocoa, instances should use some form of -init to do their initialization.
Related
I am writing a bridge from a language I am developing and ObjC.
There are several nice introspection C functions in the objective C runtime and I am able to retrieve arguments types for methods using method_getTypeEncoding.
The main problem is with object arguments which are returned as id (encoded as #) but what I would need is the real objc class name like NSString or NSNumber.
Is there a way to solve this issue without parsing the .h files?
Knowing something is an id allows you to know the size of the parameter, which is important when writing a scripting interface. Add another layer where you can dynamically verify assumptions using things like
[objectPassedIn isKindOfClass: [expectedType class]];
You want to be careful hardcoding things like, "Oh this is a string so look for __NSCFString" - because there's no way to know you'll get an instance of __NSCFString or another type. NSString is a class cluster - You could get any custom implementation back when using one.
The actual type of objects is not important to the Objective-C Runtime so you need to add your own layer. You might be able to get some useful info using Clang/llvm as a tool.
I'm reading the book "Programming in Objective C" and he explained not too much on the id type and didn't give much exercise on it, so I'm wondering how often do you use id and if programmers most of the time avoid it? (since he explained some issues with it)
I'm sure it's used, would be great if you can mention some cases it is the only solution..like real life programming cases from some kind of app development.
id is the universal type in Objective C. It can represent a * of any Objective-C type, such as NSString *, NSArray *, etc. The neat thing about Objective-C is that you can send messages to id, and if the object on the other end understands the message, it will get processed as usual without the sender having to know the real type.
It's commonly used when defining anything generic. For example, NSArray is an array of ids; it's up to the programmer to put a specific kind of object in the container (e.g. NSNumber, NSString, etc.). It's used in a lot of other places in Objective-C (such as when defining IBActions for the interface builder, when defining init methods, etc.).
id is the generic object type in Objective-C. It can hold any object.
one real world example: parsing json you wont know, if the root element is a array or a dictionary. But id would take them both.
I use it a lot, but often in conjunction with a protocol definition: id<NetworkPrinterProtocol>. This means that it should be an object of any kind but it does fulfill the NetworkPrinterProtocol. Often used for defining delegates.
see WP: Objective-C — Dynamic Typing
The id is kind of like a catch-all data type. It is used to hold values of any type.
Common uses are for the return type of init... methods. It's used by the collection classes since they can hold any object. See the various getter methods return values and the various methods for adding/setting objects in the mutable version of collection classes.
It's also used in combination with protocols when you need a reference to an object that can be any class but must adhere to a protocol. Examples include many of the delegate properties such as the UITableView delegate.
I went through the source code of GNUStep's NSNumber's implementation to understand how does factory method implementation works there.
From there What I could understand was we have NSNumber with blank implementation for all initWithXYZ kind of methods. and NSTemporaryNumber was acting like an intermediate class in the hierarchy that implemented all the initWithXYZ methods where it actually created objects of specific types , autoreleased itself and returned the created object.
Also allocWithZone was overridden to avoid creation of NSNumber object and to create object of NSTemporaryNumber if it was so otherwise create objects of specific types.
What I didn't understand was, can't the same things be done by NSNumber itself ?
why give blank implementations at all , create the object of specific type and then autorelease self.
Also if we have implementations of createXYZ methods in NSNumber itself, why have initWithXYZ methods ?
If I have to implement a factory implementation for my project where say I have two mediaItems, video , audio and photo etc.
for which I have separate classes and corresponding enums which I pass to initWithMediaType who will create an object of correct child class, return it and destroy itself.
Have two classes like NSNumber and NSTemporaryNumber: say Media and TemporaryMedia, one with blank implementations other with implementations as mentioned above ?
Should I do something like this ?
Is this the way we have to implement Factory pattern in Objective C ?
My question might seem silly biut I come from a Java, C++ background where things looked different.
The purpose might be the same but I am finding it difficult to understand the way Objective C does it since it does not have abstract classes.
Link to the source:
http://www.koders.com/objectivec/fid46956186C20201706AFE1744AA7AFEEE09D1FE5A.aspx
The point is that NSNumber is a class cluster. The class you actually end up with may be an NSIntNumber, an NSFloatNumber or one of several others. They all respond to the same messages as NSNumber (and, usually in this pattern will be subclasses of it, but that isn't required) so it makes no real difference to the caller.
When you call alloc there's no way to know what sort of object to create, so a neutral type is created and returned instead. It substitutes appropriately upon receiving an appropriate init.
So this pattern is for the implementation of class clusters. You can ignore it if writing a class that provides only instances of itself.
My model objects are lazy-loaded from an SQLite database. Don't ask why, but the code uses QuickLite to populate the objects, which means that some housekeeping has to be performed before an accessor is used the first time.
I thought, naively, that valueForKey: and setValue:forKey: would be called by the #synthesize'd accessors, so that I could simply overload those 2 methods to fill the object from the db, if necessary. Unfortunately, that doesn't work: the #synthesize'd accessors clearly don't use KVC to get/set their represented value.
My question is therefore: Is there a way to call some code before any #property is accessed, without writing all getters/setters myself?
If your model objects were a subclass of NSManagedObject then your accessors would be using KVC (you declare the properties, then use '#dynamic' rather than '#synthesize' in the .m file to indicate that the accessors will be taken care of by other code).
Basically it sounds like you're re-implementing the faulting behaviour in Core Data.
Based on your comment, the only way I can think of doing this would be to have a sort of proxy object which contains your actual object. So, your proxy object would have a single visible property, which is your actual object, and in the accessor for that, you would then check to see if you'd gone to the database for this particular object, if not, do your housekeeping.
So, your calls would be
NSString *someProperty = proxyObject.realObject.someProperty;
Within proxyObject, the accessor for realObject:
if (beenToTheDatabase)
return realObject;
else
{
// Do your business
beenToTheDatabase = YES;
return realObject;
}
Whether this is more or less effort than manually writing your accessors or migrating to core data, I don't know.
Is one of these two ways to create and initialize an object preferable?
MyClass oClass = [[MyClass alloc] init];
oClass.length = 5;
oClass.text = #"Hello";
or using a class method that contains about the same code but looks like this:
MyClass oClass = [MyClass myClassWithLength:(int) 5 andText:(NSString *) #"Hello"];
I hate it when I see things done more than one way and I have no idea if one is better than the other, or why!
Don't be a hater. :-)
By the way, I'm assuming you meant:
(Edit: removed unnecessary casts)
MyClass oClass = [[MyClass alloc] initWithLength:5 andText:#"Hello"];
The reason for multiple init... methods is to make it more convenient for developers to create properly initialized instances. So, for example, if you find that developers often need to create instances of MyClass with a length and text, you make their life easier by providing an API that allows them to do that in one step. And if you find that developers also frequently need to create instances of MyClass with just a text string, you might also provide an -initWithText: method.
And if the instances created this way are frequently used as temporary objects (i.e., not stored in instance variables or static variables), you might also add a class convenience method like +myClassWithText: that returns an autoreleased instance of MyClass initialized with the provided text string.
As to which one is better: it's always better to fully initialize an object when possible, so if the object needs both values to be properly initialized, use the method that allows you to provide both arguments. And if you don't need to store a reference to the instance you're creating, use the class convenience method so your code doesn't have to deal with memory management.
If the object is unusable without the length and text, then the second option might be better. If those fields are optional, then the first one is better.
However, I don't think there is absolute truth to this question.
If you have a class with many properties it's very unlikely to initialize them all in one single line of code. Both ways work fine for me.
If an initWithSomething: method is available and you want to provide initial values for those properties, I would always prefer it just because it's simpler. It also will always work even with immutable versions of a class.
But neither init method is inherently "better." Classes usually have one or two designated initializers and all the others just call those with default values — it doesn't necessarily leave the instance's properties untouched. The documentation for a class should indicate what its initializers do and which is the designated initializer for the class. For example, [[NSDate alloc] init] uses NSDate's designated initializer, initWithTimeIntervalSinceReferenceDate:, to create a date object representing the current date and time.
Incidentally, this also means that when you're subclassing a class, you only need to override its designated initializer. Since the others just call that, they get your new behavior for free.