Skip to content

Commit e5b15f1

Browse files
committed
Replace custom MainActor.ensureIsolated with Task { @mainactor, but where sync is required, use a LLC style DispatchQueue addition
1 parent 3e2fab6 commit e5b15f1

File tree

5 files changed

+41
-42
lines changed

5 files changed

+41
-42
lines changed

Sources/StreamChat/Audio/AudioPlayer/AudioPlaying.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
131131
open func play() {
132132
do {
133133
try audioSessionConfigurator.activatePlaybackSession()
134-
MainActor.ensureIsolated {
134+
Task { @MainActor in
135135
player.play()
136136
}
137137
} catch {
@@ -141,7 +141,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
141141
}
142142

143143
open func pause() {
144-
MainActor.ensureIsolated {
144+
Task { @MainActor in
145145
player.pause()
146146
}
147147
}
@@ -170,7 +170,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
170170
}
171171

172172
open func updateRate(_ newRate: AudioPlaybackRate) {
173-
MainActor.ensureIsolated {
173+
Task { @MainActor in
174174
player.rate = newRate.rawValue
175175
}
176176
}
@@ -203,7 +203,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
203203

204204
func playbackWillStop(_ playerItem: AVPlayerItem) {
205205
let matchesCurrentItem: Bool = {
206-
MainActor.ensureIsolated {
206+
DispatchQueue.performSynchronouslyOnMainQueue {
207207
let playerItemURL = (playerItem.asset as? AVURLAsset)?.url
208208
let currentItemURL = (player.currentItem?.asset as? AVURLAsset)?.url
209209
return playerItemURL != nil && playerItemURL == currentItemURL
@@ -236,7 +236,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
236236
guard let self = self, self.context.isSeeking == false else {
237237
return
238238
}
239-
let rate = MainActor.ensureIsolated { player.rate }
239+
let rate = DispatchQueue.performSynchronouslyOnMainQueue { player.rate }
240240
self.updateContext { value in
241241
let currentTime = player.currentTime().seconds
242242
value.currentTime = currentTime.isFinite && !currentTime.isNaN
@@ -281,7 +281,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
281281
}
282282

283283
private func notifyDelegates() {
284-
MainActor.ensureIsolated {
284+
Task { @MainActor in
285285
multicastDelegate.invoke { $0.audioPlayer(self, didUpdateContext: context) }
286286
}
287287
}
@@ -308,7 +308,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
308308
/// We are going to check if the URL requested to load, represents the currentItem that we
309309
/// have already loaded (if any). In this case, we will try either to resume the existing playback
310310
/// or restart it, if possible.
311-
let currentItem = MainActor.ensureIsolated { player.currentItem?.asset as? AVURLAsset }
311+
let currentItem = DispatchQueue.performSynchronouslyOnMainQueue { player.currentItem?.asset as? AVURLAsset }
312312
if let currentItem,
313313
asset.url == currentItem.url,
314314
context.assetLocation == asset.url {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// Copyright © 2025 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import Foundation
6+
7+
extension DispatchQueue {
8+
/// Synchronously performs the provided action on the main thread.
9+
///
10+
/// Performing this action is safe because the function checks the current thread, and if it's currently in the main
11+
/// one, it performs the action safely without dead-locking the thread.
12+
///
13+
/// - Important: Most of the time we should use `Task { @MainActor in`, but in some cases we need the blocking manner.
14+
static func performSynchronouslyOnMainQueue<T>(_ action: @MainActor() throws -> T) rethrows -> T where T: Sendable {
15+
if Thread.current.isMainThread {
16+
try MainActor.assumeIsolated {
17+
try action()
18+
}
19+
} else {
20+
try DispatchQueue.main.sync {
21+
try action()
22+
}
23+
}
24+
}
25+
}

Sources/StreamChat/Utils/MainQueue+Synchronous.swift

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

StreamChat.xcodeproj/project.pbxproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@
277277
4F6AD5E52CABEAB6007E769C /* KeyPath+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6AD5E32CABEAB0007E769C /* KeyPath+Extensions.swift */; };
278278
4F6B84102D008D6E005645B0 /* MemberUpdatePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6B840F2D008D5F005645B0 /* MemberUpdatePayload.swift */; };
279279
4F6B84112D008D6E005645B0 /* MemberUpdatePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6B840F2D008D5F005645B0 /* MemberUpdatePayload.swift */; };
280+
4F6FB1AB2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */; };
281+
4F6FB1AC2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */; };
280282
4F73F3982B91BD3000563CD9 /* MessageState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F73F3972B91BD3000563CD9 /* MessageState.swift */; };
281283
4F73F3992B91BD3000563CD9 /* MessageState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F73F3972B91BD3000563CD9 /* MessageState.swift */; };
282284
4F73F39E2B91C7BF00563CD9 /* MessageState+Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F73F39D2B91C7BF00563CD9 /* MessageState+Observer.swift */; };
@@ -496,7 +498,6 @@
496498
797EEA4624FFAF4F00C81203 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797EEA4524FFAF4F00C81203 /* DataStore.swift */; };
497499
797EEA4824FFB4C200C81203 /* DataStore_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797EEA4724FFB4C200C81203 /* DataStore_Tests.swift */; };
498500
797EEA4A24FFC37600C81203 /* ConnectionStatus_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797EEA4924FFC37600C81203 /* ConnectionStatus_Tests.swift */; };
499-
7985BDAA252B1E53002B8C30 /* MainQueue+Synchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */; };
500501
79877A092498E4BC00015F8B /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79877A012498E4BB00015F8B /* User.swift */; };
501502
79877A0A2498E4BC00015F8B /* Device.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79877A022498E4BB00015F8B /* Device.swift */; };
502503
79877A0B2498E4BC00015F8B /* Member.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79877A032498E4BB00015F8B /* Member.swift */; };
@@ -2097,7 +2098,6 @@
20972098
C121E8EC274544B200023E4C /* Publisher+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4AA3B92502731900FAAF6E /* Publisher+Extensions.swift */; };
20982099
C121E8ED274544B200023E4C /* UniqueId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797E10A724EAF6DE00353791 /* UniqueId.swift */; };
20992100
C121E8EE274544B200023E4C /* MulticastDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CD959124F9380B00E87377 /* MulticastDelegate.swift */; };
2100-
C121E8EF274544B200023E4C /* MainQueue+Synchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */; };
21012101
C121E8F0274544B200023E4C /* Dictionary+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88EA9AD725470F6A007EE76B /* Dictionary+Extensions.swift */; };
21022102
C121E8F1274544B200023E4C /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881506EB258212BF0013935B /* MultipartFormData.swift */; };
21032103
C121E8F2274544B200023E4C /* SystemEnvironment+Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7AD954E25D536AA00076DC3 /* SystemEnvironment+Version.swift */; };
@@ -3223,6 +3223,7 @@
32233223
4F6A77032D2FD09A0019CAF8 /* AppSettings_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings_Tests.swift; sourceTree = "<group>"; };
32243224
4F6AD5E32CABEAB0007E769C /* KeyPath+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyPath+Extensions.swift"; sourceTree = "<group>"; };
32253225
4F6B840F2D008D5F005645B0 /* MemberUpdatePayload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberUpdatePayload.swift; sourceTree = "<group>"; };
3226+
4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+Extensions.swift"; sourceTree = "<group>"; };
32263227
4F73F3972B91BD3000563CD9 /* MessageState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageState.swift; sourceTree = "<group>"; };
32273228
4F73F39D2B91C7BF00563CD9 /* MessageState+Observer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageState+Observer.swift"; sourceTree = "<group>"; };
32283229
4F7B58942DCB6B5A0034CC0F /* AllocatedUnfairLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllocatedUnfairLock.swift; sourceTree = "<group>"; };
@@ -3433,7 +3434,6 @@
34333434
797EEA4524FFAF4F00C81203 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = "<group>"; };
34343435
797EEA4724FFB4C200C81203 /* DataStore_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore_Tests.swift; sourceTree = "<group>"; };
34353436
797EEA4924FFC37600C81203 /* ConnectionStatus_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionStatus_Tests.swift; sourceTree = "<group>"; };
3436-
7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainQueue+Synchronous.swift"; sourceTree = "<group>"; };
34373437
798779F62498E47700015F8B /* Member.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Member.json; sourceTree = "<group>"; };
34383438
798779F72498E47700015F8B /* Channel.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Channel.json; sourceTree = "<group>"; };
34393439
798779F82498E47700015F8B /* OtherUser.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = OtherUser.json; sourceTree = "<group>"; };
@@ -5638,10 +5638,10 @@
56385638
792A4F3E247FFDE700EAF71D /* Data+Gzip.swift */,
56395639
40789D3B29F6AD9C0018C2BB /* Debouncer.swift */,
56405640
88EA9AD725470F6A007EE76B /* Dictionary+Extensions.swift */,
5641+
4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */,
56415642
84CF9C72274D473D00BCDE2D /* EventBatcher.swift */,
56425643
C173538D27D9F804008AC412 /* KeyedDecodingContainer+Array.swift */,
56435644
DBCAFE2325C44B920015AD58 /* LazyCachedMapCollection.swift */,
5644-
7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */,
56455645
4FE56B8C2D5DFE3A00589F9A /* MarkdownParser.swift */,
56465646
79CD959124F9380B00E87377 /* MulticastDelegate.swift */,
56475647
881506EB258212BF0013935B /* MultipartFormData.swift */,
@@ -11379,7 +11379,6 @@
1137911379
4F1BEE792BE384FE00B6685C /* ReactionListState.swift in Sources */,
1138011380
79C5CBE825F66DBD00D98001 /* ChatChannelWatcherListController.swift in Sources */,
1138111381
8A62706E24BF45360040BFD6 /* BanEnabling.swift in Sources */,
11382-
7985BDAA252B1E53002B8C30 /* MainQueue+Synchronous.swift in Sources */,
1138311382
ADF9E1F72A03E7E400109108 /* MessagesPaginationState.swift in Sources */,
1138411383
79983C8126663436000995F6 /* ChatMessageVideoAttachment.swift in Sources */,
1138511384
ADEEB7F22BD1368900C76602 /* MessageReactionGroupPayload.swift in Sources */,
@@ -11672,6 +11671,7 @@
1167211671
AD7DFC3625D2FA8100DD9DA3 /* CurrentUserUpdater.swift in Sources */,
1167311672
AD0CC0342BDC4A6B005E2C66 /* ReactionListController+Combine.swift in Sources */,
1167411673
88206FC425B18C88009D086A /* ConnectionRepository.swift in Sources */,
11674+
4F6FB1AB2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */,
1167511675
79682C4B24BF37CB0071578E /* ChannelListPayload.swift in Sources */,
1167611676
AD545E642D52827B008FD399 /* DraftListQuery.swift in Sources */,
1167711677
79D6CE3725F7C84600BE2EEC /* ChatChannelWatcherListController+SwiftUI.swift in Sources */,
@@ -12566,6 +12566,7 @@
1256612566
841BAA052BCE94F8000C73E4 /* QueryPollsRequestBody.swift in Sources */,
1256712567
C121E8B4274544B000023E4C /* CurrentUserController+SwiftUI.swift in Sources */,
1256812568
40789D1E29F6AC500018C2BB /* AudioPlayingDelegate.swift in Sources */,
12569+
4F6FB1AC2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */,
1256912570
ADF2BBEC2B9B622B0069D467 /* AppSettingsPayload.swift in Sources */,
1257012571
C121E8B5274544B000023E4C /* CurrentUserController+Combine.swift in Sources */,
1257112572
C121E8B6274544B000023E4C /* ConnectionController.swift in Sources */,
@@ -12658,7 +12659,6 @@
1265812659
C121E8EC274544B200023E4C /* Publisher+Extensions.swift in Sources */,
1265912660
C121E8ED274544B200023E4C /* UniqueId.swift in Sources */,
1266012661
C121E8EE274544B200023E4C /* MulticastDelegate.swift in Sources */,
12661-
C121E8EF274544B200023E4C /* MainQueue+Synchronous.swift in Sources */,
1266212662
C121E8F0274544B200023E4C /* Dictionary+Extensions.swift in Sources */,
1266312663
C121E8F1274544B200023E4C /* MultipartFormData.swift in Sources */,
1266412664
AD545E672D53C271008FD399 /* DraftMessagesRepository.swift in Sources */,

TestTools/StreamChatTestTools/Mocks/StreamChat/VoiceRecording/MockAVPlayer.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class MockAVPlayer: AVPlayer {
4444
override public func replaceCurrentItem(
4545
with item: AVPlayerItem?
4646
) {
47-
MainActor.ensureIsolated {
47+
DispatchQueue.performSynchronouslyOnMainQueue {
4848
replaceCurrentItemWasCalled = true
4949
replaceCurrentItemWasCalledWithItem = item
5050
}
@@ -57,7 +57,7 @@ public class MockAVPlayer: AVPlayer {
5757
toleranceAfter: CMTime,
5858
completionHandler: @escaping @Sendable(Bool) -> Void
5959
) {
60-
MainActor.ensureIsolated {
60+
DispatchQueue.performSynchronouslyOnMainQueue {
6161
seekWasCalledWithTime = time
6262
seekWasCalledWithToleranceBefore = toleranceBefore
6363
seekWasCalledWithToleranceAfter = toleranceAfter
@@ -67,7 +67,7 @@ public class MockAVPlayer: AVPlayer {
6767
toleranceBefore: toleranceBefore,
6868
toleranceAfter: toleranceAfter,
6969
completionHandler: { _ in
70-
MainActor.ensureIsolated {
70+
Task { @MainActor in
7171
completionHandler(!self.holdSeekCompletion)
7272
}
7373
}

0 commit comments

Comments
 (0)