From c5041941e3fb4633995220d3f5288694fd6b3d8e Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 4 Jul 2025 16:52:57 +0200 Subject: [PATCH] Fix timer crash by ensuring Timer is scheduled on main thread - Timer.scheduledTimer must be called on main thread with run loop - Wrapped timer scheduling in DispatchQueue.main.async - This prevents EXC_BREAKPOINT crash when called from background threads --- bitchat.xcodeproj/project.pbxproj | 11 ++++++----- bitchat/Services/BluetoothMeshService.swift | 19 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/bitchat.xcodeproj/project.pbxproj b/bitchat.xcodeproj/project.pbxproj index 46a0abde..c5f1e7dc 100644 --- a/bitchat.xcodeproj/project.pbxproj +++ b/bitchat.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 63; objects = { /* Begin PBXBuildFile section */ @@ -36,7 +36,7 @@ 6DC1563390A15C042D059CF9 /* EncryptionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionService.swift; sourceTree = ""; }; 763E0DBA9492A654FC0CDCB9 /* AppInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppInfoView.swift; sourceTree = ""; }; 7EEBDA723E1CFD88758DA4AC /* bitchat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = bitchat.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 997D512074C64904D75DDD40 /* bitchat.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = bitchat.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 997D512074C64904D75DDD40 /* bitchat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = bitchat.app; sourceTree = BUILT_PRODUCTS_DIR; }; A08E03AA0C63E97C91749AEC /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; A2136C3E22D02D4A8DBE7EAB /* BinaryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryProtocol.swift; sourceTree = ""; }; D5C3D880FF8AE1673B20E1E3 /* BluetoothMeshService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothMeshService.swift; sourceTree = ""; }; @@ -179,7 +179,6 @@ ); mainGroup = 18198ED912AAF495D8AF7763; minimizedProjectReferenceProxies = 1; - preferredProjectObjectVersion = 54; projectDirPath = ""; projectRoot = ""; targets = ( @@ -253,6 +252,7 @@ CODE_SIGNING_REQUIRED = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = bitchat/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -261,7 +261,7 @@ "@executable_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - PRODUCT_BUNDLE_IDENTIFIER = com.bitchat.app; + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; PRODUCT_NAME = bitchat; SDKROOT = iphoneos; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; @@ -279,6 +279,7 @@ CODE_SIGNING_REQUIRED = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = L3N5LHJD5Y; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = bitchat/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -287,7 +288,7 @@ "@executable_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - PRODUCT_BUNDLE_IDENTIFIER = com.bitchat.app; + PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; PRODUCT_NAME = bitchat; SDKROOT = iphoneos; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; diff --git a/bitchat/Services/BluetoothMeshService.swift b/bitchat/Services/BluetoothMeshService.swift index 873d2115..174359c8 100644 --- a/bitchat/Services/BluetoothMeshService.swift +++ b/bitchat/Services/BluetoothMeshService.swift @@ -782,17 +782,20 @@ class BluetoothMeshService: NSObject { self.delegate?.didUpdatePeerList(connectedPeerIDs) } } else { - // Cancel any pending update - peerListUpdateTimer?.invalidate() - - // Schedule a new update after debounce interval - peerListUpdateTimer = Timer.scheduledTimer(withTimeInterval: peerListUpdateDebounceInterval, repeats: false) { [weak self] _ in + // Must schedule timer on main thread + DispatchQueue.main.async { [weak self] in guard let self = self else { return } - let connectedPeerIDs = self.getAllConnectedPeerIDs() - // print("[DEBUG] Notifying peer list update after debounce: \(connectedPeerIDs.count) peers") + // Cancel any pending update + self.peerListUpdateTimer?.invalidate() - DispatchQueue.main.async { + // Schedule a new update after debounce interval + self.peerListUpdateTimer = Timer.scheduledTimer(withTimeInterval: self.peerListUpdateDebounceInterval, repeats: false) { [weak self] _ in + guard let self = self else { return } + + let connectedPeerIDs = self.getAllConnectedPeerIDs() + // print("[DEBUG] Notifying peer list update after debounce: \(connectedPeerIDs.count) peers") + self.delegate?.didUpdatePeerList(connectedPeerIDs) } }