Skip to content

Commit 18dbd8b

Browse files
authored
[#558] 프로젝트의 Sendable 경고를 약하게 보도록 수정한다 (#559)
* chore: 기본 설정으로 롤백 * refactor: AsyncStream 기반 스트림을 Combine으로 수정 * refactor: Sendable 제거 * refactor: Sendable 경고를 해결하기 위한 잔여 구현물 제거 * refactor: 무분별한 Sendable 채택 제거 롤백
1 parent 13103a3 commit 18dbd8b

20 files changed

Lines changed: 117 additions & 305 deletions

Application/DevLogData/Sources/Repository/TodoMutationEventBusImpl.swift

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,17 @@
55
// Created by opfic on 6/6/26.
66
//
77

8-
import Foundation
8+
import Combine
99
import DevLogDomain
1010

11-
actor TodoMutationEventBusImpl: TodoMutationEventBus {
12-
private var continuations = [UUID: AsyncStream<TodoMutationEvent>.Continuation]()
11+
final class TodoMutationEventBusImpl: TodoMutationEventBus {
12+
private let subject = PassthroughSubject<TodoMutationEvent, Never>()
1313

14-
func publish(_ event: TodoMutationEvent) async {
15-
continuations.values.forEach { $0.yield(event) }
14+
func publish(_ event: TodoMutationEvent) {
15+
subject.send(event)
1616
}
1717

18-
func events() -> AsyncStream<TodoMutationEvent> {
19-
let id = UUID()
20-
let (stream, continuation) = AsyncStream.makeStream(of: TodoMutationEvent.self)
21-
22-
continuations[id] = continuation
23-
continuation.onTermination = { [weak self] _ in
24-
Task {
25-
await self?.removeContinuation(id: id)
26-
}
27-
}
28-
29-
return stream
30-
}
31-
}
32-
33-
private extension TodoMutationEventBusImpl {
34-
func removeContinuation(id: UUID) {
35-
continuations[id] = nil
18+
func observe() -> AnyPublisher<TodoMutationEvent, Never> {
19+
subject.eraseToAnyPublisher()
3620
}
3721
}

Application/DevLogData/Sources/Repository/TodoRepositoryImpl.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ final class TodoRepositoryImpl: TodoRepository {
110110
func upsertTodo(_ todo: Todo) async throws {
111111
let todoRequest = TodoRequest.fromDomain(todo)
112112
try await upsertTodo(todoRequest)
113-
await todoMutationEventBus.publish(.updated(todo.id))
113+
todoMutationEventBus.publish(.updated(todo.id))
114114
}
115115

116116
func upsertTodo(_ todoDraft: TodoDraft) async throws {
@@ -131,7 +131,7 @@ final class TodoRepositoryImpl: TodoRepository {
131131
do {
132132
try await todoService.deleteTodo(todoId: todoId)
133133
widgetSyncEventBus.publish(.syncRequested)
134-
await todoMutationEventBus.publish(.deleted(todoId))
134+
todoMutationEventBus.publish(.deleted(todoId))
135135
} catch {
136136
throw error.toDomain()
137137
}
@@ -141,7 +141,7 @@ final class TodoRepositoryImpl: TodoRepository {
141141
do {
142142
try await todoService.undoDeleteTodo(todoId: todoId)
143143
widgetSyncEventBus.publish(.syncRequested)
144-
await todoMutationEventBus.publish(.restored(todoId))
144+
todoMutationEventBus.publish(.restored(todoId))
145145
} catch {
146146
throw error.toDomain()
147147
}

Application/DevLogData/Tests/Repository/TodoMutationEventBusImplTests.swift

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,24 @@
55
// Created by opfic on 6/6/26.
66
//
77

8+
import Combine
89
import Testing
910
import DevLogDomain
1011
@testable import DevLogData
1112

1213
struct TodoMutationEventBusImplTests {
1314
@Test("TodoMutationEventBus는 발행된 이벤트를 관찰자에게 전달한다")
14-
func todoMutationEventBus는_발행된_이벤트를_관찰자에게_전달한다() async {
15+
func todoMutationEventBus는_발행된_이벤트를_관찰자에게_전달한다() {
1516
let bus = TodoMutationEventBusImpl()
16-
let events = await bus.events()
17-
let task = Task {
18-
var iterator = events.makeAsyncIterator()
19-
return await iterator.next()
20-
}
17+
var events = [TodoMutationEvent]()
18+
var cancellables = Set<AnyCancellable>()
2119

22-
await bus.publish(.updated("todo-id"))
20+
bus.observe()
21+
.sink { events.append($0) }
22+
.store(in: &cancellables)
2323

24-
let event = await task.value
25-
#expect(event == .updated("todo-id"))
24+
bus.publish(.updated("todo-id"))
25+
26+
#expect(events == [.updated("todo-id")])
2627
}
2728
}

Application/DevLogData/Tests/Repository/TodoRepositoryImplTests.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct TodoRepositoryImplTests {
2525
let events = fixture.widgetSyncEventBus.events
2626
#expect(events == [.syncRequested, .syncRequested, .syncRequested])
2727

28-
let mutationEvents = await fixture.todoMutationEventBus.publishedEvents()
28+
let mutationEvents = fixture.todoMutationEventBus.publishedEvents()
2929
#expect(mutationEvents == [.updated(todo.id), .deleted(todo.id), .restored(todo.id)])
3030
}
3131

@@ -58,7 +58,7 @@ struct TodoRepositoryImplTests {
5858
let syncEvents = fixture.widgetSyncEventBus.events
5959
#expect(syncEvents.isEmpty)
6060

61-
let mutationEvents = await fixture.todoMutationEventBus.publishedEvents()
61+
let mutationEvents = fixture.todoMutationEventBus.publishedEvents()
6262
#expect(mutationEvents.isEmpty)
6363
}
6464

@@ -169,21 +169,19 @@ private final class WidgetSyncEventBusSpy: WidgetSyncEventBus {
169169
}
170170
}
171171

172-
private actor TodoMutationEventBusSpy: TodoMutationEventBus {
172+
private final class TodoMutationEventBusSpy: TodoMutationEventBus {
173173
private var capturedEvents = [TodoMutationEvent]()
174174

175-
func publish(_ event: TodoMutationEvent) async {
175+
func publish(_ event: TodoMutationEvent) {
176176
capturedEvents.append(event)
177177
}
178178

179179
func publishedEvents() -> [TodoMutationEvent] {
180180
capturedEvents
181181
}
182182

183-
func events() async -> AsyncStream<TodoMutationEvent> {
184-
AsyncStream { continuation in
185-
continuation.finish()
186-
}
183+
func observe() -> AnyPublisher<TodoMutationEvent, Never> {
184+
Empty().eraseToAnyPublisher()
187185
}
188186
}
189187

Application/DevLogDomain/Sources/Entity/AuthProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import Foundation
99

10-
public enum AuthProvider: String, CaseIterable, Sendable {
10+
public enum AuthProvider: String, CaseIterable {
1111
case apple = "apple.com"
1212
case google = "google.com"
1313
case github = "github.com"

Application/DevLogDomain/Sources/Entity/TodoMutationEvent.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Created by opfic on 6/6/26.
66
//
77

8-
public enum TodoMutationEvent: Equatable, Sendable {
8+
public enum TodoMutationEvent: Equatable {
99
case updated(String)
1010
case deleted(String)
1111
case restored(String)

Application/DevLogDomain/Sources/Protocol/TodoMutationEventBus.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
// Created by opfic on 6/6/26.
66
//
77

8-
public protocol TodoMutationEventBus: Sendable {
9-
func publish(_ event: TodoMutationEvent) async
10-
func events() async -> AsyncStream<TodoMutationEvent>
8+
import Combine
9+
10+
public protocol TodoMutationEventBus {
11+
func publish(_ event: TodoMutationEvent)
12+
func observe() -> AnyPublisher<TodoMutationEvent, Never>
1113
}

Application/DevLogInfra/Sources/Common/FirebaseDependency.swift

Lines changed: 0 additions & 47 deletions
This file was deleted.

Application/DevLogInfra/Sources/Service/AuthServiceImpl.swift

Lines changed: 22 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ import DevLogCore
1313
import DevLogData
1414

1515
final class AuthServiceImpl: AuthService {
16-
private let store = FirebaseDependency(value: Firestore.firestore())
17-
private let messaging = FirebaseDependency(value: Messaging.messaging())
16+
private let store = Firestore.firestore()
17+
private let messaging = Messaging.messaging()
1818
private let logger = Logger(category: "AuthServiceImpl")
19-
private let authStatePublisher: AuthStatePublisher
19+
private let subject = CurrentValueSubject<Bool, Never>(Auth.auth().currentUser != nil)
20+
private var handler: AuthStateDidChangeListenerHandle?
21+
private var isCompletingSignIn = false
2022

2123
var uid: String? {
2224
Auth.auth().currentUser?.uid
@@ -35,26 +37,36 @@ final class AuthServiceImpl: AuthService {
3537
}
3638

3739
init() {
38-
authStatePublisher = AuthStatePublisher(logger: logger)
40+
handler = Auth.auth().addStateDidChangeListener { [weak self] _, user in
41+
self?.handleAuthStateChange(user)
42+
}
43+
}
44+
45+
deinit {
46+
guard let handler else { return }
47+
Auth.auth().removeStateDidChangeListener(handler)
3948
}
4049

4150
func observeSignedIn() -> AnyPublisher<Bool, Never> {
42-
authStatePublisher.observeSignedIn()
51+
subject.eraseToAnyPublisher()
4352
}
4453

4554
func beginSignIn() {
4655
logger.info("Beginning sign-in bootstrap")
47-
authStatePublisher.beginSignIn()
56+
isCompletingSignIn = true
57+
subject.send(false)
4858
}
4959

5060
func completeSignIn() {
5161
logger.info("Completing sign-in bootstrap")
52-
authStatePublisher.completeSignIn()
62+
isCompletingSignIn = false
63+
subject.send(Auth.auth().currentUser != nil)
5364
}
5465

5566
func cancelSignIn() {
5667
logger.info("Cancelling sign-in bootstrap")
57-
authStatePublisher.cancelSignIn()
68+
isCompletingSignIn = false
69+
subject.send(Auth.auth().currentUser != nil)
5870
}
5971

6072
func getProviderID() async throws -> String? {
@@ -114,59 +126,8 @@ final class AuthServiceImpl: AuthService {
114126

115127
}
116128

117-
private final class AuthStatePublisher {
118-
private let logger: Logger
119-
private let subject: CurrentValueSubject<Bool, Never>
120-
private let lock = NSLock()
121-
private var handler: FirebaseDependency<AuthStateDidChangeListenerHandle>?
122-
private var isCompletingSignIn = false
123-
124-
init(logger: Logger) {
125-
self.logger = logger
126-
self.subject = CurrentValueSubject<Bool, Never>(Auth.auth().currentUser != nil)
127-
self.handler = FirebaseDependency(
128-
value: Auth.auth().addStateDidChangeListener { [weak self] _, user in
129-
self?.handleAuthStateChange(user)
130-
}
131-
)
132-
}
133-
134-
deinit {
135-
guard let handler else { return }
136-
handler.removeAuthStateDidChangeListener()
137-
}
138-
139-
func observeSignedIn() -> AnyPublisher<Bool, Never> {
140-
lock.lock()
141-
defer { lock.unlock() }
142-
return subject.eraseToAnyPublisher()
143-
}
144-
145-
func beginSignIn() {
146-
lock.lock()
147-
isCompletingSignIn = true
148-
subject.send(false)
149-
lock.unlock()
150-
}
151-
152-
func completeSignIn() {
153-
lock.lock()
154-
isCompletingSignIn = false
155-
subject.send(Auth.auth().currentUser != nil)
156-
lock.unlock()
157-
}
158-
159-
func cancelSignIn() {
160-
lock.lock()
161-
isCompletingSignIn = false
162-
subject.send(Auth.auth().currentUser != nil)
163-
lock.unlock()
164-
}
165-
166-
private func handleAuthStateChange(_ user: User?) {
167-
lock.lock()
168-
defer { lock.unlock() }
169-
129+
private extension AuthServiceImpl {
130+
func handleAuthStateChange(_ user: User?) {
170131
let signedIn = user != nil
171132
logger.info("Firebase auth state changed. signedIn: \(signedIn)")
172133

0 commit comments

Comments
 (0)