再次使用Singleton,但使用多线程和Objective-C

时间:2010-04-12 05:56:37

标签: objective-c multithreading singleton

我知道Singleton模式已经讨论过了很多。但是因为我还没有完全理解Objective-C中的内存管理机制,所以当我将Singleton实现与多线程结合起来时,我遇到了一个很大的错误,花了我一整天来解决它。

我有一个单身对象,我们称之为ObjectX。我在ObjectX内声明了一个将分离新线程的对象,当我调用

时,让我们调用该对象objectWillSpawnNewThread
[[ObjectX sharedInstance].objectWillSpawnNewThread startNewThread];

新线程无法正确执行,最后我发现我不应该在singleton类中声明对象objectWillSpawnNewThread

以下是我的问题:

  1. Objective-C如何在内存中分配静态对象? Objective-C在哪里分配它们(主线程堆栈或其他地方)?
  2. 如果我们在单例对象中生成一个新线程,为什么会失败?
  3. 我搜索了Objective-C语言[ObjC.pdf]和Objective-C memory management文档,也许我错过了一些内容,但目前我找不到任何有用的信息。

2 个答案:

答案 0 :(得分:1)

  1. 了解内存管理规则。它们很简单,一周之内你就会有时间投资。

  2. 忘记单身人士。更确切地说,忘记代码强制执行的单身人士。它们不必要地复杂化,99%的时间都是糟糕的设计。

  3. 阅读MiškoHevery的Singletons are Pathological Liars,仔细阅读,阅读所有相关博客文章并思考一下。大多数情况下,没有真正需要一个类来强制执行单个实例。通常,您可以通过创建某种类型的Factory类来解决问题,该类将为您创建大多数实例并将它们连接在一起:

    @interface Factory {
        id classYouWantJustOneInstanceOf;
    }
    
    - (id) wireMainController;
    
    @implementation Factory
    
    - (id) init {
        [super init];
        // No “sharedFoo” stuff necessary. Foo is a plain
        // class without singleton boilerplate, easily testable.
        classYouWantJustOneInstanceOf = [[Foo alloc] init];
        return self;
    }
    
    - (id) wireMainController {
        id controller = [[SomeClass alloc] init];
        // Dependencies set explicitly, good.
        [controller setFoo:classYouWantJustOneInstanceOf];
        return [controller autorelease];
    }
    
    @implementation UIApplicationDelegate
    
    - (void) applicationDidFinishLauching: (UIApplication) app {
        // Now all your “singletons” will get created,
        // no funny static stuff.
        factory = [[Factory alloc] init];
        controller = [[factory wireMainController] retain];
        [window addSubview:controller.view];
        // up and running
    }
    
    - (void) dealloc {
       [controller release];
       // Now all your “singletons” will get released.
       [factory release];
       [super dealloc];
    }
    

    我知道与“简单”[Foo sharedFoo]相比,这感觉有些不安,但是值得,相信我。


    此解决方案的优点,如果不明显:

    1. 班级中没有单独的样板文件。没有静态共享实例,没有线程同步,没有。

    2. 明确的依赖关系管理。如果A类需要B的实例来完成它的工作,你可以从公共setter或A的构造函数参数中看到它。实现文件中没有惊人的依赖。如果您需要以不同的方式连接A,比如说出于测试目的,当依赖关系是显式的时(与调用[B sharedB]相反),它会更容易。

    3. 清除对象生命周期。没有静态变量,没有静态初始化,也没有延迟初始化,除非你真的需要它。您知道何时创建对象并且您可以释放您创建的所有内容。

    4. 请注意,这是一个简化的案例,因此应用程序委托和Factory之间的划分看起来有点迂腐,但在实际情况下它很有意义(参见Principle of single responsibility)。

答案 1 :(得分:0)

除非你发布一些代码,否则很难说你做错了什么,但单身对象没有任何魔力。作为静态对象,没有任何东西。

问题1:

所有Objective-C对象都是从堆中分配的。您可以从任何范围声明指向它们的指针,但是在代码中的某个地方,直接或间接地,必须向对象的类发送alloc消息,并将结果指针初始化并分配给指针。必须在对象的init方法中初始化对象的实例变量。因此,实现单例的一种方法如下:

// Header
@interface ObjectX : NSObject
{
    SpawnObject* objectWillSpawnNewThread;
}
+(ObjectX*) sharedInstance;

// Implementation
@implementation ObjectX

-(id) init
{
    self = [super init];
    if (self != nil)
    {
        objectWillSpawnNewThread = [[SpawnObject alloc] init];
    }
    return self;
}

+(ObjectX*) sharedInstance
{
    static ObjectX* sharedInstance;
    @synchronized([ObjectX class])
    {
        if (sharedInstance == nil)
        {
            sharedInstance = [[ObjectX alloc] init];
        }
    }
    return sharedInstance;
}
@end

问题2:

除非您发布代码和错误消息,否则无法告诉您答案。但是,一个常见问题是忘记在新线程中设置自动释放池。