【问题标题】:On lazy instantiation and convenience methods关于惰性实例化和便利方法
【发布时间】:2012-01-19 20:13:54
【问题描述】:

假设您有一个Singleton 常量类,您希望在整个应用程序中使用它的实例。

someClass,因此我们可以引用[Constants instance] someCleverConstant];

键入它很快就会变老,如果能获得实例的快捷方式会很好。

  • someClass中,我们可以声明@property (nonatomic, weak, readonly) Constants *constants;
  • 实例的吸气剂
-(Constants*) constants {
  if (constants == nil) 
    constants = [Constants instance];
  return constants;
}

这样在 someClass 中,因此我们可以引用 constants.someCleverConstant; 来代替

关于此的几个问题:

  • 我描述的方法是否合理?
  • 声明属性weak是否正确?
  • 我所描述的内容是否存在任何性能问题?直接调用实例真的会更好吗?
  • 假设您有 20 个类,每个类都需要它自己的指向常量实例的指针。那么这种方法行得通吗?

感谢您的宝贵时间。

【问题讨论】:

  • 这些是什么常量?

标签: objective-c lazy-initialization convenience-methods


【解决方案1】:

在 @vinceburn 之后,我将使用以下示例作为常量,将单例用于更复杂的结构。

// 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;

#define 相比,我更喜欢它,因为我可以自动完成和编译器检查,而且它更自然地适合 Apple 在某些 UIKit 类中的处理方式。

【讨论】:

  • 您已完成 #define 的代码。对于字符串以外的任何其他内容,我都会尽可能地使用#define,因为正如您所指出的那样,它更难调试。我通常只将它用于string,它们是一些key / value coding 的一部分。为了避免拼写错误。
  • 我不知道它会自动完成我对#define 的运气一直不太好,但这可能只是 xcode。出于兴趣,您为什么要使用 #define 作为字符串,而不仅仅是像我的示例中那样使用 extern?有什么优势吗?
  • 我没有大的C背景,第一次使用关键字extern时很困惑,在我学习objective-C时阅读的书中他们主要使用#define,所以我就采用了它。不知道有什么好处,除了我得到自动补全并避免了编译器无法捕获的字符串中的拼写错误,因为它们会在字符串中,但extern 也给了你。
【解决方案2】:

仅使用全局变量或函数似乎需要做很多工作。我认为其中任何一个都是更合理的方法。

【讨论】:

    【解决方案3】:

    你可以只创建一个指向你的单例的全局指针,比如NSApp for [NSApplication sharedApplication]

    大概你已经有了类似的东西

    static Constants * defaultInstance = nil;
    

    在您的实现文件的顶部。如果删除static,并在标题中声明变量(将定义保留在.m文件中):

    @interface Constants : NSObject
    // etc.
    @end
    
    extern Constants * defaultInstance;
    

    然后,您可以通过名称defaultInstance(可能想要更改该名称)在任何导入标头的文件中访问单例实例(无论如何您都必须这样做)。您必须在程序早期的某个地方调用您的单例设置方法(+instance 或其他),例如 -applicationDidFinishLaunching,以确保在使用之前设置指针。

    • 我描述的方法是否合理?

    我认为上面和 Paul.s 的回答中描述了其他更好的方法。

    • 声明属性weak是否正确?

    是的,拥有这个指针的类不需要拥有它,因为单例拥有它自己;

    • 我所描述的内容是否存在任何性能问题?直接调用实例真的会更好吗?

    无论是[Constants instance]self.constants,您都在发送消息。你第一次做self.constants,你做了两个。不过,这些都不应该是一个真正的问题。

    • 假设您有 20 个类,每个类都需要它自己的指向 Constants 实例的指针。那么这种方法行得通吗?

    对我来说,它似乎笨拙且不雅。

    【讨论】:

      【解决方案4】:

      对于常量,我更喜欢使用这样的 .h 文件

      // 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"
      

      虽然我会使用 Singleton 来返回更复杂的元素。
      这是我使用核心数据简化我的生活而不是到处重写相同代码的单例。

      @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
      

      所以在我的代码中,当我需要创建一个新实体时,我只需要这样做:

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

      有关单例概念的更多信息,请查看 Apple 文档中 Creating a Singleton Instance 部分中的 HERE,并仔细查看他们提供的用于制作单例的代码,这应该可以回答您对 weak or strong 的询问链接到它。
      但本质上,严格的单例实现只会在整个应用程序期间创建该类的一个实例。因此,如果你有 100 个对象指向它并不会改变你的记忆足迹,那么只有 1 个单例,但是如果你有 100 个对象肯定会影响你的记忆。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-28
        相关资源
        最近更新 更多