I have a class that inherits from multiple superclasses, and I would like to get the methods that the class has. Naively using methods() returns methods from the class I'm working with as well as superclass methods, but I'm not interested in the superclass methods.
Any idea how to do this? I couldn't find anything in MATLAB documentation.
Thanks!
If your subclass doesn't reimplement any of the methods of the superclasses (or if you're fine with ignoring reimplemented methods), you can use the functions METHODS and SUPERCLASSES to find a list of subclass methods that aren't also methods of any of the superclasses. For example:
>> obj = 'hgsetget'; %# A sample class name
>> supClasses = superclasses(obj)
supClasses =
'handle' %# Just one superclass, but what follows should handle more
>> supMethods = cellfun(#methods,supClasses,... %# Find methods of superclasses
'UniformOutput',false);
>> supMethods = unique(vertcat(supMethods{:})); %# Get a unique list of
%# superclass methods
>> subMethods = setdiff(methods(obj),supMethods) %# Find methods unique to the
%# subclass
subMethods =
'get'
'getdisp'
'set'
'setdisp'
Even though this question is solved, let me add another answer using meta.class capabilities:
%# some class name
clname = 'hgsetget';
%# obtain class meta-info
mt = meta.class.fromName(clname);
%# get name of class defining each method
cdef = arrayfun(#(c)c.Name, [mt.MethodList.DefiningClass], 'Uniform',false);
%# keep only methods that are defined in the subclass
subMethods = {mt.MethodList(ismember(cdef,clname)).Name}
The result for this example:
subMethods =
'set' 'get' 'setdisp' 'getdisp' 'empty'
Note how the result also includes the static methods empty which all non-abstract classes have (used to create an empty array of that class).
Related
Say I have a subclass of NSManagedObject called MBManagedSquare and MBManagedCircle. An MBManagedSquare and MBManagedCircle define a method prepareFromDictionary:(NSDictionary*)dic, and both of their implementations are different.
Say I have this code:
NSString *type = // could be #"MBManagedSquare" or #"MBManagedCircle"
NSEntityDescription *desc = [NSEntityDescription entityForName:type inManagedObjectContext:_context];
NSManagedObject *object = [[NSManagedObject alloc] initWithEntity:desc insertIntoManagedObjectContext:_context];
So the type of entity it will be with Core Data is determined dynamically via a type string. So all I know is that it is an NSManagedObject.
What I want to do is call the prepareFromDictionary: method for the right class.
So if the type is "MBManagedSquare", I want to cast the object to an MBManagedSquare, and then call
[castedObject prepareFromDictionary:dic];
What I tried doing is:
Class class = NSClassFromString(type);
class *castedObject = (class*)object;
but I get an expected expression error. I'm not sure if this is even possible. How would I do this?
You don't need to worry about calling the right class if the selectors and their parameters match -- ObjC has plenty of dynamic dispatch powers.
As far as an implementation, it's pretty common to either:
create a common base with the interface you want
or create a protocol which both classes adopt:
MONProtocol.h
#protocol MONManagedShapeProtocol < NSObject >
- (void)prepareFromDictionary:(NSDictionary *)pDictionary;
#end
then (since you know it is one of the two types, MBManagedSquare or MBManagedCircle) either derive from the base or adopt the protocol and declare your variable like:
// if subclass
MBManagedShape * castedObject = (MBManagedShape*)object;
or
// if protocol
NSManagedObject<MONManagedShapeProtocol>* castedObject =
(NSManagedObject <MONManagedShapeProtocol>*)object;
no need for a cast there. the object can be either or and the function is only there once.
checking if it is there is good: respondsToSelecctor:#selector(prepareFromDictionary:)
In the second chapter of his iOS Programming book, Joe Conway describes using 'self' in class methods in the event of subclassing. I understand this concept and have a question about the issue of subclassing.
Background: We created a Possession class whose class method +randomPossession looks like this:
+(id)randomPossession
{
NSArray *randomAdjectiveList = [NSArray arrayWithObjects:#"Fluffy", #"Rusty", #"Shiny", nil];
NSArray *randomNounList = [NSArray arrayWithObjects:#"Bear", #"Spork", #"Mac", nil];
unsigned long adjectiveIndex = rand() % [randomAdjectiveList count];
unsigned long nounIndex = rand() % [randomNounList count];
NSString *randomName = [NSString stringWithFormat:#"%# %#", [randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]];
int randomValue = rand() % 100;
NSString *randomSerialNumber = [NSString stringWithFormat:#"%c%c%c%c%c",
'0' + rand() % 10,
'A' + rand() % 10,
'0' + rand() % 10,
'A' + rand() % 10,
'0' + rand() % 10];
Possession *newPossession = [[self alloc] initWithPossessionName:randomName valueInDollars:randomValue serialNumber:randomSerialNumber];
return [newPossession autorelease];
}
I am aware that the return value should really be of type id such that id newPossession = ...
I subclassed Possession and created a class called BallGlove that included a new iVar, brandName, an NSString *
I overrode the +randomPossession in BallGlove as follows:
+(id)randomPossession
{
BallGlove *myGlove = [super randomPossession];
NSArray *brandNames = [NSArray arrayWithObjects:#"Rawlings", #"Mizuno", #"Wilson", nil];
unsigned long randomNameIndex = rand() % [brandNames count];
[myGlove setBrandName:[brandNames objectAtIndex:randomNameIndex]];
NSLog(#"myGlove is of type class: %#", [self class]);
return myGlove;
}
My question is this: Is the manner in which I overrode this class method appropriate and acceptable by the community (i.e. parallel the -init format by capturing the super implementation in a variable, manipulate the variable accordingly and then return it? My output shows that the object returned is an instance of BallGlove however, I was interested in the acceptable implementation. Thanks in advance.
Yep, that's a perfectly sensible way to do it. There's nothing particularly different between class methods and normal methods — just that one is performed by a class and the other is performed by an instance.
The moment you override a class method you can decide to implement it with the help of the super implementation or without it. It is totally up to you. Overiding init is a completely differeent story, not only because it is an instance method but because it has a convention/contract associated with it. Keep in mind that for instance methods the Liskov Subtitution principle should not be violated.
Your overrided of the class method is perfectly fine, although I would consider overiding class methods a design smell. Although it's very well possible in Objective-C, it's not in other languages and that for a very good reason. Polymorphism as a concept is better bound to instances that can be used as substitutes for each other, whereas using class methods breaks the concept (i.e. no real subtitution). It's clever, but not necessesarily intuitive and flexible.
Yes, it is acceptable to do your initialization like that. In fact that is how it is done in most cases. I mean, that is the reason for inheriting from a super class in the first place. You want stuff in addition to what is present in the super class. So, you insert code to whatever is specific to the inherited class and it should be done that way.
I think how you want the BallGlove object initialized is also a factor in how you define your inherited method. The question arises on calling the Possession init or calling the BallGlove init (Not that creating an instance of a class is the only place to use a class method). So it comes down to the logic of creating your objects i.e. how you well you are describing BallGlove object-are you making sure that your class method describes it in ways that fits the BallGlove object criteria and does not become generic Possession object. My answer is that if you can implement it right, using a parallel line of class methods is acceptable.
Also, it doesn't matter if you are returning of type Possession in your super class because, id can point to an object of any class type
It's technically ok.
I'd propose an alternative, though. If you already have a designated public initializer on your base class (which you might want to create and call from that factory class method anyway), and then use that very initializer (or even a new one from your subclass) in your subclasses' class method.
It's not much more code, but in my opinion easier to follow and future-proof. The initializer might come handy as well at one point, but of course it's not a solution for every application.
What would be a nice pattern in Objective-C for class variables that can be "overridden" by subclasses?
Regular Class variables are usually simulated in Objective-C using a file-local static variables together with exposed accessors defined as Class methods.
However, this, as any Class variables, means the value is shared between the class and all its subclasses. Sometimes, it's interesting for the subclass to change the value for itself only. This is typically the case when Class variables are used for configuration.
Here is an example: in some iOS App, I have many objects of a given common abstract superclass (Annotation) that come in a number of concrete variations (subclasses). All annotations are represented graphically with a label, and the label color must reflect the specific kind (subclass) of its annotation. So all Foo annotations must have a green label, and all Bar annotations must have a blue label. Storing the label color in each instance would be wasteful (and in reality, perhaps impossible as I have many objects, and actual configuration data - common to each instance - is far larger than a single color).
At runtime, the user could decide that all Foo annotations now will have a red label. And so on.
Since in Objective-C, Classes are actual objects, this calls for storing the Foo label color in the Foo class object. But is that even possible? What would be a good pattern for this kind of things? Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Why do you think this would be ugly? It is a very simple approach since you can use [self className] as the key in the dictionary. It is also easy to make it persistent since you can simply store the dictionary in NSUserDefaults (as long as it contains only property-list objects). You could also have each class default to its superclass's values by calling the superclass method until you find a class with a value.
+ (id)classConfigurationForKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
Class c = [self class];
id value = nil;
while(value == nil) {
NSDictionary *classConfig = [_configurationDict objectForKey:[c className]];
if(classConfig) {
value = [classConfig objectForKey:key];
}
c = [c superclass];
}
return value;
}
+ (void)setClassConfiguration:(id)value forKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
NSMutableDictionary *classConfig = [_configurationDict objectForKey:[self className]];
if(classConfig == nil) {
classConfig = [NSMutableDictionary dictionary];
[_configurationDict setObject:classConfig forKey:[self className]];
}
[classConfig setObject:value forKey:key];
}
This implementation provides no checking to make sure you don't go over the top superclass, so you will need to ensure that there is a value for that class to avoid an infinite loop.
If you want to store objects which can't be stored in a property list, you can use a method to convert back and forth when you access the dictionary. Here is an example for accessing the labelColor property, which is a UIColor object.
+ (UIColor *)classLabelColor {
NSData *data = [self classConfigurationForKey:#"labelColor"];
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
+ (void)setClassLabelColor:(UIColor *)color {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:color];
[self setClassConfiguration:data forKey:#"labelColor"];
}
my answer here may help:
What is the recommended method of styling an iOS app?
in that case, your annotation just holds a reference to a style (e.g. you need only one per style), and the size of a pointer for an entire style is not bad. either way, that post may give you some ideas.
Update
Jean-Denis Muys: That addresses the sample use case of my question, but not my question itself (a pattern to simulate class instance variables).
you're right, i didn't know how closely your example modeled your problem and i considered commenting on that.
for a more general and reusable solution, i'd probably just write a threadsafe global dictionary if your global data is nontrivial (as you mentioned in your OP). you could either populate it in +initialize or lazily by introducing a class method. then you could add a few categories to NSObject to access and mutate the static data -- do this for syntactical ease.
i suppose the good thing about that approach is that you can reuse it in any program (even though it may appear ugly or complex to write). if that's too much locking, then you may want to divide dictionaries by prefixes or create a simple thread safe dictionary which your class holds a reference to -- you can then synthesize an instance variable via the objc runtime to store it and declare an instance method to access it. the class method would still have to use the global data interface directly.
In the interface I have this:
Animal* myPet;
At runtime I may want myPet to be a cat or a dog, which are subclasses of Animal:
id newPet;
if(someCondition) {
newPet = [[Cat alloc] initWithNibName:#"Cat" bundle:nil];
} else {
newPet = [[Dog alloc] initWithNibName:#"Dog" bundle:nil];
}
self.myPet = newPet;
Obviously this is incorrect, but I hope it's enough to show what I'm trying to do. What is the best practice for doing this?
isKindOfClass is your friend:
[newPet isKindOfClass:Dog.class] == NO
Strongly type newPet as Animal * instead of id. id can hold a reference to an instance of any class, but properties cannot be used with it (the dot syntax requires a strongly typed lvalue.) Since both Cat and Dog inherit from Animal, this will be perfectly correct and valid.
If you're using two classes that don't share a common ancestor (past NSObject), then you should take a step back and rethink your design--why would instances of those two classes need to occupy the same variable?
NSString *className = #"Cat";
Animal *myPet = [[NSClassFromString(className) alloc] init];
It's unclear what you are after, but if you want to create an instance of a class named by a string, this should do it.
For anyone arriving from Google based on the title: "Determine class type at runtime", here are some useful things to know:
You can call the class method on an NSObject* at run time to get a reference to its class.
[myObject class];
Take a look at these methods too:
isKindOfClass: - check if an object belongs to a class anywhere in its hierarchy.
isMemberOfClass: - check if an object belongs to a specific class.
I am working on an object factory to keep track of a small collection of objects. The objects can be of different types, but they will all respond to createInstance and reset. The objects can not be derived from a common base class because some of them will have to derive from built-in cocoa classes like NSView and NSWindowController.
I would like to be able to create instances of any suitable object by simply passing the desired classname to my factory as follows:
myClass * variable = [factory makeObjectOfClass:myClass];
The makeObjectOfClass: method would look something like this:
- (id)makeObjectOfClass:(CLASSNAME)className
{
assert([className instancesRespondToSelector:#selector(reset)]);
id newInstance = [className createInstance];
[managedObjects addObject:newInstance];
return newInstance;
}
Is there a way to pass a class name to a method, as I have done with the (CLASSNAME)className argument to makeObjectOfClass: above?
For the sake of completeness, here is why I want to manage all of the objects. I want to be able to reset the complete set of objects in one shot, by calling [factory reset];.
- (void)reset
{
[managedObjects makeObjectsPerformSelector:#selector(reset)];
}
You can convert a string to a class using the function: NSClassFromString
Class classFromString = NSClassFromString(#"MyClass");
In your case though, you'd be better off using the Class objects directly.
MyClass * variable = [factory makeObjectOfClass:[MyClass class]];
- (id)makeObjectOfClass:(Class)aClass
{
assert([aClass instancesRespondToSelector:#selector(reset)]);
id newInstance = [aClass createInstance];
[managedObjects addObject:newInstance];
return newInstance;
}
I have right a better tutorial on that , please checkout
https://appengineer.in/2014/03/13/send-class-name-as-a-argument-in-ios/
It's pretty easy to dynamically specify a class, in fact you can just reference it by it's name:
id string = [[NSClassFromString(#"NSString") alloc] initWithString:#"Hello!"];
NSLog( #"%#", string );
One other tip, I would avoid using the nomenclature 'managed object' since most other Cocoa programmers will read that as NSManagedObject, from Core Data. You may also find it easier to use a global NSNotification (that all your reset-able objects subscribe to) instead of managing a collection of different types of objects, but you're more informed to make that decision than I am.
The bit of the answer missing from the other answers is that you could define a #protocol containing your +createInstance and +reset methods.
It sounds like you want something like:
- (id)makeObjectOfClassNamed:(NSString *)className
{
Class klass = NSClassFromString(className);
assert([klass instancesRespondToSelector:#selector(reset)]);
id newInstance = [klass createInstance];
[managedObjects addObject:newInstance];
return newInstance;
}
This would assume a class method named +createInstance. Or you could just use [[klass alloc] init].
To call it:
MyClass *variable = [factory makeObjectOfClassNamed:#"MyClass"];
Depending on what you're trying to do, it might be better to pass around class objects than strings, e.g.:
MyClass *variable = [factory makeObjectOfClass:[MyClass class]];