我正在尝试找出适合在Swift中使用的单例模型.到目前为止,我已经能够得到一个非线程安全模型:
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
}
if !Static.instance {
Static.instance = TPScopeManager()
}
return Static.instance!
}
}
Run Code Online (Sandbox Code Playgroud)
在Static结构中包装单例实例应允许单个实例在没有复杂命名方案的情况下不与单例实例发生冲突,并且它应该使事情变得相当私密.显然,这个模型不是线程安全的,所以我尝试将dispatch_once添加到整个事情中:
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
static var token: dispatch_once_t = 0
}
dispatch_once(Static.token) { Static.instance = TPScopeManager() }
return Static.instance!
}
}
Run Code Online (Sandbox Code Playgroud)
但我得到一个编译器错误dispatch_once:
无法将表达式的类型'Void'转换为'()'类型
我已经尝试了几种不同的语法变体,但它们似乎都有相同的结果:
dispatch_once(Static.token, { Static.instance = TPScopeManager() })
Run Code Online (Sandbox Code Playgroud)
dispatch_once使用Swift 的正确用法是什么?我最初认为问题出在块中,因为dispatch_once错误消息,但我看的越多,我认为可能是获得() …
是否可以在单元测试tearDown中重置dispatch_once代码的状态?
我认为如果我们的单元测试可以从一个非常干净的状态运行会很好,但我们正在努力使用dispatch_once和一些使用dispatch进行的单例测试.
到目前为止,我已经看到了这些问题的答案(1,2,3)建议使用GCD是dispatch_once这样的:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
Run Code Online (Sandbox Code Playgroud)
输出:
This is printed only on the first call to test()
This is printed for each call to test()
Run Code Online (Sandbox Code Playgroud)
但是等一下.token是一个变量,所以我可以很容易地做到这一点:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call …Run Code Online (Sandbox Code Playgroud) 有多个源调用特定方法,但我想确保它被调用一次(每个对象)
我想使用类似的语法
// method called possibly from multiple places (threads)
-(void)finish
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self _finishOnce]; // should happen once per object
});
}
// should only happen once per object
-(void)_finishOnce{...}
Run Code Online (Sandbox Code Playgroud)
问题是令牌是在同一个类的所有实例中共享的 - 所以不是一个好的解决方案 - 每个对象是否有dispatch_once_t - 如果不是,确保它被调用一次的最佳方法是什么?
编辑:
这是我想到的一个提议的解决方案 - 它看起来好吗?
@interface MyClass;
@property (nonatomic,strong) dispatch_queue_t dispatchOnceSerialQueue; // a serial queue for ordering of query to a ivar
@property (nonatomic) BOOL didRunExactlyOnceToken;
@end
@implementation MyClass
-(void)runExactlyOnceMethod
{
__block BOOL didAlreadyRun = NO;
dispatch_sync(self.dispatchOnceSerialQueue, ^{
didAlreadyRun …Run Code Online (Sandbox Code Playgroud) 如何使用displatch_once,因此每个实例生命周期执行一次给定的代码
等价的是在对象中有一个属性,并像这样使用它
- (void)viewWillAppear:(..).. {
...
if (self.isDisplatched == NO) {
...
self.isDisplatched = YES;
}
}
Run Code Online (Sandbox Code Playgroud)
但我不想使用额外的属性,而是dispatch_once_t或simmilar
假设我们覆盖scrollViewDidScroll方法,并且只有第一次滚动,我们想要doSomething()
一个简单的方法是实现这是一个实例级布尔变量并切换/检查它.
func scrollViewDidScroll(scrollView: UIScrollView!) {
if(!scrolled) {
scrolled = true;
doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
我想要一个不引入布尔变量的更好的解决方案scrolled.类似dispatch_once但对象的生命周期而不是整个过程.
这个模式有名字吗?
在 Swift 3 中,dispatch_once 函数被移除,迁移指南建议使用初始化闭包:
let myGlobal = { ... global 在对闭包的调用中包含初始化 ... }()
_ = myGlobal // 使用 myGlobal 将仅在第一次使用时调用初始化代码。
我想从初始化闭包中访问“self”实例变量,如下所示:
class SomeClass {
var other = SomeOtherClass()
let initialize: () = {
// self.other - this doesn't work, complains about unresolved identifier 'self'
// how to access self.other here?
} ()
func doSomething() {
// initialize will only be called once
initialize
}
}
Run Code Online (Sandbox Code Playgroud)
为什么在闭包中无法访问“自我”,以及如何使其成为?