On lazy instantiation and convenience methods
Asked Answered
E

4

1

Assume you have a Singleton Constants class, instance of which you'd like to use throughout your application.

In someClass, therefore we can reference [Constants instance] someCleverConstant];

Typing this gets old really quick and it would be nice to get a shortcut to the instance.

  • In someClass, we can declare @property (nonatomic, weak, readonly) Constants *constants;
  • And a getter to the instance
-(Constants*) constants {
  if (constants == nil) 
    constants = [Constants instance];
  return constants;
}

This way in someClass, therefore we can reference constants.someCleverConstant; instead

A few questions on this:

  • Is what i described a reasonable approach?
  • Is it correct to declare a property weak?
  • Is there any performance concerns with what i have described? Would it actually be better to call instance directly?
  • Consider a situation where you have 20 classes, each needing it's own pointer to Constants instance. Would this approach work then?

Thank you for your time.

Expend answered 13/12, 2011 at 23:57 Comment(1)
What kind of constants are these?Gallard
L
1

You could just create a global pointer to your singleton, like NSApp for [NSApplication sharedApplication].

Presumably you've already got something like

static Constants * defaultInstance = nil;

at the top of your implementation file. If you remove the static, and declare the variable in your header (keeping the definition in the .m file):

@interface Constants : NSObject
// etc.
@end

extern Constants * defaultInstance;

You can then access the singleton instance via the name defaultInstance (probably want to change that name, though) in any file that imports the header (which you must be doing anyways). You'll have to call your singleton setup method (+instance or whatever) somewhere very early in your program, such as -applicationDidFinishLaunching to be sure that the pointer is set before you use it.

  • Is what I described a reasonable approach?

I think there are other, better approaches, described above and in Paul.s's answer.

  • Is it correct to declare a property weak?

Yes, the class that has this pointer doesn't need to own it, because the singleton owns itself;

  • Is there any performance concerns with what i have described? Would it actually be better to call instance directly?

Either way, [Constants instance] or self.constants you're doing a message send. The first time you do self.constants, you're doing two. None of this should be a real concern, though.

  • Consider a situation where you have 20 classes, each needing it's own pointer to Constants instance. Would this approach work then?

To me, it seems unwieldy and inelegant.

Lakieshalakin answered 14/12, 2011 at 1:6 Comment(0)
G
3

Following @vinceburn I would use the following example for constants and a singleton for more complex structures.

// Constants.h
// Replace PSMyApp for something more useful. e.g. company/name initials followed by app/class

// String example
NSString * const PSMyAppString = @"constantString"; 

// Logically related integers
typedef enum {
   PSMyAppRelatedValuesOne = 0,
   PSMyAppRelatedValuesTwo,
   PSMyAppRelatedValuesThree
} PSMyAppRelatedValues;

// Float example
const CGFloat PSMyAppFloat = 0.3f;

// Integer that has no related values
const NSInteger PSMyAppInteger = 2;

I prefer this over #define as I get auto completion and compiler checking and it fits more naturally with the way Apple does thing in some of the UIKit classes.

Gallard answered 14/12, 2011 at 0:43 Comment(3)
You got code completion for #define. And for anything else than string I stay as far as possible of #define, because it's harder to debug, like you pointed out. I usually use it only for string that are part of some key / value coding. To avoid typo.Reinaldoreinaldos
I didn't know that it autocompleted I've never had much luck with #define, but that could just be xcode. Out of interest why do you use #define for strings and not just extern like in my example? Is there any advantage?Gallard
I don't have a big C background and I got confused with the keyword extern the first time I used it, and in the book I was reading while learning objective-C they were mainly using #define, so I just adopted it. Don't know of any advantage, except that I get autocompletion and avoid typo in string that the compiler would not catch because they would be in string, but extern also give you that.Reinaldoreinaldos
B
2

This seems like a lot of work to get around just using a global variable or function. I think either of those is a more reasonable approach.

Bedaub answered 14/12, 2011 at 0:21 Comment(0)
R
1

For constant I prefer to use a .h file like this

// ConstanteDef.h
#pragma mark Entity Name Constante
#define kItemInfos @"ItemInfos"
#define kCategorie_DItems @"Categorie_DItems"
#define kCommerce @"Commerce"
#define kListe @"Liste"
#define kListeItem @"ListeItem"
#define kPrixElement @"PrixElement"
#define kTypeDe_CommerceOuListe @"TypeDe_CommerceOuListe"

While I would use the Singleton to return me more complex element.
Here is a singleton that I've made to simplify my live with core data, instead of rewriting the same code everywhere.

@interface CoreDataController : NSObject {

NSManagedObjectContext *leManagedObjectContext;
NSManagedObjectModel *leManagedObjectModel;

@private
Commerce_MO *leCommerceAucun;
}
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;

#pragma mark Objet par Défaut
@property (nonatomic, retain, readonly) Commerce_MO *commerceAucun;

#pragma mark Nouvel Objet
//  new = retain count = 1, celui qui commande est responsable de la mémoire.
- (id)newMOforClass:(Class)uneClasse;   //  Pas le mieux, mais pourrais servir pendant le run time.  Retourne nil si uneClasse ne correspond pas à quelque chose.
- (PrixElement_MO *)newPrixElement;
- (ItemInfos_MO *)newItemInfos;
- (Commerce_MO *)newCommerce;
- (Liste_MO *)newListe;
- (ListeItem_MO *)newListeItem;

#pragma mark Singleton call
+ (CoreDataController *)sharedCoreDataController;
@end

So in my code when I need to create a new entity I just need to do this :

CoreDataController *cdc = [CoreDataController sharedCoreDataController];
Liste_MO * = [cdc newListe];

For more on the Singleton concept, Look HERE in the Apple documentation at the section Creating a Singleton Instance, and look closely at the code they are giving to make a singleton, that should answer your interrogation about weak or strong link to it.
But in essence a strict singleton implementation will only have one instance of that class created for the whole duration of the application. So if you got 100 objects pointing to it doesn't change your memory foot print, there is only 1 singleton, but if you have thoses 100 objects that will definitely impact your memory.

Reinaldoreinaldos answered 14/12, 2011 at 0:35 Comment(0)
L
1

You could just create a global pointer to your singleton, like NSApp for [NSApplication sharedApplication].

Presumably you've already got something like

static Constants * defaultInstance = nil;

at the top of your implementation file. If you remove the static, and declare the variable in your header (keeping the definition in the .m file):

@interface Constants : NSObject
// etc.
@end

extern Constants * defaultInstance;

You can then access the singleton instance via the name defaultInstance (probably want to change that name, though) in any file that imports the header (which you must be doing anyways). You'll have to call your singleton setup method (+instance or whatever) somewhere very early in your program, such as -applicationDidFinishLaunching to be sure that the pointer is set before you use it.

  • Is what I described a reasonable approach?

I think there are other, better approaches, described above and in Paul.s's answer.

  • Is it correct to declare a property weak?

Yes, the class that has this pointer doesn't need to own it, because the singleton owns itself;

  • Is there any performance concerns with what i have described? Would it actually be better to call instance directly?

Either way, [Constants instance] or self.constants you're doing a message send. The first time you do self.constants, you're doing two. None of this should be a real concern, though.

  • Consider a situation where you have 20 classes, each needing it's own pointer to Constants instance. Would this approach work then?

To me, it seems unwieldy and inelegant.

Lakieshalakin answered 14/12, 2011 at 1:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.