Chary 1.0.7

Chary 1.0.7

Maintained by nayanda1.



Chary 1.0.7

  • By
  • Nayanda Haberty

Chary

Chary is a DispatchQueue Utilities for safer sync and asynchronous programming. It helps to avoid a race condition when dealing with multithreaded application

Codacy Badge build test SwiftPM Compatible Version License Platform

Requirements

  • Swift 5.0 or higher (or 5.3 when using Swift Package Manager)
  • iOS 10.0 or higher

Only Swift Package Manager

  • macOS 10.0 or higher
  • tvOS 10.10 or higher

Installation

Cocoapods

Chary is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Chary'

Swift Package Manager from XCode

  • Add it using XCode menu File > Swift Package > Add Package Dependency
  • Add https://github.com/hainayanda/Chary.git as Swift Package URL
  • Set rules at version, with Up to Next Major option and put 1.0.4 as its version
  • Click next and wait

Swift Package Manager from Package.swift

Add as your target dependency in Package.swift

dependencies: [
  .package(url: "https://github.com/hainayanda/Chary.git", .upToNextMajor(from: "1.0.4"))
]

Use it in your target as Chary

 .target(
    name: "MyModule",
    dependencies: ["Chary"]
)

Author

Nayanda Haberty, [email protected]

License

Pharos is available under the MIT license. See the LICENSE file for more info.


Basic Usage

Two utilities come with Chary, Atomic propertyWrapper and DispatchQueue extensions

Atomic propertyWrapper

Atomic propertyWrapper is a propertyWrapper to wrap a property so it could be accessed and edited atomically:

class MyClass {
    @Atomic var atomicString: String = "atomicString"
    ...
    ...
}

then the atomicString will be Thread safe regardless of where it is accessed or edited.

DispatchQueue.main.async {
    myClass.atomicString = "from main thread"
}
DispatchQueue.global().async {
    myClass.atomicString = "from global thread"
}

DispatchQueue Extensions

Chary has some DispatchQueue Extension that will help when dealing with multithreaded.

Check current queue

You can check current DispatchQueue using isCurrentQueue(is:) which will check is the queue given is the current queue or not.

myQueue = DispatchQueue(label: "myQueue")
myQueue.sync {
    // this will print true
    print(DispatchQueue.isCurrentQueue(is: myQueue))
}
// this will print false
print(DispatchQueue.isCurrentQueue(is: myQueue))

What it did do is registering the DispatchQueue given for detection and compare the current detectable queues with the given one:

public static func isCurrentQueue(is queue: DispatchQueue) -> Bool {
    queue.registerDetection()
    return current == queue
}

Calling DispatchQueue.current will not guarantee to return the current DispatchQueue, since it can only return only DispatchQueue that already been registered for detection. There are some default DispatchQueue that will auto registered when current is called:

  • DispatchQueue.main
  • DispatchQueue.global()
  • DispatchQueue.global(qos: .background)
  • DispatchQueue.global(qos: .default)
  • DispatchQueue.global(qos: .unspecified)
  • DispatchQueue.global(qos: .userInitiated)
  • DispatchQueue.global(qos: .userInteractive)
  • DispatchQueue.global(qos: .utility)

Other than that, it will need manual call for registerDetection() to allow the DispatchQueue to be accesible by calling DispatchQueue.current. Since isCurrentQueue(is:) will automatically register the given DispatchQueue, the queue passed will be accesible from DispatchQueue.current after.

Safe Sync

Running sync from DispatchQueue sometimes can raise an exception if it is called in the same DispatchQueue. To avoid this, you can use safeSync instead which will check the current queue first and decide whether it needs to run the block right away or by using the default sync. You don't need to register the DispatchQueue since it will automatically register the DispatchQueue before checking:

DispatchQueue.main.safeSync {
    print("this will safely executed")
}

Async if needed

Sometimes you want to execute the operation right away if it's in the right DispatchQueue instead of running it asynchronously by using async. Like when you update UI, it's better if you run it right away instead of putting it in the asynchronous queue if you are already in DispatchQueue.main. You can use asyncIfNeeded to achieve that functionality right away. It will check the current DispatchQueue and decide whether it needs to run right away or by using the default async. You don't need to register the DispatchQueue since it will automatically register the DispatchQueue before checking:

DispatchQueue.main.asyncIfNeeded {
    print("this will executed right away or asynchronously if in different queue")
}

Contribute

You know-how. Just clone and do a pull request