How to use NSlock in ios

NSlock in ios : It is rare anymore that NSLock is the right tool for the job. There much better tools now, particularly with GCD.That’s very hard to implement without deadlocking if you’re trying to lock and unlock on different threads. The fundamental problem is that if lock blocks the thread, then there is no way for the subsequent unlock to ever run on that thread, and you can’t unlock on a different thread.

Better yet; use an NSOperationQueue or a GCD queue as your synchronization primitive.

An NSLock is a mutex; it prevents multiple threads from accessing the same resource simultaneously, which is exactly what you want to do here. Once one thread acquires the lock, other threads attempting to acquire the lock will wait until the first thread releases the lock.

You’ll want to create a lock and store it somewhere that persists across and between function calls, most likely in an instance variable in this case. To acquire the lock, call its lock method, and to release it, use unlock:

EXAMPLE-1

var checkOne = false

var checkTwo = false

//create the lock
let lock = NSLock()
func functionOne(){
//async stuff
//acquire the lock
lock.lock()
checkOne = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
//release the lock
lock.unlock()
}
func functionTwo(){
//async stuff
lock.lock()
checkTwo = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
lock.unlock()
}
func functionThree(){
//your code goes here
}
override func viewDidLoad() {

functionOne()
functionTwo()
}

EXAMPLE-3

A more “modern” approach is to use a DispatchQueue instead of an NSLock. Dispatch is higher-level than APIs like NSLock and NSThread; instead of directly working with locks and threads, you’ll use queues.

A serial dispatch queue works like a checkout line at a store. You submit blocks of code to the queue, and it executes them one at a time in the order they were received. You can also create a concurrent dispatch queue which executes its tasks simultaneously by passing .concurrent to the options parameter of the DispatchQueue initializer.

A serial dispatch queue is an easy way to protect a resource from being accessed by multiple threads at once — just create a queue for that resource, and put every access to that resource on the queue.

//Create a serial dispatch queue
let queue = DispatchQueue(label: "name of queue")
func functionOne(){
//async stuff

//Add a task to the queue, and execute it synchronously (i.e. wait for it to finish.)
//You can also use async to execute a task asynchronously,
//but sync is slightly more efficient unless you need it to be asynchronous.
queue.sync {
checkOne = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
}
}
func functionTwo(){
//async stuff
queue.sync {
checkTwo = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
}
}
func functionThree(){
//stuff
}
override func viewDidLoad() {

functionOne()
functionTwo()
}

EXAMPLE-3 

class ViewController: UIViewController {

let group = DispatchGroup()

override func viewDidLoad() {
super.viewDidLoad()

group.enter()
functionOne()

group.enter()
functionTwo()

group.notify(queue: .global(qos: .default), execute: { [weak self] in
self?.functionThree()
})
}

func functionOne() {
//async stuff

group.leave()
}

func functionTwo() {
//async stuff

group.leave()
}

func functionThree() {
//stuff
}
}

EXAMPLE-4

private var taskDelegate: TaskDelegate
private var taskDelegateLock = NSLock()

/// The delegate for the underlying task.
open internal(set) var delegate: TaskDelegate {
get {
taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
return taskDelegate
}
set {
taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
taskDelegate = newValue
}
}

init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
self.session = session

switch requestTask {
case .data(let originalTask, let task):
taskDelegate = DataTaskDelegate(task: task)
self.originalTask = originalTask
case .download(let originalTask, let task):
taskDelegate = DownloadTaskDelegate(task: task)
self.originalTask = originalTask
case .upload(let originalTask, let task):
taskDelegate = UploadTaskDelegate(task: task)
self.originalTask = originalTask
case .stream(let originalTask, let task):
taskDelegate = TaskDelegate(task: task)
self.originalTask = originalTask
}

delegate.error = error
delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
}
/// The delegate for the underlying task.
open internal(set) var delegate: TaskDelegate {
get {
taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
return taskDelegate
}
set {
taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
taskDelegate = newValue
}
}
Scroll to Top

Discover more from CODE t!ps

Subscribe now to keep reading and get access to the full archive.

Continue reading