Swift 3 - Atomic boolean - swift

Does anybody know how to make an atomic boolean in iOS 10?
Current code:
import UIKit
struct AtomicBoolean {
fileprivate var val: UInt8 = 0
/// Sets the value, and returns the previous value.
/// The test/set is an atomic operation.
mutating func testAndSet(_ value: Bool) -> Bool {
if value {
return OSAtomicTestAndSet(0, &val)
} else {
return OSAtomicTestAndClear(0, &val)
}
}
/// Returns the current value of the boolean.
/// The value may change before this method returns.
func test() -> Bool {
return val != 0
}
}
The code works as expected, but i keep getting the warning:
'OSAtomicTestAndSet' was deprecated in iOS 10.0: Use atomic_fetch_or_explicit(memory_order_relaxed) from <stdatomic.h> instead
I can't get it to work with atomic_fetch_or_explicit(memory_order_relaxed).
Does anyone know how to convert my current code to iOS 10, in order to get rid of this warning?
Thank you!

the better way is to avoid it ... If you would like to mimick it just to synchronise access to your AtomicBoolean, use synchronisation avaiable in GCD
for example
import PlaygroundSupport
import Foundation
import Dispatch
PlaygroundPage.current.needsIndefiniteExecution = true
let q = DispatchQueue(label: "print")
struct AtomicBoolean {
private var semaphore = DispatchSemaphore(value: 1)
private var b: Bool = false
var val: Bool {
get {
q.async {
print("try get")
}
semaphore.wait()
let tmp = b
q.async {
print("got", tmp)
}
semaphore.signal()
return tmp
}
set {
q.async {
print("try set", newValue)
}
semaphore.wait()
b = newValue
q.async {
print("did", newValue)
}
semaphore.signal()
}
}
}
var b = AtomicBoolean()
DispatchQueue.concurrentPerform(iterations: 10) { (i) in
if (i % 4 == 0) {
_ = b.val
}
b.val = (i % 3 == 0)
}
prints
try get
try set false
try set false
try set true
did false
got false
try get
try set true
did false
try set false
did true
did true
try set true
try set false
got false
try set false
did false
try get
did true
try set true
did false
did false
got false
try set false
did true
did false

Apple confirmed that read and write of Bool value is not an atomic operation in Swift.
But there are many ways to synchronize.
Example
Somewhere add below global-function logic:
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return try body()
}
And use like:
let myLock = NSObject();
// ...
synchronized(myLock) {
// Something not thread safe here...
}

Your first option is to...
just use a regular lock and guard your value access, the other is...
to use Swift Atomics
Then you can just say
var value = ManagedAtomic<UInt8>(0)
// Atomic store
value.store(2, ordering: .relaxed)
// Atomic load
value.load(ordering: .relaxed)

Related

Swift PropertyWrapper for waiting on a value to set for the first time not working

I intend to wait for the value is set for the first time and then the get method should return. But I am getting wrong result on the first time. Here is the code
import Foundation
import OSLog
#propertyWrapper
struct WaitTillSet<T> {
private var value: T
private let group: DispatchGroup
init(wrappedValue value: T) {
self.group = DispatchGroup()
self.value = value
group.enter()
}
var wrappedValue: T {
get { getValue() }
set { setValue(newValue: newValue) }
}
mutating func setValue(newValue: T) {
value = newValue
group.leave()
}
func getValue() -> T {
group.wait()
return value
}
}
let logger = Logger()
func testFunc() {
#WaitTillSet var data = 0
DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 2) {
logger.info("Setting value to 10")
data = 10
}
logger.info("data = \(data)")
logger.info("dataAgain = \(data)")
}
testFunc()
And here is the output
2022-08-23 10:57:39.867967-0700 Test[68117:4747009] Setting value to 10
2022-08-23 10:57:39.868923-0700 Test[68117:4746644] data = 0
2022-08-23 10:57:39.869045-0700 Test[68117:4746644] dataAgain = 10
Program ended with exit code: 0
I also tried DispatchSemaphore. That gives the same result. Instead of propertyWrapper if I use class in the similar way I see the same problem. There is something fundamentally wrong with this.

Extends Set's insert in swift for custom logic

I need to have custom logic in a Set that defines when a Hashable can be insert or not.
First I tried to solve this with a observer
var Tenants: Set<Tenant> = [] {
willSet {
// to the business logic here
// ...
But in an observer i can not return an error. So I tried to extend Set to overwrite the insert method.
extension Set where Element == Tenant {
#inlinable mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element){
// .... do my logic here ...
return (true, newMember)
}
}
That works so far and the method will be called. I can return true and if my logic did not pass even a false. Ok, but how do I add the Element into the Set? super.insert(). The return is correct, but the Set is empty. How to add the elements into the concrete set?
Implementation so far
/// Global set of known tenants
var Tenants: Set<Tenant> = [] {
willSet {
let newTenants = newValue.symmetricDifference(Tenants)
guard let newTenant = newTenants.first else {
Logging.main.error("Can not find tenant to add.")
return
}
Logging.main.info("Will add new Tenant \(newTenant.name) [\(newTenant.ident)]")
}
}
extension Set where Element == Tenant {
#inlinable mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element){
print("Check to add...")
// .... do my logic here ...
// ok
return (true, newMember)
}
}
The result is:
Check to add...
error : Can not find tenant to add.
Check to add...
error : Can not find tenant to add.
This seems to work for "do my logic here"
self = self.union([newMember])
Edit: Because this breaks the semantics of Set, I think it is better to write it as something like this:
struct CheckedSet<T: Hashable> {
private(set) var wrappedSet: Set<T> = []
var shouldInsert: (T) -> Bool = { _ in true }
mutating func maybeInsert(_ t: T) {
guard shouldInsert(t) else { return }
wrappedSet.insert(t)
}
}
var cs = CheckedSet<String>()
cs.shouldInsert = { str in str.allSatisfy(\.isLowercase) }
cs.maybeInsert("HELLO")
cs.wrappedSet // []
cs.maybeInsert("hello")
cs.wrappedSet // ["hello"]
I would do it with a property wrapper:
#propertyWrapper
struct TenantsSet {
var wrappedSet: Set<Tenant>
struct Projected {
let error: Bool
}
var projectedValue = Projected(error: false)
var wrappedValue: Set<Tenant> {
get { wrappedSet }
set {
print("some custom logic")
// set projectedValue appropriately
wrappedSet = newValue
}
}
init(wrappedValue: Set<Tenant>) {
wrappedSet = wrappedValue
}
}
This allows error-reporting by checking the error property on the projected value:
#TenantsSet var tenants = []
func f() {
tenants = [Tenant()]
if $tenants.error {
}
}
As the Swift Guide says:
Extensions add new functionality to an existing class, structure, enumeration, or protocol type.
You are not supposed to use them to modify existing behaviour. It would be very confusing to readers of your code. If you want to use an extension to do this, you should declare a new method, with a different signature. Perhaps call it insert(newTenant:)?

XCTWaiter().wait with XCTestExpectation and NSPredicate seems to fail

I am trying to write unit tests where I want my test case to wait for a variable in a certain class to change. So I create an expectation with a predicate and wait for the value to change using XCTWaiter().wait(for: [expectation], timeout: 2.0), which I assume is the correct method to use.
The following code works as expected:
class ExpectationTests: XCTestCase {
var x: Int = 0
private func start() {
_ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in
self.x = 1
}
}
func test1() {
let predicate = NSPredicate(format: "x == 1")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: self)
start()
let result = XCTWaiter().wait(for: [expectation], timeout: 2.0)
switch result {
case .completed: XCTAssertEqual(x, 1)
case .timedOut: XCTFail()
default: XCTFail()
}
}
A variable (x) is set to 0 and then changes to 1 after 0.5s by the start() function. The predicate waits for that var (x) to change. That works: result is set to .completed and the var actually is set to 1. Yeah :-)
However, when the variable that I want to observe is not a local var, but is in a class somewhere, it no longer works. Consider the following code fragment:
class MyClass: NSObject {
var y: Int = 0
func start() {
_ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in
self.y = 1
}
}
}
func test2() {
let myClass = MyClass()
let predicate = NSPredicate(format: "y == 1")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: myClass)
myClass.start()
let result = XCTWaiter().wait(for: [expectation], timeout: 2.0)
switch result {
case .completed: XCTAssertEqual(myClass.y, 1)
case .timedOut: XCTFail()
default: XCTFail()
}
}
It is quite similar to the first piece of code, but this always ends after 2 seconds with result being .timedOut. I can't see what I am doing wrong. I use a variable from object myClass that I pass into the expectation instead of a local var and object 'self'. (The class var myClass.y is actually set to 1 when the test ends.)
I tried replacing XCTNSPredicateExpectation(predicate:object) with expectation(for:evaluatedWith:handler), but that didn't make any difference.
Many examples here on StackOverflow use a predicate that checks for exists in XCUIElement. But I am not testing UI; I just want to check if some var in some class has changed within a timeout period. I don't understand why that is so different from checking var exists in XCUIElement.
Any ideas?! Thank you in advance!
Well, thanks to #Willeke for pointing me in the right direction, I did find a solution, but I can't say I understand it completely...
Here's what my code looks like now:
// MARK: - Test 2
class MyClass: NSObject {
var y: Int = 0
func start() {
_ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in
self.y = 1
}
}
}
func test2() {
let myClass = MyClass()
let predicate = NSPredicate() { any, _ in
// guard let myClass = any as? MyClass else { return false }
return myClass.y == 1
}
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: myClass)
myClass.start()
let result = XCTWaiter().wait(for: [expectation], timeout: 2.0)
switch result {
case .completed: XCTAssertEqual(myClass.y, 1)
case .timedOut: XCTFail()
default: XCTFail()
}
}
I can use a predicate with a closure that regularly checks whether the var has changed and returns true if it has the correct value. (It does that about once per second.) However, I actually thought that's what XCTWaiter was for, given the description in the documentation of expectation(for:evaluatedWith:handler:) (which is a convenience method for XCTNSPredicateExpectation):
The expectation periodically evaluates the predicate. The test fulfills the expectation when the predicate evaluates to true.
So, I am happy that I can move on, but I still don't understand why this doesn't work with NSPredicate(format: "y == 1") instead of the predicate with the closure...

Weak reference becomes nil after dispatch into serial queue

I've toyed around with Swift Playground and noticed the following issue:
The code below describes a series of object connected to one another in the following way:
objectC --> ObjectB -- weak ref to another C --> another C --> Object B etc..
Each objectC consists of
- a ref to a object B
- a weak ref to a delegate => this one becomes nil!!
Each objectB consists of
- A var integer
- A weak ref to another object C
The code does the following:
objectC call a function, say run(), which will evaluate (objectB.weak_ref_to_another_C), and call objectB.weak_ref_to_another_C.run() in a serial Queue.
After calling .run() a couple of times, C's delegate mysteriously becomes nil....
Any idea what I'm doing wrong? To start the code, simply call test_recursive_serial() on Swift Playground.
let serialQueue = DispatchQueue(label: "myQueue");
public protocol my_protocol:class {
func do_something(ofValue:Int,completion:((Int) -> Void))
}
public class classA:my_protocol {
public let some_value:Int;
public init(value:Int){
self.some_value = value;
}
public func do_something(ofValue:Int,completion:((Int) -> Void)) {
print("A:\(some_value) in current thread \(Thread.current) is executing \(Thread.current.isExecuting)");
if self.some_value == ofValue {
completion(ofValue);
}
}
}
public class classB {
public weak var jump_to_C:classC?;
public var value:Int = 0;
}
public class classC {
weak var delegate:my_protocol?{
willSet {
if (newValue == nil) { print("target set to nil") }
else { print("target set to delegate") }
}
}
var someB:classB?
public func do_something_else() {
print(self.delegate!)
}
public func do_another(withValue:Int,completion:((Int) -> Void)) {
}
public func run(completion:#escaping ((Int) -> Void)) {
print("\(self.someB?.value)");
assert(self.delegate != nil, "not here");
if let obj = someB?.jump_to_C, obj !== self {
someB?.value += 1;
print("\(someB!)")
usleep(10000);
if let value = someB?.value, value > 100 {
completion(someB!.value);
} else {
serialQueue.async {
print("lauching...")
obj.run(completion: completion);
}
}
}else{
print("pointing to self or nil...\(someB)")
}
}
}
public func test_recursive_serial() {
let my_a = classA(value:100);
let arrayC:[classC] = (0..<10).map { (i) -> classC in
let c = classC();
c.delegate = my_a;
return c;
}
let arrayB:[classB] = (0..<10).map { (i) -> classB in
let b = classB();
let ii = (i + 1 >= 10) ? 0 : i + 1;
b.jump_to_C = arrayC[ii]
return b;
}
arrayC.forEach { (cc) in
cc.someB = arrayB[Int(arc4random())%arrayB.count];
}
arrayC.first!.run() { (value) in
print("done!");
}
}
Important note: if test_recursive_serial() content is directly called from the playground, that is not through a function, the problem doesn't appear.
Edit: You'll need to add 'PlaygroundPage.current.needsIndefiniteExecution = true' to the playground code.
Edit: Ok, I feel I need to add this. Big mistake on my side, test_recursive_serial() doesn't keep a reference on any of the called objects, so obviously, they all become nil after the code leaves the function. Hence the problem. Thanks to Guy Kogus for pointing that out.
Final edit: Adding this, in the hope it might help. Swift playground are great to test-drive code, but can sometime become very busy. Within the current issue, the solution requires to set the variables first, and then pass them to test_recursive_serial() which in turn adds to the chatty appearance of the playground. Here's another option to keep your code tidy and self-contained, while dealing with async functions of various flavours...
If you have an async task - one that doesn't fit into URL fetch -, say:
myObject.myNonBlockingTask(){ print("I'm done!"}
First, include XCTest at the top of your file.
import XCTest
then add the following:
func waitForNotificationNamed(_ notificationName: String,timeout:TimeInterval = 5.0) -> Bool {
let expectation = XCTNSNotificationExpectation(name: notificationName)
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
return result == .completed
}
finally, change your completion block to:
myObject.myNonBlockingTask(){
print("I'm done!")
let name = NSNotification.Name(rawValue: "foobar");
NotificationCenter.default.post(name:name , object: nil)
}
XCTAssert(waitForNotificationNamed("foobar", timeout: 90));
the full playground code will look like:
public func my_function() {
let somevar:Int = 123
let myObject = MyClass(somevar);
myObject.myNonBlockingTask(){
print("I'm done!")
let name = NSNotification.Name(rawValue: "foobar");
NotificationCenter.default.post(name:name , object: nil)
}
XCTAssert(waitForNotificationNamed("foobar", timeout: 90));
}
Playground will wait on the notification before going any further, and also generate an exception if it times out. All locally created objects will remain valid until the execution completes.
Hope this helps.
The main issue is that you're testing this in Playgrounds, which doesn't necessarily play nicely with multithreading. Following from this SO question, change the test_recursive_serial function to:
arrayC.first!.run() { (value) in
print("done! \(value)")
XCPlaygroundPage.currentPage.needsIndefiniteExecution = false
}
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
while XCPlaygroundPage.currentPage.needsIndefiniteExecution {
}
(You'll need to add import XCPlayground at the top of the code to make it work.)
If you don't add that code change, then my_a is released after you leave that function, which is why delegate becomes nil on the second call to run.
I also found that in run, if you don't call the completion closure in the else case like so:
public func run(completion:#escaping ((Int) -> Void)) {
...
if let obj = someB?.jump_to_C, obj !== self {
...
}else{
print("pointing to self or nil...\(someB)")
completion(-1) // Added fallback
}
}
Then the program gets stuck. By adding that it runs to the end, although I haven't actually worked out why.
Also, please get rid of all your ;s, this isn't Objective-C 😜

How to check if an XCTestCase test has failed

Is it possible to check within a running test if any of its XCTAsserts have failed? I have a test with a few assertions in a row, and I want to add some code afterward to perform a specific action if any of them failed:
class testClass : XCTestCase
{
func testSomething()
{
let someComputedValue1 = func1()
let someComputedValue2 = func2()
XCTAssertLessThanOrEqual(someComputedValue1, 0.5)
XCTAssertLessThanOrEqual(someComputedValue2, 0.2)
if anyOfTheAboveAssertionsFailed {
performAction()
}
}
}
The part I'd like tips on is that anyOfTheAboveAssertionsFailed condition without duplicating the comparisons to the hard-coded values.
While using your own assertion methods solves the PO's issue, it is cumbersome if you need to use several XCAssert-methods.
Another approach is to override continueAfterFailure. If there is no failure the property will not be requested. If there is one, it will.
class MyTest: XCTest {
private var hasFailed = false
override var continueAfterFailure: Bool {
get {
hasFailed = true
return super.continueAfterFailure
}
set {
super.continueAfterFailure = newValue
}
}
override func tearDown() {
if hasFailed { performAction() }
hasFailed = false
}
}
You could of course write a new function...
func assertLessThanOrEqual(value: Double, limit: Double) -> Bool {
XCTAssertLessThanOrEqual(value, limit)
return value <= limit
}
And then write your tests like...
var allGood = true
allGood = allGood && assertLessThanOrEqual(someComputedValue1, 0.5)
allGood = allGood && assertLessThanOrEqual(someComputedValue2, 0.2)
if !allGood {
performAction()
}