Execute only once

Hi,

In the class A, I would like a piece of code to execute only once.

class A {

}

Note:

  1. I have multiple instances of class A, in each instance f1 could only be executed once
  2. I might not call f1 while an instance of A is created, meaning I can call it any time, only the first time it needs to get executed.
  3. Preferably without Foundation framework (but if it can't be avoided, then fine)

Question:

  1. Is my attempt a reasonable approach or is there a better way to do it ?
  2. Is it ok to have a variable do the work ? (normally I use variable to assign values)

My attempt:

class A {
    
    lazy var f1 : () = {
        
        print("cool")
    }()
}

Execution:

let a1 = A()
a1.f1
a1.f1

print("-------")

let a2 = A()
a2.f1
a2.f1

Do you care about threading? That is, for any given instance of A, is it possible that multiple threads might be calling f1 at the same time?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like

Thread safety

Thanks @eskimo, That's a good point ! I hadn't thought about it, in my current scenario it is in the same thread but would be good to make it thread safe. Would synchronisation help like DispatchQueue ?

Generally what is the way execute only once is handled (with / without thread safety) ?

Problems with my code:

1. Feels like a variable (it is a variable ;) ... I am using it to execute code)
Presently I have to write _ = f1, otherwise the compiler would throw the error Expression resolves to an unused property. Wish I could suppress the compiler error without having to write _. Is there a way to do it ?

2. Can be assigned
Since it is a lazy var it can be assigned a new value

@discardableResult

Jeremy

1 Like

Old school way

public class Singleton<T> {
    
    var _value: T?
    let lock: NSLock = NSLock()
    
    public var value { get set }
    
}

Thanks @Jeremy, I think @discardableResult is for methods / functions, but glad you pointed it out, I remember seeing it somewhere in the documentation but couldn't recollect.

Thanks @SusanCheng, I wanted it to be executed once for every instance. I have multiple instances of the same class. May be I am just twisting it too much instead of having a boolean flag.

I have lost of codes using this trick.

This is the most simple and efficient way. If you use atomic value or other methods, it always have multiple threads go on and do the computation at the same time.

Using lock can stop all the threads and only allow one thread do the computation.

1 Like

Thanks @SusanCheng, that code would help me to make my code thread safe.

You need a variable that's a function.

class Whatever {
typealias Closure = () -> Void

var f1: Closure?

init() {
    f1 = { [weak self] in
        print("hello")
        self?.f1 = nil
    }
}

}

let what = Whatever()
what.f1?()
what.f1?()
what.f1?()

1 Like

Generally what is the way execute only once is handled (with / without
thread safety) ?

While I’m happy to offer opinions on both, my advice is that you decide in advance whether thread safety is an issue and then write your code accordingly. Thread safety is not something to be taken lightly, so you don’t want to add thread safety code unless you absolutely need it.


For a single-threaded implementation, I’d just use a Boolean:

class A {

    var hasRunF1 = false

    func f1() {
        if hasRunF1 {
            return
        }
        … your code here …
    }
}

You can play games with lazy properties if you want, but using a Boolean isn’t that much more difficult and it’s really clear to the reader.


For a thread-safe implementation, lazy won’t work (static lazy properties are thread safe, but lazy properties are not). You will need to implement some form of locking. How you do that depends on a bunch of factors:

  • Do you already have a synchronisation strategy? For example, if your type is already using a Dispatch queue for synchronisation, it makes sense to piggyback off that.

  • Do you want the ‘inner’ code to run synchronously? If you use a Dispatch queue, you could have the inner code run asynchronously, which may or may not be what you want.

  • Do you have any hard dependency requirements? Earlier you said “preferably without Foundation framework”, and the obvious alternative to using a Dispatch queue is an NSLock, which is part of Foundation.

Warning If you decide to use a mutex, I strongly encourage you to use NSLock. Lower-level APIs, like pthread mutexes, have some nasty pitfalls when used from Swift.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like

Thanks @phoneyDev, this is better than my attempt, having it as a closure helps and is much nicer to call.

Thanks a lot @eskimo, yeah keeping it simple does make it more readable and makes the intent more clear.

In the current scenario, it doesn't need thread safety as it is UI code and would in the main thread.

Usually I tend to use DispatchQueue, but I didn't realise that the inner code does run asynchronously, I will try the NSLock.

Usually I tend to use DispatchQueue, but I didn't realise that the
inner code does run asynchronously

Dispatch gives you the option:

  • If you want it to run asynchronously, use async(_:…).

  • If you want it to run synchronously, use sync(_:).

If you have to be careful with the latter because it runs the risk of deadlock (just like NSLock).

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

Thanks @eskimo, I had understood your explanation incorrectly.

The methods async and sync make the intent clear.

I have pasted sample code, how I am using it.

class X {}

class A {
    
    private let xSyncQueue = DispatchQueue(label: "X Sync Queue",
                                           qos: .default,
                                           attributes: .concurrent,
                                           autoreleaseFrequency: .inherit,
                                           target: nil)
    
    private var _x  : X?
    
    var x : X? {
        
        get {
            return xSyncQueue.sync { _x }
        }
        
        set {
            xSyncQueue.sync(flags: .barrier) {
                _x = newValue
            }
        }
    }
}

Can you elaborate a bit on this? I've used os_unfair_lock for a mutex in the past, is this a bad practice?

Can you elaborate a bit on this?

The gotcha relates to pointer identity. I’m going to explain this in terms of atomics, because that’s super easy to understand, but the same problem crops up when you use low-level C APIs.

Imagine you have a C function like this:

void incrementAtomic(uint32_t * counter);

This gets imported into Swift as:

func incrementAtomic(_ counter: UnsafeMutablePointer<UInt32>!)

You might then think about wrapping that in a Swift class:

class MyAtomicCounter {

    private var counter: UInt32 = 0

    func increment() {
        incrementAtomic(&self.counter)
    }
}

This is not safe. The reason its not safe is that Swift’s & operator, as used on line 6, is not the same as C’s. Conceptually, the Swift version looks like the following:

var tmp = self.counter
incrementAtomic(&tmp)
self.counter = tmp

In many circumstances that temporary variable gets optimised away, and thus things work, but that’s not guaranteed. To guarantee that this works, you have to manage the memory yourself, so something like this:

class MyAtomicCounter {

    init() {
        self.lockPtr = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)
    }

    deinit {
        self.lockPtr.deallocate()
    }

    private var lockPtr: UnsafeMutablePointer<UInt32>

    func increment() {
        incrementAtomic(self.lockPtr)
    }
}

It’s not that this is hard code to write, it’s just a gotcha you have to be aware of. As you’ll know from my other posts, I’m a big fan of using high-level abstractions by default, and only reverting to low-level constructs if I absolutely need to. Hence my recommendation to use NSLock.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

4 Likes
Terms of Service

Privacy Policy

Cookie Policy