Using MPSession sendResource Progress in a SwiftUI ProgressView causes crash

When transferring files in a Multipeer Session, using the Progress instances (returned by either sendResource in the sender or the delegate method session(didStartReceiving:) on the receiver) in a SwiftUI ProgressView will eventually cause a crash (EXC_BAD_ACCESS in swift_retain on com.apple.MCSession.syncQueue)

I have created a small sample project that demonstrates the problem. It can be found at: https://github.com/eidria/Multipeer-Progress-Demo.git. A screen shot of the stack trace from a crash (crash.jpg) is in the “Images” folder.

STEPS TO REPRODUCE Run the sample on two different hosts connected to the same network (project contains both iOS & macOS targets, bug manifests in any combination). When the second instance comes up, they will automatically find and connect to each other. When the “Send Files” button is enabled, clicking it will cause the sender to repeatedly send the file “Image.HEIC” from the “Images” folder to the receiver, which deletes it upon receipt of a successful transfer (i.e. delegate call back is called with a nil error). Subsequent transfers are triggered when the sender receives notice that the prior send completed successfully. Eventually, after some (usually small) number of files have been transferred, either the sender or receiver will crash in the middle of a transfer, with EXC_BAD_ACCESS in swift_retain on com.apple.MCSession.syncQueue.

Commenting out the ProgressView in the file FileTransferView.swift will allow the apps to run in perpetuity.

Answered by DTS Engineer in 804731022

Hi @navvadassity,

I believe this is the result of a system bug involving either ProgressView (defined as @preconcurrency), Progress (defined as @unchecked Sendable) and Swift Concurrency (e.g., async tasks). Please submit a bug report via Feedback Assistant and respond here with the Feedback ID.

In addition, please ensure your report includes the description above, including the source code for the demo app screenshots and error logs uploaded as attachments.

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

Hi @navvadassity,

I believe this is the result of a system bug involving either ProgressView (defined as @preconcurrency), Progress (defined as @unchecked Sendable) and Swift Concurrency (e.g., async tasks). Please submit a bug report via Feedback Assistant and respond here with the Feedback ID.

In addition, please ensure your report includes the description above, including the source code for the demo app screenshots and error logs uploaded as attachments.

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

Accepted Answer

After some further communication with DTS (Thanks Paris!), a workaround is to use XXViewRepresentable to wrap a platform-specific progress view. Here is my solution:

import SwiftUI

#if os(macOS)
    import AppKit
    public typealias SuperClass = NSViewRepresentable
#else
    import UIKit
    public typealias SuperClass = UIViewRepresentable
#endif

public struct RepresentedProgressView: SuperClass {
    @State public private(set) var progress: Progress

    public init(_ progress: Progress) {
        self.progress = progress
    }

    #if os(macOS)
        public func makeNSView(context: Self.Context) -> NSProgressIndicator {
            let view = NSProgressIndicator()
            view.observedProgress = progress
            return view
        }

        public func updateNSView(_ uiView: Self.NSViewType, context: Self.Context) {

        }
    #else
        public func makeUIView(context: Self.Context) -> UIProgressView {
            let view = UIProgressView()
            view.observedProgress = progress
            return view
        }

        public func updateUIView(_ uiView: Self.UIViewType, context: Self.Context) {

        }
    #endif
}

This is working in our code, and doesn't crash with > 60 files transferred

Using MPSession sendResource Progress in a SwiftUI ProgressView causes crash
 
 
Q