Skip to content

Commit 627d62c

Browse files
committed
feat: Enhance concurrency support and Sendable conformance across multiple components
1 parent 047a613 commit 627d62c

25 files changed

+526
-367
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Foundation
2+
3+
extension DispatchQueue {
4+
/// Asynchronously executes a closure on the main thread with MainActor isolation.
5+
///
6+
/// This method is preferred over `Task { @MainActor in }` for performance-critical code
7+
/// (e.g., 60fps tracking).
8+
/// `Task` creates a new task context, while `DispatchQueue.main.async` is a lightweight
9+
/// dispatch to the main thread.
10+
@inline(__always)
11+
public static func runOnMain(_ operation: @MainActor @escaping () -> Void) {
12+
main.async {
13+
MainActor.assumeIsolated {
14+
operation()
15+
}
16+
}
17+
}
18+
}

app/xcode/Sources/VCamBridge/UniBridge+Typed.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public struct ScreenResolutionPayload: Equatable {
5555

5656
// MARK: - Bridge Callback
5757
public extension UniBridge {
58-
nonisolated(unsafe) static var methodCallback: (UniBridgeMethodId, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> Void = { _, _, _ in }
58+
@MainActor static var methodCallback: (UniBridgeMethodId, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> Void = { _, _, _ in }
5959
}
6060

6161
// MARK: - Bridge Implementation

app/xcode/Sources/VCamBridge/UniBridge.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/// GENERATED BY ./scripts/generate_bridge
22
import SwiftUI
3-
public final class UniBridge: @unchecked Sendable {
3+
4+
@MainActor
5+
public final class UniBridge {
46
public static let shared = UniBridge()
57
private init() {}
68
public enum IntType: Int32, Sendable {

app/xcode/Sources/VCamBridge/ValueBinding.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import class AppKit.NSColor
33
import struct SwiftUI.Binding
44
import struct SwiftUI.Color
55

6-
public final class ValueBinding<Value, Kind: RawRepresentable>: @unchecked Sendable where Kind.RawValue == Int32, Kind: Sendable {
6+
@MainActor
7+
public final class ValueBinding<Value, Kind: RawRepresentable> where Kind.RawValue == Int32, Kind: Sendable {
78
public var getValue: ((Kind) -> Value)?
89
public var setValue: (Kind, Value) -> Void = { _, _ in }
910

app/xcode/Sources/VCamData/ModelManager.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public final class ModelManager {
2828
return modelItems.first { $0.id == id }
2929
}
3030

31+
public func model(for modelId: UUID) -> Models.Model? {
32+
modelItems.first { $0.id == modelId }?.model
33+
}
34+
3135
public func setLastLoadedModel(_ model: ModelItem) {
3236
lastLoadedModelId = model.id
3337
saveMeta()

app/xcode/Sources/VCamData/UniState+Value.swift

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ public struct UniStateValue<Value> {
1616
public typealias SelfKeyPath = ReferenceWritableKeyPath<UniState, Self>
1717

1818
private let keyPath: ValueKeyPath
19-
private let onSet: ((UniState, Value) -> Void)?
19+
private let onSet: (@MainActor (UniState, Value) -> Void)?
2020

21+
@MainActor
2122
public static subscript(
2223
_enclosingInstance instance: UniState,
2324
wrapped wrappedKeyPath: ValueKeyPath,
@@ -39,7 +40,7 @@ public struct UniStateValue<Value> {
3940
set { fatalError() }
4041
}
4142

42-
init(_ keyPath: ValueKeyPath, onSet: ((UniState, Value) -> Void)? = nil) {
43+
init(_ keyPath: ValueKeyPath, onSet: (@MainActor (UniState, Value) -> Void)? = nil) {
4344
self.keyPath = keyPath
4445
self.onSet = onSet
4546
}
@@ -49,14 +50,14 @@ public struct UniStateValue<Value> {
4950

5051
extension UniStateValue where Value == Bool {
5152
init(_ keyPath: ValueKeyPath, persist: UserDefaults.Key<Bool>? = nil, bridge: UniBridge.BoolType) {
52-
self.init(keyPath) { _, newValue in
53+
self.init(keyPath) { @MainActor _, newValue in
5354
if let key = persist { UserDefaults.standard.set(newValue, for: key) }
5455
UniBridge.shared.boolMapper.setValue(bridge, newValue)
5556
}
5657
}
5758

5859
init(_ keyPath: ValueKeyPath, persistAsInt: UserDefaults.Key<Int>, trueValue: Int = 1, bridge: UniBridge.BoolType) {
59-
self.init(keyPath) { _, newValue in
60+
self.init(keyPath) { @MainActor _, newValue in
6061
UserDefaults.standard.set(newValue ? trueValue : 0, for: persistAsInt)
6162
UniBridge.shared.boolMapper.setValue(bridge, newValue)
6263
}
@@ -67,14 +68,14 @@ extension UniStateValue where Value == Bool {
6768

6869
extension UniStateValue where Value == CGFloat {
6970
init(_ keyPath: ValueKeyPath, persist: UserDefaults.Key<Double>? = nil, bridge: UniBridge.FloatType) {
70-
self.init(keyPath) { _, newValue in
71+
self.init(keyPath) { @MainActor _, newValue in
7172
if let key = persist { UserDefaults.standard.set(Double(newValue), for: key) }
7273
UniBridge.shared.floatMapper.setValue(bridge, newValue)
7374
}
7475
}
7576

7677
init(_ keyPath: ValueKeyPath, bridge: UniBridge.FloatType) {
77-
self.init(keyPath) { _, newValue in
78+
self.init(keyPath) { @MainActor _, newValue in
7879
UniBridge.shared.floatMapper.setValue(bridge, newValue)
7980
}
8081
}
@@ -84,14 +85,14 @@ extension UniStateValue where Value == CGFloat {
8485

8586
extension UniStateValue where Value == Int32 {
8687
init(_ keyPath: ValueKeyPath, persist: UserDefaults.Key<Int>? = nil, bridge: UniBridge.IntType) {
87-
self.init(keyPath) { _, newValue in
88+
self.init(keyPath) { @MainActor _, newValue in
8889
if let key = persist { UserDefaults.standard.set(Int(newValue), for: key) }
8990
UniBridge.shared.intMapper.setValue(bridge, newValue)
9091
}
9192
}
9293

9394
init(_ keyPath: ValueKeyPath, bridge: UniBridge.IntType) {
94-
self.init(keyPath) { _, newValue in
95+
self.init(keyPath) { @MainActor _, newValue in
9596
UniBridge.shared.intMapper.setValue(bridge, newValue)
9697
}
9798
}
@@ -101,7 +102,7 @@ extension UniStateValue where Value == Int32 {
101102

102103
extension UniStateValue where Value == String {
103104
init(_ keyPath: ValueKeyPath, persist: UserDefaults.Key<String>? = nil, bridge: UniBridge.StringType) {
104-
self.init(keyPath) { _, newValue in
105+
self.init(keyPath) { @MainActor _, newValue in
105106
if let key = persist { UserDefaults.standard.set(newValue, for: key) }
106107
UniBridge.shared.stringMapper.setValue(bridge, newValue)
107108
}
@@ -112,7 +113,7 @@ extension UniStateValue where Value == String {
112113

113114
extension UniStateValue where Value == Color {
114115
init(_ keyPath: ValueKeyPath, persist: UserDefaults.Key<String>? = nil, bridge: UniBridge.StructType) {
115-
self.init(keyPath) { _, newValue in
116+
self.init(keyPath) { @MainActor _, newValue in
116117
if let key = persist, let hex = newValue.hexRGBAString {
117118
UserDefaults.standard.set(hex, for: key)
118119
}
@@ -121,7 +122,7 @@ extension UniStateValue where Value == Color {
121122
}
122123

123124
init(_ keyPath: ValueKeyPath, bridge: UniBridge.StructType) {
124-
self.init(keyPath) { _, newValue in
125+
self.init(keyPath) { @MainActor _, newValue in
125126
UniBridge.shared.structMapper.binding(bridge).wrappedValue = newValue
126127
}
127128
}

app/xcode/Sources/VCamDefaults/UserDefaultValue.swift

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
1-
//
2-
// UserDefaultsValue.swift
3-
//
4-
//
5-
// Created by Tatsuya Tanaka on 2022/04/23.
6-
//
7-
81
import Foundation
92

10-
public protocol UserDefaultsValue {
3+
public protocol UserDefaultsValue: Sendable {
114
associatedtype EncodeValue
125
func encodeUserDefaultValue() -> EncodeValue
136
static func decodeUserDefaultValue(_ value: EncodeValue) -> Self?

app/xcode/Sources/VCamDefaults/UserDefaults+.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public extension UserDefaults {
2222
}
2323

2424
public extension UserDefaults {
25-
struct Key<Value: UserDefaultsValue> {
25+
struct Key<Value: UserDefaultsValue>: Sendable {
2626
public let rawValue: String
2727
public let defaultValue: Value
2828

app/xcode/Sources/VCamEntity/Version.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
public struct Version {
3+
public struct Version: Sendable {
44
public let components: [Int]
55

66
static var bundle: Bundle { .main }

0 commit comments

Comments
 (0)