Skip to content

Commit 6f8686f

Browse files
authored
Fix crash in ChannelAvatarsMerger when accessing shared properties (#858)
1 parent 0276d06 commit 6f8686f

File tree

4 files changed

+52
-12
lines changed

4 files changed

+52
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
33

44
# Upcoming
55

6-
### 🔄 Changed
6+
### 🐞 Fixed
7+
- Fix rare concurrency crash in `ChannelAvatarsMerger.createMergedAvatar(from:)` [#858](https://github.com/GetStream/stream-chat-swiftui/pull/858)
78

89
# [4.79.1](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.79.1)
910
_June 03, 2025_

Sources/StreamChatSwiftUI/ChatChannelList/ChannelAvatarsMerger.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ public class ChannelAvatarsMerger: ChannelAvatarsMerging {
2121
@Injected(\.images) private var images
2222

2323
/// Context provided utils.
24-
private lazy var imageProcessor = utils.imageProcessor
25-
private lazy var imageMerger = utils.imageMerger
24+
private var imageProcessor: ImageProcessor { utils.imageProcessor }
25+
private var imageMerger: ImageMerging { utils.imageMerger }
2626

2727
/// Placeholder images.
28-
private lazy var placeholder1 = images.userAvatarPlaceholder1
29-
private lazy var placeholder2 = images.userAvatarPlaceholder2
30-
private lazy var placeholder3 = images.userAvatarPlaceholder3
31-
private lazy var placeholder4 = images.userAvatarPlaceholder4
28+
private var placeholder1: UIImage { images.userAvatarPlaceholder1 }
29+
private var placeholder2: UIImage { images.userAvatarPlaceholder2 }
30+
private var placeholder3: UIImage { images.userAvatarPlaceholder3 }
31+
private var placeholder4: UIImage { images.userAvatarPlaceholder4 }
3232

3333
/// Creates a merged avatar from the given images
3434
/// - Parameter avatars: The individual avatars

StreamChatSwiftUI.xcodeproj/project.pbxproj

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
402C54482B6AAC0100672BFB /* StreamChatSwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8465FBB52746873A00AF091E /* StreamChatSwiftUI.framework */; };
1111
402C54492B6AAC0100672BFB /* StreamChatSwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8465FBB52746873A00AF091E /* StreamChatSwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12+
4F03F18F2E0140C6001C71A2 /* ChannelAvatarsMerger_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F03F18E2E0140C6001C71A2 /* ChannelAvatarsMerger_Tests.swift */; };
1213
4F077EF82C85E05700F06D83 /* DelayedRenderingViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F077EF72C85E05700F06D83 /* DelayedRenderingViewModifier.swift */; };
1314
4F198FDD2C0480EC00148F49 /* Publisher+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F198FDC2C0480EC00148F49 /* Publisher+Extensions.swift */; };
1415
4F65F1862D06EEA7009F69A8 /* ChooseChannelQueryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F65F1852D06EEA5009F69A8 /* ChooseChannelQueryView.swift */; };
@@ -610,6 +611,7 @@
610611

611612
/* Begin PBXFileReference section */
612613
4A65451E274BA170003C5FA8 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
614+
4F03F18E2E0140C6001C71A2 /* ChannelAvatarsMerger_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelAvatarsMerger_Tests.swift; sourceTree = "<group>"; };
613615
4F077EF72C85E05700F06D83 /* DelayedRenderingViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelayedRenderingViewModifier.swift; sourceTree = "<group>"; };
614616
4F198FDC2C0480EC00148F49 /* Publisher+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publisher+Extensions.swift"; sourceTree = "<group>"; };
615617
4F65F1852D06EEA5009F69A8 /* ChooseChannelQueryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseChannelQueryView.swift; sourceTree = "<group>"; };
@@ -2020,17 +2022,18 @@
20202022
84C94C7D27567CC2007FE2B9 /* ChatChannelList */ = {
20212023
isa = PBXGroup;
20222024
children = (
2023-
84C94C7F27567D3F007FE2B9 /* ChatChannelListViewModel_Tests.swift */,
2024-
84C94D432757C704007FE2B9 /* MoreChannelActionsViewModel_Tests.swift */,
2025+
4F03F18E2E0140C6001C71A2 /* ChannelAvatarsMerger_Tests.swift */,
20252026
84C94D67275A6AFD007FE2B9 /* ChannelHeaderLoader_Tests.swift */,
2027+
849894942AD96CCC004ACB41 /* ChatChannelListItemView_Tests.swift */,
20262028
84C94D412757C16D007FE2B9 /* ChatChannelListTestHelpers.swift */,
20272029
848399EB275FB41B003075E4 /* ChatChannelListView_Tests.swift */,
2028-
84DEC8DA27609FA200172876 /* MoreChannelActionsView_Tests.swift */,
2030+
84C94C7F27567D3F007FE2B9 /* ChatChannelListViewModel_Tests.swift */,
2031+
84D6B55927DF6EC7009C6D07 /* LoadingView_Tests.swift */,
20292032
91B763A5283EB39600B458A9 /* MoreChannelActionsFullScreenWrappingView_Tests.swift */,
2033+
84DEC8DA27609FA200172876 /* MoreChannelActionsView_Tests.swift */,
2034+
84C94D432757C704007FE2B9 /* MoreChannelActionsViewModel_Tests.swift */,
20302035
84DEC8DC2760A10500172876 /* NoChannelsView_Tests.swift */,
20312036
8413D90127A9654600A89432 /* SearchResultsView_Tests.swift */,
2032-
84D6B55927DF6EC7009C6D07 /* LoadingView_Tests.swift */,
2033-
849894942AD96CCC004ACB41 /* ChatChannelListItemView_Tests.swift */,
20342037
);
20352038
path = ChatChannelList;
20362039
sourceTree = "<group>";
@@ -3082,6 +3085,7 @@
30823085
84C94D66275A660B007FE2B9 /* MessageActionsViewModel_Tests.swift in Sources */,
30833086
84C94D0827578BF2007FE2B9 /* MockFunc.swift in Sources */,
30843087
84B2B5CA281947E100479CEE /* ViewFrameUtils.swift in Sources */,
3088+
4F03F18F2E0140C6001C71A2 /* ChannelAvatarsMerger_Tests.swift in Sources */,
30853089
8423C342277CBA280092DCF1 /* TypingSuggester_Tests.swift in Sources */,
30863090
84507C9A281ACCD70081DDC2 /* AddUsersView_Tests.swift in Sources */,
30873091
4F8D64402DDDCF9300026C09 /* MessageRelativeDateFormatter_Tests.swift in Sources */,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//
2+
// Copyright © 2025 Stream.io Inc. All rights reserved.
3+
//
4+
5+
@testable import StreamChatSwiftUI
6+
@testable import StreamChatTestTools
7+
import XCTest
8+
9+
final class ChannelAvatarsMergerTests: StreamChatTestCase {
10+
private var merger: ChannelAvatarsMerger!
11+
12+
override func setUp() {
13+
super.setUp()
14+
merger = ChannelAvatarsMerger()
15+
}
16+
17+
override func tearDown() {
18+
super.tearDown()
19+
merger = nil
20+
}
21+
22+
func testConcurrentCalls() {
23+
let sourceImages: [UIImage] = [
24+
XCTestCase.TestImages.chewbacca.image,
25+
XCTestCase.TestImages.r2.image,
26+
XCTestCase.TestImages.vader.image,
27+
XCTestCase.TestImages.yoda.image
28+
]
29+
DispatchQueue.concurrentPerform(iterations: 100) { _ in
30+
let images = Array(sourceImages.prefix((1...4).randomElement()!))
31+
let mergedImage = merger.createMergedAvatar(from: images)
32+
XCTAssertNotNil(mergedImage)
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)