Customize handling of asynchronous events by combining event-processing operators using Combine.

Posts under Combine tag

123 Posts

Post

Replies

Boosts

Views

Activity

ICCameraDevice Takes Forever to Be Ready
Using ImageCaptureCore, to send PTP devices to cameras via tether, I noticed that all of my Nikon cameras can take up to an entire minute for PTP events to start logging. My Canons and Sonys are ready instantly. Any idea why? I use the ICDeviceBrowser to browse for cameras, and then request to open the session. According to the docs, it says it's ready after it enumerates its objects? If that's the case, is there a way to bypass that? Even on an empty SD card it's slow.
1
0
800
Oct ’23
Weird issue with SwiftData saving models correctly, but causing a crash when trying to access data prior to the saving
That may not be the best way to explain it. Essentially, I'm requesting data from Reddit and storing it in an object called Request. This object has a timestamp and an array of objects called Post. Everything was working fine until I started to add some code to filter the post that were being fetched from reddit. extension [Request] { func insert(request: Request, in context: ModelContext) { if self.count == 0 { context.logMessage("There are no existing request") context.insert(request) context.logMessage("Request saved") }else { print(request) // No crash print(request.timestamp) // No crash print(request.posts) // Causes a crash } } } When it does crash, it points to this code inside the SwiftData model. This code seems to be something within SwiftData. I didn't write any of this. { @storageRestrictions(accesses: _$backingData, initializes: _posts) init(initialValue) { _$backingData.setValue(forKey: \.posts, to: initialValue) _posts = _SwiftDataNoType() } get { _$observationRegistrar.access(self, keyPath: \.posts) return self.getValue(forKey: \.posts) } set { _$observationRegistrar.withMutation(of: self, keyPath: \.posts) { self.setValue(forKey: \.posts, to: newValue) } } } It has the error at the return self.getValue() line: Thread 5: EXC_BREAKPOINT (code=1, subcode=0x2406965c4) This is the sequence that occurs: View is loaded Checks if it should load a new request If it should, it calls this function private func requestNewData() { redditService.fetchRedditAllData(completion: { result in DispatchQueue.main.async { switch result { case .success(let newRequest): modelContext.logMessage("Successfully retreived and decoded data from Reddit") // Log the success //modelContext.insert(newRequest) requests.insert(request: newRequest, in: modelContext) case .failure: modelContext.logMessage("Failed to retrieve and decode data from Reddit") } } }) } The code for the fetch function is here: func fetchRedditAllData(completion: @escaping (Result<Request, Error>) -> Void) { // Try to construct the URL and return if it fails guard let url = URL(string: RedditRequests.all) else { context.logMessage("Failed to contruct the url for r/all") return } // Try to retrieve data from the URL session.dataTask(with: url, completionHandler: { data, _, error in // If it fails, log the failure if let error = error { self.context.logMessage("Failed to retrieve data from the r/all URL.\n\(error.localizedDescription)") } else { // If it doesn't fail, try to decode the data do { let data = data ?? Data() // Get data let response = try self.decoder.decode(Request.self, from: data) // Decode JSON into Request model completion(.success(response)) // Return response (request) if successful self.context.logMessage("Decoded data") } catch { completion(.failure(error)) self.context.logMessage("Failed to decode data into a Request.\n\(error.localizedDescription)") } } }).resume() } If I don't try to access request.posts before saving it to the context, it works fine. It will fetch the data and store it to the phone and then display it on the phone. When I try to access request.posts to do some filtering, it crashes. Does anyone have any ideas?
1
3
2.3k
Oct ’23
Why does Combine assign crash when writing to an optional property?
This code crashes ("Unexpectedly found nil while unwrapping an Optional value") import Combine class Receiver { &#9;&#9;var value: Int! &#9;&#9;var cancellables = Set<AnyCancellable>([]) &#9;&#9;init(_ p: AnyPublisher<Int,Never>) { &#9;&#9;&#9;&#9;p.assign(to: \.value, on: self).store(in: &cancellables) &#9;&#9;} } let receiver = Receiver(Just(5).eraseToAnyPublisher()) It does not crash if I use p.sink { self.value = $0 }.store(in: &cancellables) instead of the assign, and it does not crash if I do not use an optional for the value-property. To me this looks like a bug in Swift's constructor code, but maybe I am overlooking something?
1
1
1.5k
Sep ’23
Xcode Previews bug? View is not re-rendered as expected
I've made a small reproducing example app to demonstrate this issue. Just create an iOS App project and replace the App and ContentView files with the following code. The app works as expected when running it in a simulator or on a device but the SwiftUI Preview will get stuck showing only the loading state, even though the print statement in the View's body has printed viewModel.state: showingContent(SwiftUITest.ViewModel.Content(text: "Hello world!", reloadButtonTitle: "Reload"))to the console. When stuck showing the loading state (an animated ProgressView), If I change .padding(.all, 12) to e.g. .padding(.all, 2) or vice versa, then that will make the Preview render the expected content. Also, if I tap the Reload-button, it will not show the ProgressView for 2 seconds as expected (and as the app will do when run in a simulator or on a device), instead it will just show a white screen, and the same workaround (changing the padding amount) can be used to make the it render the expected content. Can other people reproduce this behavior, is it a known bug, or am I doing something wrong? TestApp.swift import SwiftUI @main struct SwiftUITestApp: App { var body: some Scene { WindowGroup { ContentView(viewModel: ViewModel( contentLoader: { try! await Task.sleep(nanoseconds: 2_000_000_000) return .init(text: "Hello world!", reloadButtonTitle: "Reload") } )) } } } ContentView.swift import SwiftUI struct ContentView: View { @StateObject var viewModel: ViewModel var body: some View { let _ = print("viewModel.state:", viewModel.state) Group { switch viewModel.state { case .notStarted, .loading: ProgressView() case .showingContent(let content): VStack { Text(content.text) .padding(.all, 12) Button(content.reloadButtonTitle) { viewModel.handle(event: .reloadButtonWasTapped) } } } } .onAppear { viewModel.handle(event: .viewDidAppear) } } } // MARK: - ViewModel @MainActor final class ViewModel: ObservableObject { @Published var state: State = .notStarted let contentLoader: () async -> Content init(contentLoader: @escaping () async -> Content) { self.contentLoader = contentLoader } func handle(event: Event) { switch state { case .notStarted: if event == .viewDidAppear { loadContent() } case .loading: break case .showingContent: if event == .reloadButtonWasTapped { loadContent() } } } func loadContent() { guard state != .loading else { return } state = .loading Task { print("starts loading", Date.now) let content = await contentLoader() print("finished loading", Date.now) state = .showingContent(content) } } enum State: Equatable { case notStarted case loading case showingContent(Content) } struct Content: Equatable { let text: String let reloadButtonTitle: String } enum Event: Equatable { case viewDidAppear case reloadButtonWasTapped } } // MARK: - Preview struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView(viewModel: ViewModel( contentLoader: { try! await Task.sleep(nanoseconds: 2_000_000_000) return .init(text: "Hello world!", reloadButtonTitle: "Reload") } )) } } Here's the simple behavior of the app (recorded from simulator): Each time the view appears, it loads it's content for two seconds while showing a ProgressView, then it shows the content, which includes a Reload button, and if you tap that button it will reload the content for 2 seconds again. I would expect the Preview to behave in the same way.
2
0
1.6k
Sep ’23
Why not all values sink when using concurrent queue as a receiveOn scheduler?
I'm learning Combine. I'm trying to understand some behavior when there is concurrent queue applied to receiveOn as a scheduler. I extracted code to present the situation that I'm trying to understand. let queue = DispatchQueue.global() // Or OperationQueue() let subscription = (1...10).publisher .receive(on: queue) .sink { value in print("Received \(value)") } I'm receiving in debug console such output: Received 1 Received 2 Received 3 Received 7 Received 6 But I was expecting 10 lines in the output. Everytime I run it I'm receiving different results but not 10 lines - 10 values. What is happening here? Does anybody know? Where is 4, 5, 8, 9 and 10? Why completion is arriving faster before all values? Is this a combine bug? I was looking in 2 books related to Combine and in apple documentation. No warnings about using concurrent queues as a schedulers in Combine.
0
0
740
Aug ’23
Mix new @Observable with MVVM and Combine
We currently have our entire app written as SwiftUI Views with ViewModels (currently set as @StateObjects). SwiftUI has a new feature in iOS 17 called @Observable which simplifies the MVVM pattern and would greatly reduce the complexity of our codebase. However, our current ViewModels implement Combine pipelines on the @Published properties which allows us to do all sorts of things from validation of inputs to ensuring lists are filtered correctly. Without the @Published property wrapper in the new @Observable macro, we don't have access to those combine pipelines and so we were wondering how others have solved this? One idea we are floating around is using CurrentValueSubjects as the variable types, but that does pollute the code a little as we have to utilise .send() and .value in the Views which seems like an anti-pattern. Any thoughts or help would be greatly appreciated!
2
3
1.9k
Aug ’23
Crash on Publishers.ReceiveOn.Inner.cancel()
We are experiencing crash on Combine on iOS 16 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000021dc6408c Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [11489] Triggered by Thread: 0 Thread 0 name: Thread 0 Crashed: 0 libsystem_platform.dylib 0x000000021dc6408c _os_unfair_lock_recursive_abort + 36 (lock.c:508) 1 libsystem_platform.dylib 0x000000021dc5e898 _os_unfair_lock_lock_slow + 280 (lock.c:567) 2 Combine 0x00000001d8298174 Publishers.ReceiveOn.Inner.cancel() + 28 (Locking.swift:35) 3 Combine 0x00000001d8297c98 protocol witness for Cancellable.cancel() in conformance Publishers.ReceiveOn<A, B>.Inner<A1> + 24 (<compiler-generated>:0) 4 Combine 0x00000001d828ffc0 Subscribers.Sink.cancel() + 628 (Sink.swift:161) 5 Combine 0x00000001d82ca8ec protocol witness for Cancellable.cancel() in conformance Subscribers.Sink<A, B> + 24 (<compiler-generated>:0) 6 Combine 0x00000001d82945fc AnyCancellable.cancel() + 212 (Subscription.swift:107) 7 Combine 0x00000001d828e250 AnyCancellable.__deallocating_deinit + 16 (Subscription.swift:92) 8 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 9 libswiftCore.dylib 0x00000001c9c15294 swift_arrayDestroy + 124 (Array.cpp:208) 10 libswiftCore.dylib 0x00000001c9a38140 _SetStorage.deinit + 328 (UnsafePointer.swift:954) 11 libswiftCore.dylib 0x00000001c9a38164 _SetStorage.__deallocating_deinit + 16 (SetStorage.swift:0) 12 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 13 AppNameCore 0x00000001033ae3ec MessagesThreadPresenterImpl.deinit + 396 (<compiler-generated>:0) 14 AppNameCore 0x00000001033ae43c MessagesThreadPresenterImpl.__deallocating_deinit + 12 (MessagesThreadPresenter.swift:0) 15 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 16 libswiftCore.dylib 0x00000001c9c25120 bool swift::HeapObjectSideTableEntry::decrementStrong<(swift::PerformDeinit)1>(unsigned int) + 292 (RefCount.h:1032) 17 AppNameCore 0x00000001033b7c44 0x102f64000 + 4537412 18 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 19 Combine 0x00000001d82c0b48 Publishers.FlatMap.Outer.deinit + 232 (<compiler-generated>:0) 20 Combine 0x00000001d82b8244 Publishers.FlatMap.Outer.__deallocating_deinit + 16 (FlatMap.swift:0) 21 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 22 Combine 0x00000001d829366c assignWithTake for SubscriptionStatus + 68 (<compiler-generated>:0) 23 Combine 0x00000001d82906ec outlined assign with take of SubscriptionStatus + 76 (<compiler-generated>:0) 24 Combine 0x00000001d82dd138 closure #1 in Publishers.ReceiveOn.Inner.receive(completion:) + 144 (ReceiveOn.swift:201) 25 Foundation 0x00000001c9fb312c $sIegh_IeyBh_TR + 36 (<compiler-generated>:0) 26 CoreFoundation 0x00000001cfab6514 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28 (CFRunLoop.c:1805) 27 CoreFoundation 0x00000001cfb1ed6c __CFRunLoopDoBlocks + 368 (CFRunLoop.c:1847) 28 CoreFoundation 0x00000001cfaef1cc __CFRunLoopRun + 2452 (CFRunLoop.c:3201) 29 CoreFoundation 0x00000001cfaf3eb0 CFRunLoopRunSpecific + 612 (CFRunLoop.c:3418) 30 GraphicsServices 0x0000000209ce9368 GSEventRunModal + 164 (GSEvent.c:2196) 31 UIKitCore 0x00000001d1fe9668 -[UIApplication _run] + 888 (UIApplication.m:3758) 32 UIKitCore 0x00000001d1fe92cc UIApplicationMain + 340 (UIApplication.m:5348) 33 AppName 0x000000010009190c main + 180 (main.swift:11) 34 dyld 0x00000001ee3ec960 start + 2528 (dyldMain.cpp:1170)
0
2
1.1k
Jun ’23
[iOS 16 Leak?]
Hello For apps built with xcode 13 but ran on ios 16 beta devices, im seeing a potential leak in Combine that i suspect may be causing a breaking bug(the view fails to load anything on subsequent visits after being dismissed, which im suspecting is due to the leaked observable object) . The issue is resolved when built with Xcode 14 Beta, no bug and no leak I am triggering a flow multiple times and seeing the instances of an @ObservableObject used as a @StateObject in a view keep going up in the memory debugger, without the corresponding view leaking to accompany it like ive seen before. so the observable object is being leaked I see the following in the memory graph debugger. It indicates a BoxVTable relation to the observable datastore, which i presume is an internal type i dont have access to, when the view has disappeared Any Ideas? ive checked all the typical closure leak possibilities ive fixed before and this seems to be different
1
1
2.0k
Jun ’23
Mixing Combine and async/await in the same project?
I'm working on an iOS project and I'm wondering if it's possible to mix Combine and the new async/await feature in Swift. I want to leverage the power of Combine's reactive programming paradigm along with the simplified asynchronous code flow provided by async/await. Has anyone tried mixing these two approaches in the same project? Are there any known issues or considerations to keep in mind? Are there any best practices or patterns to follow when combining Combine and async/await? I would appreciate any insights or experiences shared. Thank you in advance!
1
0
1.3k
Jun ’23
Understanding the PassthroughSubject and CurrentValueSubject
Can someone please help me understand PassthroughSubject and CurrentValueSubject? What I understand so far is that they are subjects where subscribers can listen to changes made to these subjects, but I'm really straggling to understand the following. I'm I correct by saying that PassthroughSubject or CurrentValueSubject could replace delegation and asynchronous function calls? Is it possible to delare a subject in Class A and subscribe to listen to those subject changes in Class B and in some other classes or are listeners meant to only be used direclty in SwiftUI structs? Thanks
0
0
941
Jun ’23
Live Activity Push Token Updates getting Called Twice
I'm trying to get push tokens for Live Activities but I am getting the same token twice, Why is that? Is there any other way to get the token just once, so I can hit the API to save the token. Here's the code: Task { for await data in runningActivity.pushTokenUpdates { let myToken = data.hexString self.count += 1 print("Count \(self.count)\n" + myToken) } Output: Count 1 80dc21086f81.........646d7084805dc Count 2 80dc21086f81.........646d7084805dc I can't seem to understand why this is happening, and some times it takes significantly longer to get the tokens. Am I doing anything wrong? Please do share your thoughts. Thank you!
1
1
1.7k
Jun ’23
What thread does Combine `.collect` method emit on?
What is the expected thread on which a .collect operation in Swift's Combine will emit? Specifically I am seeing this code crash in the second precondition, but not the first: return Publishers.MergeMany(publishers) .handleEvents(receiveOutput: { _ in precondition(Thread.isMainThread) // <- This is fine }) .collect() .handleEvents(receiveOutput: { _ in precondition(Thread.isMainThread) // <- Crash is here }) It is as if the .collect operation is picking a different thread to use, even though the final publisher in the MergeMany must have emitted on the main thread. I have deduced this behavior via crash logs uploaded from Firebase. Can anyone explain this observed behavior?
0
1
810
May ’23
Debug Wrapper around NotificationCenter
I've been struggling with writing some dependency injection types for Foundation types like NotificationCenter, UIDevice, etc. I've created a sample package to demonstrate: https://github.com/MFB-Technologies-Inc/notification-center-client-demo. The goal is to mimic NotificationCenter's Publisher and notifications AsyncSequence. LiveNotificationCenterClientTests.testStream will fail unless it's run in isolation. If more than one test is run, it will never complete because no values are ever received from the stream. MockNotificationCenterClientTests.testPublisher fails because the expectations are not fulfilled before the timeout. For whatever reason, the published values are not being received in the sink. MockNotificationCenterClientTests.testStream never completes because the value is being endlessly awaited. It seems that there are some fundamental things about concurrency that I'm getting wrong. Can anybody help me debug this? For the two stream tests, I know I could rewrite them to fail with a timeout like the publisher tests but that's not the real problem.
0
0
907
May ’23
Fatal Error - Couldn't parse lesssonData.json as array <Lesson>
Hello, I've completed the Landmarks App Apple Developer tutorial, since finishing it I decided to create a project using the .JSON code from the project. I've wrote the code in an identical layout as the tutorial, however I am receiving the error - Couldn't parse lesssonData.json as array - when trying to load a preview and the app builds successfully but crashes when I launch it. Below is the code, any help is appreciated! LessonList.swift import SwiftUI struct LessonList: View { var lesson: Lesson var body: some View { VStack { List { Section { ForEach(lessons, id: \.self) { lesson in Label(lesson.name, systemImage: "house") } } Section { Label("Hello World!", systemImage: "globe") } } } } } struct LessonList_Previews: PreviewProvider { static var lessons = ModelData().lessons static var previews: some View { LessonList(lesson: lessons[0]) } } ModelData.swift import Foundation import Combine final class ModelData: ObservableObject { @Published var lessons: [Lesson] = load("lessonData.json") } var lessons: [Lesson] = load("lessonData.json") func load<T: Decodable>(_ filename: String) -> T { let data: Data guard let file = Bundle.main.url(forResource: filename, withExtension: nil) else { fatalError("Couldn't find \(filename) in main bundle.") } do { data = try Data(contentsOf: file) } catch { fatalError("Couldn't load \(filename) from main bundle:\n\(error)") } do { let decoder = JSONDecoder() return try decoder.decode(T.self, from: data) } catch { fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)") // Error on this Line } } lessonData.JSON [ { "id":"1001", "lessonNo":"Lesson 1", "name":"Introduction to Photography", "category":"Introduction", }, { "id":"1002", "lessonNo":"Lesson 2", "name":"Negative and Positive Space", "category":"Introduction", }, { "id":"1003", "lessonNo":"Lesson 3", "name":"Introduction to Camera Angles", "category":"Introduction", }, { "id":"1004", "lessonNo":"Lesson 4", "name":"Lighting and Framing", "category":"Beginners", }, { "id":"1005", "lessonNo":"Lesson 5", "name":"Still Photography", "category":"Beginners", }, { "id":"1006", "lessonNo":"Lesson 6", "name":"Motion Photograhy", "category":"Beginners", }, { "id":"1007", "lessonNo":"Lesson 7", "name":"Aperture and F-Stops", "category":"Intermiediate", }, { "id":"1008", "lessonNo":"Lesson 8", "name":"Shutter Speeds", "category":"Intermiediate", }, { "id":"1009", "lessonNo":"Lesson 9", "name":"Advanced Framing", "category":"Advanced", }, { "id":"1010", "lessonNo":"Lesson 10", "name":"Advanced Aperture, F-Stops and Shutter Speeds", "category":"Advanced", }, ]
1
1
1k
May ’23
What is the return/throw state of Publisher.values if there is no error and no values
I'm converting some Combine publishers to async using .values and trying to understand what happens when: A Publisher completes before emitting a value. Here is some example code: let response = client.fetch(query: query) .tryMap { /* map the data, or throw a mapping error if it doesn't map. */ } return Model() } .eraseToAnyPublisher() .values for try await result in response { return result } throw AsyncCombineError.finishedWithoutValue // my custom error What happens with .values if the publisher completes without emitting any values? It returns a type of AsyncThrowingSequence<Self> Will it throw? return? hang? or is this state impossible to happen? Thanks and please enlighten me if I am misunderstanding structured concurrency. This is new to me!
1
0
899
May ’23
RealityKit - loading multiple usdz models into Entities
I'm new to RealityKit and facing the following issue - I'm trying to load 8 models asynchronously using the following code - cancellable = Entity.loadModelAsync(named: "m1") .append(Entity.loadModelAsync(named: "m2")) .append(Entity.loadModelAsync(named: "m3")) .append(Entity.loadModelAsync(named: "m4")) .append(Entity.loadModelAsync(named: "m5")) .append(Entity.loadModelAsync(named: "m6")) .append(Entity.loadModelAsync(named: "m7")) .append(Entity.loadModelAsync(named:"m8")) .collect() .sink(receiveCompletion: { loadCompletion in if case let .failure(error) = loadCompletion { print("Unable to load model \(error)") } self.cancellable?.cancel() }, receiveValue: { entities in }) //cancellable is an instance property defined as var cancellable:AnyCancellable? The code works as expected. However there is an Xcode issue I'm facing - the editor constantly gets stuck at "Indexing: Processing Files" and subsequently the Build process gets stuck too. This only happens when the number of models in the above chain is more than 3-4. Is there any way to break down the above loading step into smaller parts, without needing to load the models individually (i.e. without .append)?
0
0
1.1k
Apr ’23
Combine AnyCancellable.store(in:) EXC_BAD_ACCESS
I'm seeing a strange and random crash with my combine networking after updating Xcode to version 14.3 (14E222b) a few days ago. The code below is crashing with EXC_BAD_ACCESS on .store(in:) and wasn't on the previous version of Xcode. private var cancellables = Set<AnyCancellable>() func request() async { URLSession.shared .dataTaskPublisher(for: URL(string: "")!) .map{$0.data} .decode(type: Type.self, decoder: JSONDecoder()) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { print ("Received completion: \($0).") }, receiveValue: { data in print(data) }) .store(in: &cancellables) // <- CRASHING HERE }
2
1
2.6k
Apr ’23
TableView changes not work correctly in swiftUI
I'm using uikit tableview in swiftui. I get data from WebSocket and I want to update my tableview live. I successfully get data from network and update it in viewModel and pass it to QuotesTableView. The problem is occur in here. TableView not update correctly my data, i.e tableViewData's first value is Symbol1 but it shows Symbol1 data in first indexpath. I debug it in cellForRowAt function and see I get correct data, but not show correct item in cell :( it randomly changes order of data in tableview. but tableviewData order not change. @StateObject private var viewModel = QuotesViewModel() var body: some View { ZStack { Color.init(hex: "#293c54").edgesIgnoringSafeArea(.all) QuotesTableView(tableViewData: $viewModel.list) .background(Color.clear) } } } import Combine class QuotesViewModel: ObservableObject { var cancellables = Set<AnyCancellable>() // MARK: - Input var selectedSymbols: String /// Symbols list @Published var list: [SymbolsInDataModel] = .init() // MARK: - Output // MARK: - Init init() { socket = SocketManager.shared observeSocketValues() bindView() } // MARK: - Business Logic let socket: SocketManager // MARK: - Config } // MARK: - Bind View extension QuotesViewModel { /// observe view actions in here... func bindView() { } } // MARK: - Observation Socket Data extension QuotesViewModel { func observeSocketValues() { socket.$symbolsList.sink(receiveValue: { newSymbols in self.list = newSymbols }) .store(in: &cancellables) socket.$symbolsList .filter { !$0.isEmpty } .first { _ in self.list = self.socket.symbolsList return true } .sink(receiveValue: {_ in}) .store(in: &cancellables) } } struct QuotesTableView: UIViewRepresentable { // The data source for the table view @Binding var tableViewData: [SymbolsInDataModel] var selectClicked: ((_ item: SymbolsInDataModel) -> Void)? func makeUIView(context: Context) -> UITableView { let tableView = UITableView() tableView.translatesAutoresizingMaskIntoConstraints = false tableView.backgroundColor = .clear tableView.dataSource = context.coordinator tableView.showsVerticalScrollIndicator = false tableView.delegate = context.coordinator tableView.register(HostingCell.self, forCellReuseIdentifier: "Cell") return tableView } func updateUIView(_ uiView: UITableView, context: Context) { // Reload the table view data whenever the data changes uiView.reloadData() } func makeCoordinator() -> Coordinator { Coordinator(self) } } // MARK: - CompetitionsTableView -> Coordinator extension QuotesTableView { class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate { var parent: QuotesTableView init(_ tableView: QuotesTableView) { parent = tableView } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { parent.tableViewData.count } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: false) } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! HostingCell tableViewCell.backgroundColor = .clear print("indexpath: \(indexPath.row) item: \(parent.tableViewData[indexPath.row])") // Set the root view of the hosting controller to the view for this cell let row = parent.tableViewData[indexPath.row] let hostingController = UIHostingController( rootView: AnyView( QuotesCellView(item: row, selectAction: self.parent.selectClicked) ) ) hostingController.view.backgroundColor = .clear // create & setup hosting controller only once if tableViewCell.host == nil { tableViewCell.host = hostingController let tableCellViewContent = hostingController.view! tableCellViewContent.translatesAutoresizingMaskIntoConstraints = false tableViewCell.contentView.addSubview(tableCellViewContent) tableCellViewContent.topAnchor.constraint(equalTo: tableViewCell.contentView.topAnchor).isActive = true tableCellViewContent.leftAnchor.constraint(equalTo: tableViewCell.contentView.leftAnchor).isActive = true tableCellViewContent.bottomAnchor.constraint(equalTo: tableViewCell.contentView.bottomAnchor).isActive = true tableCellViewContent.rightAnchor.constraint(equalTo: tableViewCell.contentView.rightAnchor).isActive = true } else { // reused cell, so just set other SwiftUI root view tableViewCell.host = hostingController } tableViewCell.setNeedsLayout() return tableViewCell } } }
1
1
967
Apr ’23
GraphQL on iOS
Hi, I'm starting to look into GraphQL and how to support it natively on my apps, most tutorials online are about using Apollo, but I rather not introduce third party code at this point. Does someone knows any reference I can use? Thank you
0
0
814
Mar ’23
Removing cancellable from set crashes app
I have a publisher, pipelinePublisher, which runs a combine pipeline of various operations, some of which send a state update to a statePublisher passed in as an argument. pipelinePublisher gets removed on completion of its Combine pipeline: func myFunction(_ request: MyRequest) -> PassthroughSubject<State, Never> { let statePublisher = PassthroughSubject<State, Never>() let presentationSubject = CurrentValueSubject<MyRequest, Error>(request) var pipelinePublisher: AnyCancellable! pipelinePublisher = presentationSubject .eraseToAnyPublisher() .checkSomething(returningStateTo: statePublisher) // a few more operators here... .sink( receiveCompletion: { [weak self] _ in self?.cancellables.remove(pipelinePublisher) // Crash happens here }, receiveValue: { _ in } ) pipelinePublisher.store(in: &cancellables) return statePublisher .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } However, very occasionally when I call the function multiple times in very quick succession, the app crashes on the line self?.cancellables.remove(pipelinePublisher). This usually brings up one of two possible stack traces. This first is this: 2022-12-21 15:24:51.926131+0000 MyApp[23082:12933690] -[_NSCoreDataTaggedObjectID member:]: unrecognized selector sent to instance 0x8000000000000000 2022-12-21 15:24:51.931941+0000 MyApp[23082:12933690] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSCoreDataTaggedObjectID member:]: unrecognized selector sent to instance 0x8000000000000000' *** First throw call stack: ( 0 CoreFoundation 0x000000018040e7c8 __exceptionPreprocess + 172 1 libobjc.A.dylib 0x0000000180051144 objc_exception_throw + 56 2 CoreFoundation 0x000000018041d47c +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0 3 CoreFoundation 0x00000001804126c8 ___forwarding___ + 1308 4 CoreFoundation 0x0000000180414b4c _CF_forwarding_prep_0 + 92 5 libswiftCore.dylib 0x000000018be6ee68 $sSh8_VariantV6removeyxSgxF + 160 6 MyApp 0x00000001026c6080 $s12MyApp0A0C17myFunctiony7Combine12AnyPublisherVyAA12StateOs5NeverOGAA19MyRequestVFyAE11SubscribersO10CompletionOy_s5Error_pGcfU_ + 440 7 Combine 0x000000019baa2a70 $s7Combine11SubscribersO4SinkC7receive10completionyAC10CompletionOy_q_G_tF + 364 8 Combine 0x000000019baa2f28 $s7Combine11SubscribersO4SinkCy_xq_GAA10SubscriberA2aGP7receive10completionyAC10CompletionOy_7FailureQzG_tFTW + 20 9 Combine 0x000000019bb541cc $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tF + 1516 10 Combine 0x000000019bb55328 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLCy_xq__qd__GAA10SubscriberA2aJP7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tFTW + 20 11 Combine 0x000000019bb53474 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC12receiveInner10completion_yAA11SubscribersO10CompletionOy_7FailureQzG_SitF + 1668 12 Combine 0x000000019bb52de4 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC4SideV7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tF + 20 13 Combine 0x000000019bac45ec $s7Combine6FutureC7Conduit33_3AE68DE9BADC00342FC052FEBC7D3BA6LLC7fulfillyys6ResultOyxq_GF + 1056 14 Combine 0x000000019bac4960 $s7Combine6FutureC7Conduit33_3AE68DE9BADC00342FC052FEBC7D3BA6LLC6finish10completionyAA11SubscribersO10CompletionOy_q_G_tF + 336 15 Combine 0x000000019bac2de4 $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GFyAA11ConduitBaseCyxq_GXEfU0_ + 156 16 Combine 0x000000019bac6b28 $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GFyAA11ConduitBaseCyxq_GXEfU0_TA + 16 17 Combine 0x000000019bae5140 $s7Combine11ConduitListO7forEachyyyAA0B4BaseCyxq_GKXEKF + 212 18 Combine 0x000000019bac2bfc $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GF + 716 19 Combine 0x000000019bac6b08 $s7Combine6FutureCyACyxq_Gyys6ResultOyxq_GcccfcyAGcfU_TA + 20 20 MyApp 0x0000000102541dd8 $s7Combine6FutureC12MyApps5Error_pRs_rlE9operationACyxsAE_pGxyYaKc_tcfcyys6ResultOyxsAE_pGccfU_yyYaYbcfU_TY2_ + 212 21 MyApp 0x0000000102542705 $s7Combine6FutureC12MyApps5Error_pRs_rlE9operationACyxsAE_pGxyYaKc_tcfcyys6ResultOyxsAE_pGccfU_yyYaYbcfU_TATQ0_ + 1 22 MyApp 0x000000010242f1a1 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTQ0_ + 1 23 MyApp 0x000000010242f749 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTA.24TQ0_ + 1 24 libswift_Concurrency.dylib 0x00000001b03bedcd _ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE + 1 ) libc++abi: terminating with uncaught exception of type NSException The second is in the same place but with the error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber member:]: unrecognized selector sent to instance 0x8000000000000000' What is causing this? I've tried making pipelinePublisher optional and having a check that it exists before it gets removed but it does actually exist and still crashes. I can't figure this out, please help!
0
0
1.2k
Dec ’22
ICCameraDevice Takes Forever to Be Ready
Using ImageCaptureCore, to send PTP devices to cameras via tether, I noticed that all of my Nikon cameras can take up to an entire minute for PTP events to start logging. My Canons and Sonys are ready instantly. Any idea why? I use the ICDeviceBrowser to browse for cameras, and then request to open the session. According to the docs, it says it's ready after it enumerates its objects? If that's the case, is there a way to bypass that? Even on an empty SD card it's slow.
Replies
1
Boosts
0
Views
800
Activity
Oct ’23
Weird issue with SwiftData saving models correctly, but causing a crash when trying to access data prior to the saving
That may not be the best way to explain it. Essentially, I'm requesting data from Reddit and storing it in an object called Request. This object has a timestamp and an array of objects called Post. Everything was working fine until I started to add some code to filter the post that were being fetched from reddit. extension [Request] { func insert(request: Request, in context: ModelContext) { if self.count == 0 { context.logMessage("There are no existing request") context.insert(request) context.logMessage("Request saved") }else { print(request) // No crash print(request.timestamp) // No crash print(request.posts) // Causes a crash } } } When it does crash, it points to this code inside the SwiftData model. This code seems to be something within SwiftData. I didn't write any of this. { @storageRestrictions(accesses: _$backingData, initializes: _posts) init(initialValue) { _$backingData.setValue(forKey: \.posts, to: initialValue) _posts = _SwiftDataNoType() } get { _$observationRegistrar.access(self, keyPath: \.posts) return self.getValue(forKey: \.posts) } set { _$observationRegistrar.withMutation(of: self, keyPath: \.posts) { self.setValue(forKey: \.posts, to: newValue) } } } It has the error at the return self.getValue() line: Thread 5: EXC_BREAKPOINT (code=1, subcode=0x2406965c4) This is the sequence that occurs: View is loaded Checks if it should load a new request If it should, it calls this function private func requestNewData() { redditService.fetchRedditAllData(completion: { result in DispatchQueue.main.async { switch result { case .success(let newRequest): modelContext.logMessage("Successfully retreived and decoded data from Reddit") // Log the success //modelContext.insert(newRequest) requests.insert(request: newRequest, in: modelContext) case .failure: modelContext.logMessage("Failed to retrieve and decode data from Reddit") } } }) } The code for the fetch function is here: func fetchRedditAllData(completion: @escaping (Result<Request, Error>) -> Void) { // Try to construct the URL and return if it fails guard let url = URL(string: RedditRequests.all) else { context.logMessage("Failed to contruct the url for r/all") return } // Try to retrieve data from the URL session.dataTask(with: url, completionHandler: { data, _, error in // If it fails, log the failure if let error = error { self.context.logMessage("Failed to retrieve data from the r/all URL.\n\(error.localizedDescription)") } else { // If it doesn't fail, try to decode the data do { let data = data ?? Data() // Get data let response = try self.decoder.decode(Request.self, from: data) // Decode JSON into Request model completion(.success(response)) // Return response (request) if successful self.context.logMessage("Decoded data") } catch { completion(.failure(error)) self.context.logMessage("Failed to decode data into a Request.\n\(error.localizedDescription)") } } }).resume() } If I don't try to access request.posts before saving it to the context, it works fine. It will fetch the data and store it to the phone and then display it on the phone. When I try to access request.posts to do some filtering, it crashes. Does anyone have any ideas?
Replies
1
Boosts
3
Views
2.3k
Activity
Oct ’23
Why does Combine assign crash when writing to an optional property?
This code crashes ("Unexpectedly found nil while unwrapping an Optional value") import Combine class Receiver { &#9;&#9;var value: Int! &#9;&#9;var cancellables = Set<AnyCancellable>([]) &#9;&#9;init(_ p: AnyPublisher<Int,Never>) { &#9;&#9;&#9;&#9;p.assign(to: \.value, on: self).store(in: &cancellables) &#9;&#9;} } let receiver = Receiver(Just(5).eraseToAnyPublisher()) It does not crash if I use p.sink { self.value = $0 }.store(in: &cancellables) instead of the assign, and it does not crash if I do not use an optional for the value-property. To me this looks like a bug in Swift's constructor code, but maybe I am overlooking something?
Replies
1
Boosts
1
Views
1.5k
Activity
Sep ’23
Xcode Previews bug? View is not re-rendered as expected
I've made a small reproducing example app to demonstrate this issue. Just create an iOS App project and replace the App and ContentView files with the following code. The app works as expected when running it in a simulator or on a device but the SwiftUI Preview will get stuck showing only the loading state, even though the print statement in the View's body has printed viewModel.state: showingContent(SwiftUITest.ViewModel.Content(text: "Hello world!", reloadButtonTitle: "Reload"))to the console. When stuck showing the loading state (an animated ProgressView), If I change .padding(.all, 12) to e.g. .padding(.all, 2) or vice versa, then that will make the Preview render the expected content. Also, if I tap the Reload-button, it will not show the ProgressView for 2 seconds as expected (and as the app will do when run in a simulator or on a device), instead it will just show a white screen, and the same workaround (changing the padding amount) can be used to make the it render the expected content. Can other people reproduce this behavior, is it a known bug, or am I doing something wrong? TestApp.swift import SwiftUI @main struct SwiftUITestApp: App { var body: some Scene { WindowGroup { ContentView(viewModel: ViewModel( contentLoader: { try! await Task.sleep(nanoseconds: 2_000_000_000) return .init(text: "Hello world!", reloadButtonTitle: "Reload") } )) } } } ContentView.swift import SwiftUI struct ContentView: View { @StateObject var viewModel: ViewModel var body: some View { let _ = print("viewModel.state:", viewModel.state) Group { switch viewModel.state { case .notStarted, .loading: ProgressView() case .showingContent(let content): VStack { Text(content.text) .padding(.all, 12) Button(content.reloadButtonTitle) { viewModel.handle(event: .reloadButtonWasTapped) } } } } .onAppear { viewModel.handle(event: .viewDidAppear) } } } // MARK: - ViewModel @MainActor final class ViewModel: ObservableObject { @Published var state: State = .notStarted let contentLoader: () async -> Content init(contentLoader: @escaping () async -> Content) { self.contentLoader = contentLoader } func handle(event: Event) { switch state { case .notStarted: if event == .viewDidAppear { loadContent() } case .loading: break case .showingContent: if event == .reloadButtonWasTapped { loadContent() } } } func loadContent() { guard state != .loading else { return } state = .loading Task { print("starts loading", Date.now) let content = await contentLoader() print("finished loading", Date.now) state = .showingContent(content) } } enum State: Equatable { case notStarted case loading case showingContent(Content) } struct Content: Equatable { let text: String let reloadButtonTitle: String } enum Event: Equatable { case viewDidAppear case reloadButtonWasTapped } } // MARK: - Preview struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView(viewModel: ViewModel( contentLoader: { try! await Task.sleep(nanoseconds: 2_000_000_000) return .init(text: "Hello world!", reloadButtonTitle: "Reload") } )) } } Here's the simple behavior of the app (recorded from simulator): Each time the view appears, it loads it's content for two seconds while showing a ProgressView, then it shows the content, which includes a Reload button, and if you tap that button it will reload the content for 2 seconds again. I would expect the Preview to behave in the same way.
Replies
2
Boosts
0
Views
1.6k
Activity
Sep ’23
Why not all values sink when using concurrent queue as a receiveOn scheduler?
I'm learning Combine. I'm trying to understand some behavior when there is concurrent queue applied to receiveOn as a scheduler. I extracted code to present the situation that I'm trying to understand. let queue = DispatchQueue.global() // Or OperationQueue() let subscription = (1...10).publisher .receive(on: queue) .sink { value in print("Received \(value)") } I'm receiving in debug console such output: Received 1 Received 2 Received 3 Received 7 Received 6 But I was expecting 10 lines in the output. Everytime I run it I'm receiving different results but not 10 lines - 10 values. What is happening here? Does anybody know? Where is 4, 5, 8, 9 and 10? Why completion is arriving faster before all values? Is this a combine bug? I was looking in 2 books related to Combine and in apple documentation. No warnings about using concurrent queues as a schedulers in Combine.
Replies
0
Boosts
0
Views
740
Activity
Aug ’23
Mix new @Observable with MVVM and Combine
We currently have our entire app written as SwiftUI Views with ViewModels (currently set as @StateObjects). SwiftUI has a new feature in iOS 17 called @Observable which simplifies the MVVM pattern and would greatly reduce the complexity of our codebase. However, our current ViewModels implement Combine pipelines on the @Published properties which allows us to do all sorts of things from validation of inputs to ensuring lists are filtered correctly. Without the @Published property wrapper in the new @Observable macro, we don't have access to those combine pipelines and so we were wondering how others have solved this? One idea we are floating around is using CurrentValueSubjects as the variable types, but that does pollute the code a little as we have to utilise .send() and .value in the Views which seems like an anti-pattern. Any thoughts or help would be greatly appreciated!
Replies
2
Boosts
3
Views
1.9k
Activity
Aug ’23
Crash on Publishers.ReceiveOn.Inner.cancel()
We are experiencing crash on Combine on iOS 16 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000021dc6408c Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [11489] Triggered by Thread: 0 Thread 0 name: Thread 0 Crashed: 0 libsystem_platform.dylib 0x000000021dc6408c _os_unfair_lock_recursive_abort + 36 (lock.c:508) 1 libsystem_platform.dylib 0x000000021dc5e898 _os_unfair_lock_lock_slow + 280 (lock.c:567) 2 Combine 0x00000001d8298174 Publishers.ReceiveOn.Inner.cancel() + 28 (Locking.swift:35) 3 Combine 0x00000001d8297c98 protocol witness for Cancellable.cancel() in conformance Publishers.ReceiveOn<A, B>.Inner<A1> + 24 (<compiler-generated>:0) 4 Combine 0x00000001d828ffc0 Subscribers.Sink.cancel() + 628 (Sink.swift:161) 5 Combine 0x00000001d82ca8ec protocol witness for Cancellable.cancel() in conformance Subscribers.Sink<A, B> + 24 (<compiler-generated>:0) 6 Combine 0x00000001d82945fc AnyCancellable.cancel() + 212 (Subscription.swift:107) 7 Combine 0x00000001d828e250 AnyCancellable.__deallocating_deinit + 16 (Subscription.swift:92) 8 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 9 libswiftCore.dylib 0x00000001c9c15294 swift_arrayDestroy + 124 (Array.cpp:208) 10 libswiftCore.dylib 0x00000001c9a38140 _SetStorage.deinit + 328 (UnsafePointer.swift:954) 11 libswiftCore.dylib 0x00000001c9a38164 _SetStorage.__deallocating_deinit + 16 (SetStorage.swift:0) 12 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 13 AppNameCore 0x00000001033ae3ec MessagesThreadPresenterImpl.deinit + 396 (<compiler-generated>:0) 14 AppNameCore 0x00000001033ae43c MessagesThreadPresenterImpl.__deallocating_deinit + 12 (MessagesThreadPresenter.swift:0) 15 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 16 libswiftCore.dylib 0x00000001c9c25120 bool swift::HeapObjectSideTableEntry::decrementStrong<(swift::PerformDeinit)1>(unsigned int) + 292 (RefCount.h:1032) 17 AppNameCore 0x00000001033b7c44 0x102f64000 + 4537412 18 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 19 Combine 0x00000001d82c0b48 Publishers.FlatMap.Outer.deinit + 232 (<compiler-generated>:0) 20 Combine 0x00000001d82b8244 Publishers.FlatMap.Outer.__deallocating_deinit + 16 (FlatMap.swift:0) 21 libswiftCore.dylib 0x00000001c9c24134 _swift_release_dealloc + 56 (HeapObject.cpp:706) 22 Combine 0x00000001d829366c assignWithTake for SubscriptionStatus + 68 (<compiler-generated>:0) 23 Combine 0x00000001d82906ec outlined assign with take of SubscriptionStatus + 76 (<compiler-generated>:0) 24 Combine 0x00000001d82dd138 closure #1 in Publishers.ReceiveOn.Inner.receive(completion:) + 144 (ReceiveOn.swift:201) 25 Foundation 0x00000001c9fb312c $sIegh_IeyBh_TR + 36 (<compiler-generated>:0) 26 CoreFoundation 0x00000001cfab6514 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28 (CFRunLoop.c:1805) 27 CoreFoundation 0x00000001cfb1ed6c __CFRunLoopDoBlocks + 368 (CFRunLoop.c:1847) 28 CoreFoundation 0x00000001cfaef1cc __CFRunLoopRun + 2452 (CFRunLoop.c:3201) 29 CoreFoundation 0x00000001cfaf3eb0 CFRunLoopRunSpecific + 612 (CFRunLoop.c:3418) 30 GraphicsServices 0x0000000209ce9368 GSEventRunModal + 164 (GSEvent.c:2196) 31 UIKitCore 0x00000001d1fe9668 -[UIApplication _run] + 888 (UIApplication.m:3758) 32 UIKitCore 0x00000001d1fe92cc UIApplicationMain + 340 (UIApplication.m:5348) 33 AppName 0x000000010009190c main + 180 (main.swift:11) 34 dyld 0x00000001ee3ec960 start + 2528 (dyldMain.cpp:1170)
Replies
0
Boosts
2
Views
1.1k
Activity
Jun ’23
[iOS 16 Leak?]
Hello For apps built with xcode 13 but ran on ios 16 beta devices, im seeing a potential leak in Combine that i suspect may be causing a breaking bug(the view fails to load anything on subsequent visits after being dismissed, which im suspecting is due to the leaked observable object) . The issue is resolved when built with Xcode 14 Beta, no bug and no leak I am triggering a flow multiple times and seeing the instances of an @ObservableObject used as a @StateObject in a view keep going up in the memory debugger, without the corresponding view leaking to accompany it like ive seen before. so the observable object is being leaked I see the following in the memory graph debugger. It indicates a BoxVTable relation to the observable datastore, which i presume is an internal type i dont have access to, when the view has disappeared Any Ideas? ive checked all the typical closure leak possibilities ive fixed before and this seems to be different
Replies
1
Boosts
1
Views
2.0k
Activity
Jun ’23
Mixing Combine and async/await in the same project?
I'm working on an iOS project and I'm wondering if it's possible to mix Combine and the new async/await feature in Swift. I want to leverage the power of Combine's reactive programming paradigm along with the simplified asynchronous code flow provided by async/await. Has anyone tried mixing these two approaches in the same project? Are there any known issues or considerations to keep in mind? Are there any best practices or patterns to follow when combining Combine and async/await? I would appreciate any insights or experiences shared. Thank you in advance!
Replies
1
Boosts
0
Views
1.3k
Activity
Jun ’23
Understanding the PassthroughSubject and CurrentValueSubject
Can someone please help me understand PassthroughSubject and CurrentValueSubject? What I understand so far is that they are subjects where subscribers can listen to changes made to these subjects, but I'm really straggling to understand the following. I'm I correct by saying that PassthroughSubject or CurrentValueSubject could replace delegation and asynchronous function calls? Is it possible to delare a subject in Class A and subscribe to listen to those subject changes in Class B and in some other classes or are listeners meant to only be used direclty in SwiftUI structs? Thanks
Replies
0
Boosts
0
Views
941
Activity
Jun ’23
Live Activity Push Token Updates getting Called Twice
I'm trying to get push tokens for Live Activities but I am getting the same token twice, Why is that? Is there any other way to get the token just once, so I can hit the API to save the token. Here's the code: Task { for await data in runningActivity.pushTokenUpdates { let myToken = data.hexString self.count += 1 print("Count \(self.count)\n" + myToken) } Output: Count 1 80dc21086f81.........646d7084805dc Count 2 80dc21086f81.........646d7084805dc I can't seem to understand why this is happening, and some times it takes significantly longer to get the tokens. Am I doing anything wrong? Please do share your thoughts. Thank you!
Replies
1
Boosts
1
Views
1.7k
Activity
Jun ’23
What thread does Combine `.collect` method emit on?
What is the expected thread on which a .collect operation in Swift's Combine will emit? Specifically I am seeing this code crash in the second precondition, but not the first: return Publishers.MergeMany(publishers) .handleEvents(receiveOutput: { _ in precondition(Thread.isMainThread) // <- This is fine }) .collect() .handleEvents(receiveOutput: { _ in precondition(Thread.isMainThread) // <- Crash is here }) It is as if the .collect operation is picking a different thread to use, even though the final publisher in the MergeMany must have emitted on the main thread. I have deduced this behavior via crash logs uploaded from Firebase. Can anyone explain this observed behavior?
Replies
0
Boosts
1
Views
810
Activity
May ’23
Debug Wrapper around NotificationCenter
I've been struggling with writing some dependency injection types for Foundation types like NotificationCenter, UIDevice, etc. I've created a sample package to demonstrate: https://github.com/MFB-Technologies-Inc/notification-center-client-demo. The goal is to mimic NotificationCenter's Publisher and notifications AsyncSequence. LiveNotificationCenterClientTests.testStream will fail unless it's run in isolation. If more than one test is run, it will never complete because no values are ever received from the stream. MockNotificationCenterClientTests.testPublisher fails because the expectations are not fulfilled before the timeout. For whatever reason, the published values are not being received in the sink. MockNotificationCenterClientTests.testStream never completes because the value is being endlessly awaited. It seems that there are some fundamental things about concurrency that I'm getting wrong. Can anybody help me debug this? For the two stream tests, I know I could rewrite them to fail with a timeout like the publisher tests but that's not the real problem.
Replies
0
Boosts
0
Views
907
Activity
May ’23
Fatal Error - Couldn't parse lesssonData.json as array <Lesson>
Hello, I've completed the Landmarks App Apple Developer tutorial, since finishing it I decided to create a project using the .JSON code from the project. I've wrote the code in an identical layout as the tutorial, however I am receiving the error - Couldn't parse lesssonData.json as array - when trying to load a preview and the app builds successfully but crashes when I launch it. Below is the code, any help is appreciated! LessonList.swift import SwiftUI struct LessonList: View { var lesson: Lesson var body: some View { VStack { List { Section { ForEach(lessons, id: \.self) { lesson in Label(lesson.name, systemImage: "house") } } Section { Label("Hello World!", systemImage: "globe") } } } } } struct LessonList_Previews: PreviewProvider { static var lessons = ModelData().lessons static var previews: some View { LessonList(lesson: lessons[0]) } } ModelData.swift import Foundation import Combine final class ModelData: ObservableObject { @Published var lessons: [Lesson] = load("lessonData.json") } var lessons: [Lesson] = load("lessonData.json") func load<T: Decodable>(_ filename: String) -> T { let data: Data guard let file = Bundle.main.url(forResource: filename, withExtension: nil) else { fatalError("Couldn't find \(filename) in main bundle.") } do { data = try Data(contentsOf: file) } catch { fatalError("Couldn't load \(filename) from main bundle:\n\(error)") } do { let decoder = JSONDecoder() return try decoder.decode(T.self, from: data) } catch { fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)") // Error on this Line } } lessonData.JSON [ { "id":"1001", "lessonNo":"Lesson 1", "name":"Introduction to Photography", "category":"Introduction", }, { "id":"1002", "lessonNo":"Lesson 2", "name":"Negative and Positive Space", "category":"Introduction", }, { "id":"1003", "lessonNo":"Lesson 3", "name":"Introduction to Camera Angles", "category":"Introduction", }, { "id":"1004", "lessonNo":"Lesson 4", "name":"Lighting and Framing", "category":"Beginners", }, { "id":"1005", "lessonNo":"Lesson 5", "name":"Still Photography", "category":"Beginners", }, { "id":"1006", "lessonNo":"Lesson 6", "name":"Motion Photograhy", "category":"Beginners", }, { "id":"1007", "lessonNo":"Lesson 7", "name":"Aperture and F-Stops", "category":"Intermiediate", }, { "id":"1008", "lessonNo":"Lesson 8", "name":"Shutter Speeds", "category":"Intermiediate", }, { "id":"1009", "lessonNo":"Lesson 9", "name":"Advanced Framing", "category":"Advanced", }, { "id":"1010", "lessonNo":"Lesson 10", "name":"Advanced Aperture, F-Stops and Shutter Speeds", "category":"Advanced", }, ]
Replies
1
Boosts
1
Views
1k
Activity
May ’23
What is the return/throw state of Publisher.values if there is no error and no values
I'm converting some Combine publishers to async using .values and trying to understand what happens when: A Publisher completes before emitting a value. Here is some example code: let response = client.fetch(query: query) .tryMap { /* map the data, or throw a mapping error if it doesn't map. */ } return Model() } .eraseToAnyPublisher() .values for try await result in response { return result } throw AsyncCombineError.finishedWithoutValue // my custom error What happens with .values if the publisher completes without emitting any values? It returns a type of AsyncThrowingSequence<Self> Will it throw? return? hang? or is this state impossible to happen? Thanks and please enlighten me if I am misunderstanding structured concurrency. This is new to me!
Replies
1
Boosts
0
Views
899
Activity
May ’23
RealityKit - loading multiple usdz models into Entities
I'm new to RealityKit and facing the following issue - I'm trying to load 8 models asynchronously using the following code - cancellable = Entity.loadModelAsync(named: "m1") .append(Entity.loadModelAsync(named: "m2")) .append(Entity.loadModelAsync(named: "m3")) .append(Entity.loadModelAsync(named: "m4")) .append(Entity.loadModelAsync(named: "m5")) .append(Entity.loadModelAsync(named: "m6")) .append(Entity.loadModelAsync(named: "m7")) .append(Entity.loadModelAsync(named:"m8")) .collect() .sink(receiveCompletion: { loadCompletion in if case let .failure(error) = loadCompletion { print("Unable to load model \(error)") } self.cancellable?.cancel() }, receiveValue: { entities in }) //cancellable is an instance property defined as var cancellable:AnyCancellable? The code works as expected. However there is an Xcode issue I'm facing - the editor constantly gets stuck at "Indexing: Processing Files" and subsequently the Build process gets stuck too. This only happens when the number of models in the above chain is more than 3-4. Is there any way to break down the above loading step into smaller parts, without needing to load the models individually (i.e. without .append)?
Replies
0
Boosts
0
Views
1.1k
Activity
Apr ’23
Combine AnyCancellable.store(in:) EXC_BAD_ACCESS
I'm seeing a strange and random crash with my combine networking after updating Xcode to version 14.3 (14E222b) a few days ago. The code below is crashing with EXC_BAD_ACCESS on .store(in:) and wasn't on the previous version of Xcode. private var cancellables = Set<AnyCancellable>() func request() async { URLSession.shared .dataTaskPublisher(for: URL(string: "")!) .map{$0.data} .decode(type: Type.self, decoder: JSONDecoder()) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { print ("Received completion: \($0).") }, receiveValue: { data in print(data) }) .store(in: &cancellables) // <- CRASHING HERE }
Replies
2
Boosts
1
Views
2.6k
Activity
Apr ’23
TableView changes not work correctly in swiftUI
I'm using uikit tableview in swiftui. I get data from WebSocket and I want to update my tableview live. I successfully get data from network and update it in viewModel and pass it to QuotesTableView. The problem is occur in here. TableView not update correctly my data, i.e tableViewData's first value is Symbol1 but it shows Symbol1 data in first indexpath. I debug it in cellForRowAt function and see I get correct data, but not show correct item in cell :( it randomly changes order of data in tableview. but tableviewData order not change. @StateObject private var viewModel = QuotesViewModel() var body: some View { ZStack { Color.init(hex: "#293c54").edgesIgnoringSafeArea(.all) QuotesTableView(tableViewData: $viewModel.list) .background(Color.clear) } } } import Combine class QuotesViewModel: ObservableObject { var cancellables = Set<AnyCancellable>() // MARK: - Input var selectedSymbols: String /// Symbols list @Published var list: [SymbolsInDataModel] = .init() // MARK: - Output // MARK: - Init init() { socket = SocketManager.shared observeSocketValues() bindView() } // MARK: - Business Logic let socket: SocketManager // MARK: - Config } // MARK: - Bind View extension QuotesViewModel { /// observe view actions in here... func bindView() { } } // MARK: - Observation Socket Data extension QuotesViewModel { func observeSocketValues() { socket.$symbolsList.sink(receiveValue: { newSymbols in self.list = newSymbols }) .store(in: &cancellables) socket.$symbolsList .filter { !$0.isEmpty } .first { _ in self.list = self.socket.symbolsList return true } .sink(receiveValue: {_ in}) .store(in: &cancellables) } } struct QuotesTableView: UIViewRepresentable { // The data source for the table view @Binding var tableViewData: [SymbolsInDataModel] var selectClicked: ((_ item: SymbolsInDataModel) -> Void)? func makeUIView(context: Context) -> UITableView { let tableView = UITableView() tableView.translatesAutoresizingMaskIntoConstraints = false tableView.backgroundColor = .clear tableView.dataSource = context.coordinator tableView.showsVerticalScrollIndicator = false tableView.delegate = context.coordinator tableView.register(HostingCell.self, forCellReuseIdentifier: "Cell") return tableView } func updateUIView(_ uiView: UITableView, context: Context) { // Reload the table view data whenever the data changes uiView.reloadData() } func makeCoordinator() -> Coordinator { Coordinator(self) } } // MARK: - CompetitionsTableView -> Coordinator extension QuotesTableView { class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate { var parent: QuotesTableView init(_ tableView: QuotesTableView) { parent = tableView } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { parent.tableViewData.count } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: false) } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! HostingCell tableViewCell.backgroundColor = .clear print("indexpath: \(indexPath.row) item: \(parent.tableViewData[indexPath.row])") // Set the root view of the hosting controller to the view for this cell let row = parent.tableViewData[indexPath.row] let hostingController = UIHostingController( rootView: AnyView( QuotesCellView(item: row, selectAction: self.parent.selectClicked) ) ) hostingController.view.backgroundColor = .clear // create & setup hosting controller only once if tableViewCell.host == nil { tableViewCell.host = hostingController let tableCellViewContent = hostingController.view! tableCellViewContent.translatesAutoresizingMaskIntoConstraints = false tableViewCell.contentView.addSubview(tableCellViewContent) tableCellViewContent.topAnchor.constraint(equalTo: tableViewCell.contentView.topAnchor).isActive = true tableCellViewContent.leftAnchor.constraint(equalTo: tableViewCell.contentView.leftAnchor).isActive = true tableCellViewContent.bottomAnchor.constraint(equalTo: tableViewCell.contentView.bottomAnchor).isActive = true tableCellViewContent.rightAnchor.constraint(equalTo: tableViewCell.contentView.rightAnchor).isActive = true } else { // reused cell, so just set other SwiftUI root view tableViewCell.host = hostingController } tableViewCell.setNeedsLayout() return tableViewCell } } }
Replies
1
Boosts
1
Views
967
Activity
Apr ’23
GraphQL on iOS
Hi, I'm starting to look into GraphQL and how to support it natively on my apps, most tutorials online are about using Apollo, but I rather not introduce third party code at this point. Does someone knows any reference I can use? Thank you
Replies
0
Boosts
0
Views
814
Activity
Mar ’23
Removing cancellable from set crashes app
I have a publisher, pipelinePublisher, which runs a combine pipeline of various operations, some of which send a state update to a statePublisher passed in as an argument. pipelinePublisher gets removed on completion of its Combine pipeline: func myFunction(_ request: MyRequest) -> PassthroughSubject<State, Never> { let statePublisher = PassthroughSubject<State, Never>() let presentationSubject = CurrentValueSubject<MyRequest, Error>(request) var pipelinePublisher: AnyCancellable! pipelinePublisher = presentationSubject .eraseToAnyPublisher() .checkSomething(returningStateTo: statePublisher) // a few more operators here... .sink( receiveCompletion: { [weak self] _ in self?.cancellables.remove(pipelinePublisher) // Crash happens here }, receiveValue: { _ in } ) pipelinePublisher.store(in: &cancellables) return statePublisher .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } However, very occasionally when I call the function multiple times in very quick succession, the app crashes on the line self?.cancellables.remove(pipelinePublisher). This usually brings up one of two possible stack traces. This first is this: 2022-12-21 15:24:51.926131+0000 MyApp[23082:12933690] -[_NSCoreDataTaggedObjectID member:]: unrecognized selector sent to instance 0x8000000000000000 2022-12-21 15:24:51.931941+0000 MyApp[23082:12933690] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSCoreDataTaggedObjectID member:]: unrecognized selector sent to instance 0x8000000000000000' *** First throw call stack: ( 0 CoreFoundation 0x000000018040e7c8 __exceptionPreprocess + 172 1 libobjc.A.dylib 0x0000000180051144 objc_exception_throw + 56 2 CoreFoundation 0x000000018041d47c +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0 3 CoreFoundation 0x00000001804126c8 ___forwarding___ + 1308 4 CoreFoundation 0x0000000180414b4c _CF_forwarding_prep_0 + 92 5 libswiftCore.dylib 0x000000018be6ee68 $sSh8_VariantV6removeyxSgxF + 160 6 MyApp 0x00000001026c6080 $s12MyApp0A0C17myFunctiony7Combine12AnyPublisherVyAA12StateOs5NeverOGAA19MyRequestVFyAE11SubscribersO10CompletionOy_s5Error_pGcfU_ + 440 7 Combine 0x000000019baa2a70 $s7Combine11SubscribersO4SinkC7receive10completionyAC10CompletionOy_q_G_tF + 364 8 Combine 0x000000019baa2f28 $s7Combine11SubscribersO4SinkCy_xq_GAA10SubscriberA2aGP7receive10completionyAC10CompletionOy_7FailureQzG_tFTW + 20 9 Combine 0x000000019bb541cc $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tF + 1516 10 Combine 0x000000019bb55328 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLCy_xq__qd__GAA10SubscriberA2aJP7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tFTW + 20 11 Combine 0x000000019bb53474 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC12receiveInner10completion_yAA11SubscribersO10CompletionOy_7FailureQzG_SitF + 1668 12 Combine 0x000000019bb52de4 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC4SideV7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tF + 20 13 Combine 0x000000019bac45ec $s7Combine6FutureC7Conduit33_3AE68DE9BADC00342FC052FEBC7D3BA6LLC7fulfillyys6ResultOyxq_GF + 1056 14 Combine 0x000000019bac4960 $s7Combine6FutureC7Conduit33_3AE68DE9BADC00342FC052FEBC7D3BA6LLC6finish10completionyAA11SubscribersO10CompletionOy_q_G_tF + 336 15 Combine 0x000000019bac2de4 $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GFyAA11ConduitBaseCyxq_GXEfU0_ + 156 16 Combine 0x000000019bac6b28 $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GFyAA11ConduitBaseCyxq_GXEfU0_TA + 16 17 Combine 0x000000019bae5140 $s7Combine11ConduitListO7forEachyyyAA0B4BaseCyxq_GKXEKF + 212 18 Combine 0x000000019bac2bfc $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GF + 716 19 Combine 0x000000019bac6b08 $s7Combine6FutureCyACyxq_Gyys6ResultOyxq_GcccfcyAGcfU_TA + 20 20 MyApp 0x0000000102541dd8 $s7Combine6FutureC12MyApps5Error_pRs_rlE9operationACyxsAE_pGxyYaKc_tcfcyys6ResultOyxsAE_pGccfU_yyYaYbcfU_TY2_ + 212 21 MyApp 0x0000000102542705 $s7Combine6FutureC12MyApps5Error_pRs_rlE9operationACyxsAE_pGxyYaKc_tcfcyys6ResultOyxsAE_pGccfU_yyYaYbcfU_TATQ0_ + 1 22 MyApp 0x000000010242f1a1 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTQ0_ + 1 23 MyApp 0x000000010242f749 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTA.24TQ0_ + 1 24 libswift_Concurrency.dylib 0x00000001b03bedcd _ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE + 1 ) libc++abi: terminating with uncaught exception of type NSException The second is in the same place but with the error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber member:]: unrecognized selector sent to instance 0x8000000000000000' What is causing this? I've tried making pipelinePublisher optional and having a check that it exists before it gets removed but it does actually exist and still crashes. I can't figure this out, please help!
Replies
0
Boosts
0
Views
1.2k
Activity
Dec ’22