Factory Pattern - Example in Objective-C - objective-c

I'm trying to get a better grip on the Factory Pattern as illustrated here:
http://www.oodesign.com/factory-pattern.html
The examples are in Java, and I'm not a very strong Java programmer. I mostly don't understand the Constructor product ... = cClass... String.class line. I think I've got the "concept," but are these two code blocks analogous?
Furthermore, is there an example in Cocoa Foundation that uses this pattern? The only one I can think of is in UIKit registering cell classes against a UITableView.
Java:
class ProductFactory
{
private HashMap m_RegisteredProducts = new HashMap();
public void registerProduct (String productID, Class productClass)
{
m_RegisteredProducts.put(productID, productClass);
}
public Product createProduct(String productID)
{
Class productClass = (Class)m_RegisteredProducts.get(productID);
Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
return (Product)productConstructor.newInstance(new Object[] { });
}
}
Objective-C:
#interface ProductFactory : NSObject
- (void)registerProduct:(Class)productClass withIdentifier:(NSString *)identifier;
- (id)newProductForIdentifier:(NSString *)identifier;
#end
#interface ProductFactory();
#property (strong, nonatomic) NSMutableDictionary *registeredProducts;
#end
#implementation ProductFactory
- (id)init
{
self = [super init];
if (self) {
_registeredProducts = [NSMutableDictionary dictionary];
}
return self;
}
- (void)registerProduct:(Class)productClass withIdentifier:(NSString *)identifier
{
self.registeredProducts[identifier] = NSStringFromClass(productClass);
}
- (id)newProductForIdentifier:(NSString *)identifier
{
NSString *classString = self.registeredProducts[identifier];
Class productClass = NSClassFromString(classString);
return [[productClass alloc] init];
}
#end

Yes, that is generally analogous. I haven't done java for a little while so I can't explicitly explain the Constructor line but it's kind of like the definition of a designated initialiser and how to find it.
You could do a little work with #protocols to allow a range of init methods to be available for the instantiation and interrogate the class to see which protocol it conforms to (using conformsToProtocol:).

Related

Obj-C Variable Stack Type

As a foray into new programming languages, I build well known data structures to familiarize myself with the syntax and the basic ins & outs of the language. In this case, I examine the stack in Objective-C. From Apple's Working with Objects we read about the keyword 'id'
...This is a special keyword used in Objective-C to mean “some kind of object.” It is a pointer to an object, like (NSObject *), but is special in that it doesn’t use an asterisk.
By using the keyword 'id', it seems possible to create a stack data structure that holds differing types of Obj-C objects; however, I am not sure if this as intended. Is it better to create the various class methods for each potential data type rather than attempting a generic method and make sure each stack adheres to a single Object type?. Here is what I have so far
XYZNode.h
#import <Foundation/Foundation.h>
#interface XYZNode : NSObject
#property id value;
#property XYZNode *next;
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext;
-(instancetype)init;
// Class factory methods should always start with the name of
// the class (without the prefix) that they create, with the
// exception of subclasses of classes with existing factory methods.
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext;
#end
XYZNode.m
#import "XYZNode.h"
#implementation XYZNode
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext {
if (self = [super init]) {
_value = aValue;
_next = aNext;
} return self;
}
-(instancetype)init {
return [self initWithValue:nil next:nil];
}
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext {
return [[self alloc] initWithValue:aValue next:aNext];
}
#end
XYZStack.h
#import <Foundation/Foundation.h>
#interface XYZStack : NSObject
-(void)pushValue:(id)aValue;
-(id)popValue;
-(BOOL)isEmpty;
-(instancetype)init;
-(instancetype)initWithValue:(id)aValue;
+(XYZStack *)stackWithValue:(id)aValue;
#end
XYZStack.m
#import "XYZStack.h"
#import "XYZNode.h"
// The extension hides how the values are stored
#interface XYZStack ()
#property XYZNode *lastNodeAdded;
#end
#implementation XYZStack
// Default initializer
-(instancetype)initWithValue:(id)aValue {
if (self = [super init]) {
_lastNodeAdded = nil;
}
if (aValue) {
[self pushValue:aValue];
}
return self;
}
// Call default initializer
-(instancetype)init{
return [self initWithValue:nil];
}
-(BOOL)isEmpty{
return ([self lastNodeAdded] == nil);
}
-(void)pushValue:(id)aValue {
[self setLastNodeAdded:[XYZNode nodeWithValue:aValue nextNode:[self lastNodeAdded]]];
}
-(id)popValue {
id temp = [[self lastNodeAdded] value];
[self setLastNodeAdded:[[self lastNodeAdded] next]];
return temp;
}
+(XYZStack *)stackWithValue:(id)aValue {
return [[self alloc] initWithValue:aValue];
}
#end
Any comments would be appreciated.

How do I add an Object to an array via a static(+) method?

// Marketplace.h
#import <Foundation/Foundation.h>
#import "Item.h"
#interface Marketplace : NSObject
+ (void)addItemToMarketplace:(Item *)newItem; // METHOD IN QUESTION
#end
// Marketplace.m
#import "Marketplace.h"
#interface Marketplace()
#property (strong, nonatomic) NSMutableArray *listOfItems;
#end
#implementation Marketplace
+ (void)addItemToMarketplace:(Item *)newItem // METHOD IN QUESTION
{
[self.listOfItems addObject:newItem]; // Raises 3 errors
}
#end
I have declared a class method addItemToMarketplace that takes in an object of type Item and adds this Item to the listOfItems property that I have declared in the interface of the implementation file (I am not sure that I want other classes to fiddle with this property). I have used this method in another class as such [Marketplace addItemToMarketplace:newItem]. I am not sure how to handle the three errors that are raised when I write [self.listOfItems addObject:newItem].
The 3 errors are as follows:
1. Member reference type 'struct objc_class *' is a pointer; maybe you meant to use '->'?
2. Definition of 'struct objc_class' must be imported from module 'ObjectiveC.runtime' before it is required
3. No member named 'listOfItems' in 'struct objc_class'
Making the change proposed in #1, which changes self.listOfItems to self->listOfItems, raises the error "Member reference base type 'Class' is not a structure or union"
Any help would be appreciated.
// NEW CHANGES!
After making some changes and following some suggestions I found on other sites, here's what I have so far:
// Marketplace.h
#import <Foundation/Foundation.h>
#import "Item.h"
#interface Marketplace : NSObject {}
+ (Marketplace *)sharedMarket;
- (void)addItemToMarketplace:(Item *)newItem;
#end
// Marketplace.m
#import "Marketplace.h"
#interface Marketplace()
#property (strong, nonatomic)NSMutableArray *listOfItems;
#end
static Marketplace *sharedMarketplace = nil;
#implementation Marketplace
+ (Marketplace *)sharedMarket
{
if (sharedMarketplace == nil) {
sharedMarketplace = [[super allocWithZone:NULL] init];
}
return sharedMarketplace;
}
- (void)addItemToMarketplace:(Item *)newItem
{
[self.listOfItems addObject:newItem];
}
- (id)init
{
if ( (self = [super init]) ) {
}
return self;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedMarket];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#end
Questions, comments, concerns?
Only the instance methods can operate on instance data. So you need either an instance or change the data to static too:
#interface Marketplace()
#end
static NSMutableArray *listOfItems; // static is implied, so not really necessary
#implementation Marketplace
+ (void)addItemToMarketplace:(Item *)newItem {
if (!listOfItems) listOfItems = [NSMutableArray array];
[listOfItems addObject:newItem];
}
#end
Note that there's no thread safety here.
The + prefix defines a class method. Within that method self refers to the class itself which is almost certainly not what you intend. The class does not have a listOfItems as that is a property available on each instance of the class.
It is not clear what you are attempting to do here. If you are coming from a C/C++ background perhaps you have assumed a different behavior for this method. Are you trying to add an item to a list managed by a particular instance of this class or to a list shared across all instances?
If you just have one instance of marketplace in your app consider using a singleton..
You then might add items to the single marketplace like this:
[[Marketplace theMarketplace] addItem:<*item*>]
Here's one way to set this up:
#interface Marketplace : NSObject
#property ( nonatomic ) NSArray * items ;
#end
#implementation Marketplace
static Marketplace * __marketplace ;
+(void)load
{
__marketplace = [ Marketplace new ] ;
}
+(instancetype)theMarketplace
{
return __marketplace ;
}
-(void)addItem:(Item*)item
{
self.items = [ ( self.items ?: #[] ) arrayByAddingObject:item ] ;
}
#end
(or in Swift)
class Marketplace
{
struct Static
{
static let marketplace = Marketplace()
}
var items:Array<Item> = [] ;
class func get() -> Marketplace { return Static.marketplace }
func addItem( item: Item ) { self.items += item }
}

trying to understand the Singleton concept in objective-c with many variables

I'm trying to understand the Singleton concept in objective-c.
Most examples that I did found just refer to a single variable.
I'm a bit lost about how to adapt the examples to handle many variables as per an example the accelerometer values that return x, y, z.
Can you guide me a bit further ?
A Singleton refers to a special object that can only exist once inside the lifespan of your application. That object can have as many variables and properties as necessary.
// Singleton.h
#interface Singleton : NSObject
#property (readwrite) int propertyA;
#property (readwrite) int propertyB;
#property (readwrite) int propertyC;
+ (Singleton *)sharedInstance;
#end
The key to a Singleton is that it can only be created once. Usually in Objective-C we use the #synchronized() directive to make sure it only gets created once. We put this in a convenience class method called sharedInstance and return our Singleton. Since the Singleton is just an object it can easily have multiple properties, variables, and methods.
// Singleton.m
#import "Singleton.h"
#interface Singleton ()
{
int variableA;
int variableB;
int variableC;
}
#end
#implementation Singleton
static Singleton *sharedInstance = nil;
+ (Singleton *)sharedInstance
{
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[Singleton alloc] init];
}
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [super allocWithZone:zone];
return sharedInstance;
}
}
return nil;
}
- (id)init {
self = [super init];
if (self) {
// Inits
}
return self;
}
#end
This is not the ONLY way to create a Singleton. Remember the important part is it can only be created once. So you can take advantage of newer Grand Central Dispatch calls when developing for OSX and iOS such as dispatch_once.
Talking to the Singleton
So lets say you have another object elsewhere talking to the Singleton. This can be done anywhere you #import "Singleton.h"
- (void)someMethod
{
// Setting properties
int valueA = 5;
[[Singleton sharedInstance] setPropertyA:valueA];
// Reading properties
int valueB = [[Singleton sharedInstance] propertyB];
}

Objective-C Proper way to create class with only one instance

I am trying to implement a class, that subclasses NSObject directly, that can only have one instance available throughout the entire time the application using it is running.
Currently I have this approach:
// MyClass.h
#interface MyClass : NSObject
+(MyClass *) instance;
#end
And the implementation:
// MyClass.m
// static instance of MyClass
static MyClass *s_instance;
#implementation MyClass
-(id) init
{
[self dealloc];
[NSException raise:#"No instances allowed of type MyClass" format:#"Cannot create instance of MyClass. Use the static instance method instead."];
return nil;
}
-(id) initInstance
{
return [super init];
}
+(MyClass *) instance {
if (s_instance == nil)
{
s_instance = [[DefaultLiteralComparator alloc] initInstance];
}
return s_instance;
}
#end
Is this the proper way to accomplish such a task?
Thanks
You need to do a little more than that. This describes how an objective-c singleton should be implemented: Objective-C Singleton
In your scenario, there is still a way to create a second instance of your class:
MyClass *secondInstance = [[MyClass alloc] initInstance]; //we have another instance!
What you want is to override your class's +(id)alloc method:
+(id)alloc{
#synchronized(self){
NSAssert(s_instance == nil, #"Attempted to allocate a second instance of singleton(MyClass)");
s_instance = [super alloc];
return s_instance;
}
return nil;
}

Objective-C supertype polymorphism

I'm fairly new to Objective-C and wondering if it's possible to type objects as their supertype without receiving compiler warnings when assigning them, or if there is a recognised way of achieving the same thing?
I realise that this is what type id is for but I have a base class with synthesized properties and if I try to use id I get a build error "request for member 'x' in something not a structure or union", presumably because dynamic typing is fine for sending messages to an object but not for accessing synthesized properties.
For example in Java I might have:
public abstract class A {
public function doSomething() {
//some func
}
}
public class B extends A {
public function doSomething() {
//override some func
}
}
public class C extends A {
public function doSomething() {
//override some func
}
}
//and in my main class:
A objB = new B();
A objC = new C();
//the purpose of all of this is so I can then do:
A objHolder;
objHolder = objB;
objHolder.doSomething();
objHolder = objC;
objHolder.doSomething();
I currently have the above working in Objective-C but with a compiler warning: "assignment from distinct Objective-C type"
OK, here is the Objective-C interfaces, I can add the implementations if you want. It's a composite pattern:
//AbstractLeafNode
#import <Foundation/Foundation.h>
#interface AbstractLeafNode : NSObject {
NSString* title;
AbstractLeafNode* parent;
}
#property (nonatomic, retain) NSString* title;
#property (nonatomic, retain) AbstractLeafNode* parent;
#end
//Page
#import "AbstractLeafNode.h"
#interface Page : AbstractLeafNode {
//there will be stuff here later!
}
#end
//Menu
#import "AbstractLeafNode.h"
#interface Menu : AbstractLeafNode {
NSMutableArray* aChildren;
}
- (void)addChild:(AbstractLeafNode *)node;
- (void)removeChild:(AbstractLeafNode *)node;
- (AbstractLeafNode *)getChildAtIndex:(NSUInteger)index;
- (AbstractLeafNode *)getLastChild;
- (NSMutableArray *)getTitles;
#end
// I'd then like to do something like (It works with a warning):
AbstractLeafNode* node;
Menu* menu = [[Menu alloc] init];
Page* page = [[Page alloc] init];
node = menu;
[node someMethod];
node = page;
[node someMethod];
// Because of the synthesized properties I can't do this:
id node;
// I can do this, but I suspect that if I wanted synthesized properties on the page or menu it would fail:
node = (AbstractLeafNode*)menu;
node = (AbstractLeadNode*)page;
Sorry, as I was editing the question I realised that I was trying to do it the wrong way round and assign an AbstractLeafNode to a Menu, so the compiler warning completely makes sense. No errors when assigning a Menu to an AbstractLeafNode.
I've been staring at this for too long!