iOS上的线程安全懒惰初始化 [英] Thread safe lazy initialization on iOS

查看:86
本文介绍了iOS上的线程安全懒惰初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个要懒惰初始化的视图控制器,一旦初始化,在可能的情况下使用相同的副本(我不使用单例,因为我想最终将其从内存中删除),我使用吸气剂这样做,我的代码如下所示:

I have a view controller that I want to lazily initialize, and once initialized, use the same copy when possible (I don't use a singleton since I do want to remove it from memory eventually), I use the getter to do so, my code look like this:

@property (retain) UIViewController *myController

...

@synthesize myController = _myController;


...


- (UIViewController *)myController
{
    if (!_myController) {                                 // Evaluation
        _myController = [[MyViewController alloc] init];  // Object Creation
    }
    return _myController;
}

这有效,但是它不是线程安全的,并且如果在创建对象之前多个线程的求值结果为true,则将发生内存泄漏.我尝试过的一种解决方案是@synchronized代码,但是我不确定这样做的正确方法.

This works, but it's not thread safe, and if more than one thread evaluate to true before the object is created, I'll have a memory leak. One solution I've tried is to @synchronized the code, but I'm not sure the correct way to do it.

这看起来很有效,(lockForMyController是一个简单的NSString),但是这会使这段代码慢很多:

This appears to work, (lockForMyController is a simple NSString) but it makes this section of code a lot slower:

 - (UIViewController *)myController
{
    @synchronized(self.lockForMyController){
        if (!_myController) {
            _myController = [[MyViewController alloc] init];
        }
    }
    return _myController;
}

我想知道是否还有其他方法可以实现延迟初始化,线程安全的属性?

I was wondering if there is some other way to achieve a lazy initialized, thread safe, property?

推荐答案

此解决方案有效

请注意,仅当首次在后台线程上访问myController时,此解决方案才有效.如果在主线程上调用它将死锁.

Note that this solution only works if myController is accessed on a background thread the first time. It will deadlock if called on the main thread.

您要使用gcd.关键是序列化对象的创建,因此无论启动该块的线程如何,它始终只会被创建一次.

You want to use gcd. The key is serialize the creation of the object, so that regardless of the threads starting the block, it will always only be created exactly once.

- (UIViewController *)myController
    if (_myController == nil) {
        dispatch_sync(dispatch_get_main_queue(), ^ { if (_myController == nil) _myController = [[MyViewController alloc] init]; });
    }
    return _myController;
}

在这里,即使有多个线程执行该块,该块的执行也会被序列化到主线程上,并且只能创建一个MyViewController.

Here, even if multiple threads execute the block, the execution of the block is serialized onto the main thread and only one MyViewController can ever be created.

除非对象为零,否则您不会在此处看到性能下降.

You won't see a performance hit here unless the object is nil.

由于该属性是隐式原子的,这意味着在setter中,该值将被自动释放.这应该使其适合与您的自定义获取混合,因为它将自动释放对_myController的任何值更改.

Since the property is implicitly atomic, that means that in the setter the value will be autoreleased. This should make it suitable for mingling with your custom getting, since it will autorelease any value changes to _myController.

http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW2

但是,您仍然可能进入竞争状态,即您在一个线程上设置该值而在另一个线程上访问该值.每次设置该值时,您可能都想确定并执行以下操作:

However, you still may get into a race condition where you are setting the value on one thread but accessing it on another. Any time you set the value, you probably want to make sure and do something like this:

dispatch_sync(dispatch_get_main_queue(),^ {self.myController = {newValueOrNil}});

dispatch_sync(dispatch_get_main_queue(), ^ { self.myController = {newValueOrNil} });

这将确保序列化您的setter方法调用,而不必重新发明原子型setter的方法,这很难做到.

This will make sure to serialize your setter methods calls without having to reinvent the wheel for atomic setters, which is very hard to get right.

此解决方案无效

您要使用gcd.

请参阅有关单例的这篇文章.我知道您不想要单例,但这演示了如何使用该方法.您可以轻松地对其进行调整.

See this post about singletons. I know you don't want a singleton, but this demonstrates how to use the method. You can easily adapt it.

在目标C中使用GCD的dispatch_once创建单例

这篇关于iOS上的线程安全懒惰初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆