What's the best way to create an object factory in objective-c? - objective-c

I have a hierarchy of classes like this:
MyBox
|
|->ImageBox
|->GalleryBox
|->MovieBox
|-> ...
Each one identified by a string like #"image-box" or #"gallery-box" coming from an xml block like this:
<image-box><property1>value1</property1>...</image-box>.
So i decided to create a factory class, which can create for me the correct object given the xml block:
[BoxFactory.h]
#interface BoxFactory {
NSMutableDictionary* stringToClassMapping;
}
+(BoxFactory)sharedBoxFactory;
-(void)registerClass:(Class)clazz withKey:(NSString*)key;
-(MyBox*)getBoxFromXml:(NSString*)xmlBlock;
#end
[.m]
#import "BoxFactory.h"
#import "MyFantasticXmlLibrary.h"
BoxFactory* gInstance=nil;
#implementation BoxFactory
+(BoxFactory*)sharedBoxFactory {
if (gInstance==nil)
gInstance=[[BoxFactory alloc]init];
return gInstance;
}
-(id)init {
self=[super init];
stringToClassMapping=[[NSMutableDictionary alloc]initWithCapacity:10];
return self;
}
-(void)registerClass:(Class)clazz withKey:(NSString*)key {
[stringToClassMapping setObject:clazz forKey:key];
}
-(MyBox*)getBoxFromXml:(NSString*)xmlBlock {
NSString* key=[MyFantasticXmlLibrary getRootNodeName:xmlBlock];
return [[[stringToClassMapping objectForKey:key]alloc]initWithXml:xmlBlock];
}
#end
Now the problem is: where should the concrete classes call the registerClass:withKey: method? it seems like the correct place would be in the init method of the BoxFactory, but this means that the Factory must be modified for each class added, which is not scalable for big hierarchies.
I really would like to find a way to put the registration call in the concrete class itself, keeping a better organized code and less dependencies. But until now i didn't find a way to execute code when a class is loaded, without initing an instance of it.

Ok, i found it out 5 minutes after posting the question, but i still think it can help somebody so i'll leave it here:
There is a method +(void)load in NSObject called exactly when the class is loaded in the image, at the very start of the execution. So the best place to register the classes with their factory is the +(void)load method of the concrete class itself. For example:
#implementation ImageBox
+(void)load {
[[BoxFactory sharedBoxFactory]registerClass:[ImageBox class] withKey:#"image-box"];
}
-(id)initWithXmlBlock:(NSString*)xmlBlock {
[...]

I've got a few ideas:
Option 1: Change the XML
If you have control over the file format, you can then use NSClassFromString to get the Objective-C class to work with that way.
Option 2: Store you registration information in a .plist
If you store the mapping of Tag -> Class or Class -> Tag in a .plist, you can simply load that up at boot time with NSDictionary dictionaryWithContentsOfFile rather than have it all over the place in the code
Option 3: Attribute oriented approach
Decorate your classes with an property either via a category, or by protocol, this way you can query the object model at boot time and use Type Introspection to discover what classes are available and what their tags are. This avoids having to manage two things (plist and classes) and also avoids having to change the xml (sometimes a no-go because it isn't yours to muck with). It's a bit more heavy handed at boot time, but it may be an ok trade of depending on what you are doing.

Related

In Objective-C is there a way to get a list of the methods called by a method?

I have been doing some research online and have found that using the ObjectiveC package in Objective C you can get a list of all the methods on a class using class_copyMethodList(), and I see you can get the implementation (IMP) of a method using instanceMethodForSelector:. The Apple documentation here has been helpful so far but I'm stuck and not sure what I'm really looking to find.
I want a list of the methods/functions called in a given method's implementation so I can build a call tree.
Any suggestions? Thanks in advance!
This solution is kind of hard way, and will cause a line of code in every method You can also make use of sqlite and save the tracked methods..
MethodTracker.h
#interface MethodTracker : NSObject
#property (nonatomic) NSMutableArray *methodTrackArr;
+ (MethodTracker *)sharedVariables;
#end
MethodTracker.m
#implementation MethodTracker
static id _instance = nil;
+ (MethodTracker *)sharedVariables
{
if (!_instance)
_instance = [[super allocWithZone:nil] init];
return _instance;
}
// optional
- (void)addMethod:(NSString *)stringedMethod
{
// or maybe filter by: -containObject to avoid reoccurance
[self.methodTrackArr addObject:stringedMethod];
NSLog("current called methods: %#", methodTrackArr);
}
#end
and using it like:
OtherClass.m
- (void)voidDidLoad
{
[super viewDidLoad];
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
// or directly
[[MethodTracker sharedVariables].methodTrackArr addObject:[NSString stringWithUTF8String:__FUNCTION__]];
}
- (void)someOtherMethod
{
// and you need to add this in every method you have (-_-)..
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
}
i suggest you import that MethodTracker.h inside [ProjectName]-Prefix.pch file.
Sorry, for the double answer, i deleted the other one and i have no idea how did that happen..
Hope this have helped you or at least gave you an idea.. Happy coding,
Cheers!
I think in the runtime track method is possible, but function not.
I have been build a tool DaiMethodTracing for trace all methods activity in single class for some of my need. This is based on objective-c method swizzling. So, there is an idea to do this
List all Classes in your application.
swizze all the methods in each class.
filter the method you want to trace.
finally, you may got the method call path.

Create a subclass of a class using parent's init - from another class

Edit: This downvoting syndrom here sucks big time. I asked a question where I in my opinion showed that I did my homework, and asked for advice. The upvoted answers implied going with compile time warnings, whereas my own and probably most clean OOP way didn't receive any interest.
Brief overview in order to understand why I need this and what I try to do: I'm writing an ORM that implements the data mapper pattern. A mapper (i.e. for SQLite results) must create subclasses of an entity class - using the initializer of the base entity class. So there is the problem.
The mapper does not, and should not, know about specific classes. Mapping descriptions and specific mappers for different data sources are abstracted away from the entity class, and by design part of the entity description.
Entities are similar to NSManagedObject, though the ORM follows a different pattern. The description any entity is created with is similar to NSEntityDescription (but also following a different pattern and purpose).
So my goal is to create entities that I know are subclasses of ManagedEntity, using the init method of ManagedEntity.
So the init of my mapper looks like this:
- (id)initWithEntityClass:(Class)EntityClass entityDescriptor:(EntityDescription*)entityDescriptor
{
self = [super init];
if (self)
{
_EntityClass = EntityClass;
_entityDescription = entityDescription;
... (assert that class is of subclass of ManagedEntity)
}
And some time later in my mapper I then want to create the concrete entity:
-(void)createEntityWithSQLiteResultSet:(sqlite3_stmt*)resultSet
{
// Problem: How to init a class known to be a subclass of ManagedEntity?
ManagedEntity *newEntity = [[_EntityClass] alloc] initWithEntityDescription:_entityDescription];
}
So how do I create this child class of ManagedEntity, using the init of ManagedEntity?
Sure, I could use respondsToSelector() for initWithEntityDescription and invoke that. But something tells me there should be a more elegant way where the class kind is already known. Also, respondsToSelector and selector invocation will do a runtime check only. Even though the entity initializer should not change, it seems a bad choice to lose compile time checking if this method exists.
As part of your mapping, you must know what subclass you need. Then use
ManagedEntity *newEntity = [[NSClassFromString(className) alloc] initWithEntityDescription:_entityDescription];
EDIT:
I was building out this in a GitHub project as I promised and realized why it may not compile. You must have -initWithEntityDescription: declared in a known class that is accessible within the scope. In this case, it would mean that you must declare and implement ManagedEntity -initWithEntityDescription: and have have `#import "ManagedEntity.h" at the top of your file.
To reinforce Neal's correct answer that the OP claims cant work because he knows objC :)
#import <CoreData/CoreData.h>
#interface TestMapper : NSObject
- (NSManagedObject*)createClassForEntity:(NSEntityDescription*)entity context:(NSManagedObjectContext*)ctx;
#end
#import "TestMapper.h"
#implementation TestMapper
- (NSDictionary*)entityToClassMap {
return nil; //TODO ;)
}
- (NSManagedObject*)createClassForEntity:(NSEntityDescription*)entity context:(NSManagedObjectContext*)ctx {
NSString *className = self.entityToClassMap[entity.name];
assert(className);
return [[NSClassFromString(className) alloc] initWithEntity:entity insertIntoManagedObjectContext:ctx];
}
#end
alternative using the runtime you want
id cls = NSClassFromString(className);
id alloced_cls = objc_msgSend(cls, #selector(alloc));
id newEntity = objc_msgSend(alloced_cls, #selector(initWithEntity:insertIntoManagedObjectContext:), entity, ctx);
return newEntity;

Objective-C pattern for class instance variables?

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.

Objective-C: How to check if a class gets extended by a category?

In Java, you can use instanceof to check if a class extends another class or implements an interface.
In Objective-C, you can use isKindOfClass to check if a class extends another class:
if ([myObject isKindOfClass:[AnClass class]]) { }
But how can I check if a class gets extended by a category?
EDIT 2
My code of the first EDIT was unfortunately a bit confusing and nonsensical, sorry! Now, here is my new code:
I'll explain the whole problem:
I've got a class ViewCustomerCreate thats extends UITableViewController. ViewCustomerCreate gets extended by the category ICheckBox. This is my code that doesn't work:
- (void)closeModalView {
UINavigationController *parent = (UINavigationController *)self.navigationController.parentViewController;
UIViewController *parentViewContr = parent.topViewController;
if ([parentViewContr isKindOfClass:[id<ICheckBox> class]]) { // ERROR-MESSAGE see below
id<ICheckBox> parent2 = (id<ICheckBox>)parentViewContr; // works fine :-)
[parent2 setSelectedElementId:checkedIndex]; // works fine :-)
}
[self.navigationController dismissModalViewControllerAnimated:YES];
}
The error message is: "error: 'id' is not an Objective-C class name or alias"
I think that I can't use isKindOfClass to check if a class gets extended by a category, isn't it?
PS: What do I want? I have a general modal view with checkboxes and if I close this view, the parent-view should get informed what the user choose.
EDIT 3
OMG, I confounded Category with Protocol!! Aaaaahhhhh ^^
THE SOLUTION:
if ([parentViewContr conformsToProtocol:#protocol(ICheckBox)]) {
There is no way to check if a class is extended by a category, but you can check whether or not an instance responds to a particular selector with:
- (BOOL)respondsToSelector:(SEL)sel;
In Objective-C you should worry less about what an object is, and worry more about what an object can do.
If it walks like a duck, sounds like a duck and looks like a duck, then it can probably fly, you know what I mean?
You should use this as such:
if ([myObject respondsToSelector:#selector(myMethod:)])
{
// do whatever you need to do
}
Just a quick note, since you mentioned Java interfaces. You can check if an object implements a protocol (similar to Java interfaces, but not exactly the same) by using:
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
If you have defined a category on UIViewController, there are no instances of UIViewController that it is not applied to. Hence, a runtime check does not make sense.
Let's look at your actual problem:
parent.setMySpecialValue = 1; // DOES NOT WORK :-(
What does "DOES NOT WORK" actually mean? Do you get a compiler error or a runtime error. If the former, there are a couple of possible issues to loo at:
You haven't included the header file containing the category in the source file that uses that method
It is a property that you have named incorrectly. If the property is called mySpecialValue, that line of code should read:
parent.mySpecialValue = 1;
or
[parent setMySpecialValue: 1];
As of now, categories cannot define instance variables, so having a synthesized property might be an issue, so that might also be your problem, but you need to give more information about what "DOES NOT WORK" means.

Pull-up refactoring, Objective-C

I have two similar classes, MultiSlotBlock and SingleSlotBlock. They have started to share a lot of common code so I have decided to do some refactoring and pull some of the methods up to a new superclass, let's call it Block.
Now one of the methods that I pull up, simplified for the example, looks like this:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
[self doAUniqueBehaviour];
}
The problem here is that [self doAUniqueBehaviour] is showing a warning because of course my superclass doesn't implement this method anywhere.
The two solutions I thought of don't sound great to me. One is to use a protocol (the way I am currently doing it) like so:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
if ([self conformsToProtocol:#protocol(UniqueBehaviourProtocol)])
{
id<UniqueBehaviourProtocol> block = (id<UniqueBehaviourProtocol>)self;
[block doAUniqueBehaviour];
}
}
The other is to have a blank method body in my superclass (in this case there would be a lot) and just return doesNotRespondToSelector.
Something is tingling at the back of my mind that I should be using the Strategy Pattern, but I might be way off, and I haven't thought through how that would be implemented.
Any ideas? Thanks.
EDIT: I know for a fact that doAUniqueBehaviour will be implemented in all subclasses, it is just the implementation that will differ.
The superclass should not know about its subclasses. You should implement the
- (void)doACommonBehaviour method in every subclass and there:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour];
}
EDIT - clarification:
If all the subclasses are going to implement -doAUniqueBehaviour then it should be implemented in the superclass (even empty) and each subclass will override it to its needs.
If subclass1 implements -doAUniqueBehaviour1, subclass2 implements -doAUniqueBehaviour2 etc then do what I propose above; eg. in subclass1:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour1];
}
There is not such concept as abstract class in Objective-C. In order to avoid the warning, you have to provide a default implementation in your base class. Usually, this implementation will throw a doesNotRespondToSelector error at runtime:
- (id)someMethod:(SomeObject*)blah
[self doesNotRecognizeSelector:_cmd];
return nil;
}
Note: the _cmd argument is the invoked selector.
#Dimitri's suggestion will work, but instead of forcing each subclass to implement the same method, you can declare it once in Block, and just above that method (in the implementation file, not header) declare the unique method like so:
- (void) doUniqueBehaviour { }
- (void) doCommonBehaviour {
// any common code you need
[self doUniqueBehaviour];
}
This will prevent any compiler warnings, and you can override -doUniqueBehaviour in subclasses as you like. It also avoids code duplication and reduces the potential for changing the code in one subclass but not another. Plus, you don't need a separate protocol, and dynamic typing is preserved.