-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SDKS-3458 Swift6 adoption + concurrency check #6
base: develop
Are you sure you want to change the base?
Changes from 4 commits
6ee4a29
590a11f
9d05817
be03b0b
598813d
79e9278
947f55d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,20 +11,59 @@ | |
|
||
import Foundation | ||
|
||
|
||
/// Abstract class representing a field collector. | ||
/// - property key: The key of the field collector. | ||
/// - property label The label of the field collector. | ||
/// - property value The value of the field collector. It's open for modification. | ||
open class FieldCollector: Collector { | ||
public var key: String = "" | ||
public var label: String = "" | ||
public var value: String = "" | ||
open class FieldCollector: Collector, @unchecked Sendable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like you handle concurrent update of attributes, why define as unchecked? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Swift 6, this code won't compile as-is, because the compiler will error: To resolve this, we need to instruct the compiler to skip the compatibility check by explicitly marking the conformance as unchecked. This can be done using @unchecked Sendable, |
||
|
||
// Private queue for thread-safe access | ||
private let syncQueue = DispatchQueue(label: "com.fieldCollector.syncQueue", attributes: .concurrent) | ||
|
||
// Private backing properties to store data | ||
private var _key: String = "" | ||
private var _label: String = "" | ||
private var _value: String = "" | ||
|
||
// Public computed properties for thread-safe access | ||
public var key: String { | ||
get { | ||
return syncQueue.sync { _key } | ||
} | ||
set { | ||
syncQueue.async(flags: .barrier) { self._key = newValue } | ||
} | ||
} | ||
|
||
public var label: String { | ||
get { | ||
return syncQueue.sync { _label } | ||
} | ||
set { | ||
syncQueue.async(flags: .barrier) { self._label = newValue } | ||
} | ||
} | ||
|
||
public var value: String { | ||
get { | ||
return syncQueue.sync { _value } | ||
} | ||
set { | ||
syncQueue.async(flags: .barrier) { self._value = newValue } | ||
} | ||
} | ||
|
||
public let id = UUID() | ||
|
||
// Default initializer | ||
public init() {} | ||
|
||
required public init(with json: [String: Any]) { | ||
key = json[Constants.key] as? String ?? "" | ||
label = json[Constants.label] as? String ?? "" | ||
// Initializer with a JSON field | ||
required public init(with json: Field) { | ||
syncQueue.async(flags: .barrier) { | ||
self._key = json.key | ||
self._label = json.label | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,20 +13,44 @@ import Foundation | |
|
||
/// Class that handles the parsing and JSON representation of collectors. | ||
/// This class provides functions to parse a JSON object into a list of collectors and to represent a list of collectors as a JSON object. | ||
class Form { | ||
|
||
/// Parses a JSON object into a list of collectors. | ||
/// This function takes a JSON object and extracts the "form" field. It then iterates over the "fields" array in the "components" object, | ||
/// parsing each field into a collector and adding it to a list. | ||
/// - Parameter json :The JSON object to parse. | ||
/// - Returns: A list of collectors parsed from the JSON object. | ||
static func parse(json: [String: Any]) -> Collectors { | ||
var collectors = Collectors() | ||
if let form = json[Constants.form] as? [String: Any], | ||
let components = form[Constants.components] as? [String: Any], | ||
let fields = components[Constants.fields] as? [[String: Any]] { | ||
collectors = CollectorFactory().collector(from: fields) | ||
actor Form { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is not mutable state in Form, any reason we need to define it as actor? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Form can be a struct ... we generally reduce using classes. For this scenario actor is not required. i will change this. |
||
|
||
/// Parses a JSON object into a list of collectors. | ||
/// This function takes a JSON object and extracts the "form" field. It then iterates over the "fields" array in the "components" object, | ||
/// parsing each field into a collector and adding it to a list. | ||
/// - Parameter json :The JSON object to parse. | ||
/// - Returns: A list of collectors parsed from the JSON object. | ||
static func parse(json: [String: Any]) async -> Collectors { | ||
var collectors = Collectors() | ||
if let form = json[Constants.form] as? [String: Any], | ||
let components = form[Constants.components] as? [String: Any], | ||
let fields = components[Constants.fields] as? [[String: Any]] { | ||
|
||
let factory = CollectorFactory.shared | ||
|
||
let fields: [Field] = fields.compactMap { fieldDict in | ||
if let type = fieldDict["type"] as? String { | ||
let value = fieldDict["value"] as? String ?? "" | ||
let key = fieldDict[Constants.key] as? String ?? "" | ||
let label = fieldDict[Constants.label] as? String ?? "" | ||
|
||
return Field(type: type, value: value, key: key, label: label) | ||
} | ||
return collectors | ||
return nil | ||
} | ||
|
||
collectors = await factory.collector(from: fields) | ||
return collectors | ||
|
||
} | ||
return collectors | ||
} | ||
} | ||
|
||
|
||
public struct Field: Sendable { | ||
let type: String | ||
let value: String | ||
let key: String | ||
let label: String | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ import Foundation | |
import PingOidc | ||
import PingOrchestrate | ||
|
||
public class OidcModule { | ||
public actor OidcModule { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no state in OidcModule, why define it as actor? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. by default static property in classes are not thread safe. so compiler will throw error
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me think about this in another way |
||
|
||
public init() {} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a Singleton?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, CollectorFactory.shared is the usage.
So customer will have to call like to add custom callback ..
await CollectorFactory.shared.register(type: collector:)