Post

Replies

Boosts

Views

Activity

Handle multiple AsyncThrowingStreams in structured concurrency?
Hello, im currently rewriting my entire network stuff to swift concurrency. I have a Swift Package which contains the NWConnection with my custom framing protocol. So Network framework does not support itself concurrency so I build an api around that. To receive messages I used an AsyncThrowingStream and it works like that: let connection = MyNetworkFramework(host: "example.org") Task { await connection.start() for try await result in connection.receive() { // do something with result } } that's pretty neat and I like it a lot but now things got tricky. in my application I have up to 10 different tcp streams I open up to handle connection stuff. so with my api change every tcp connection runs in it's own task like above and I have no idea how to handle the possible errors from the .receive() func inside the tasks. First my idea was to use a ThrowingTaskGroup for that and I think that will work but biggest problem is that I initially start with let's say 4 tcp connections and I need the ability to add additional ones later if I need them. so it seems not possible to add a Task afterwards to the ThrowingTaskGroup. So what's a good way to handle a case like that? i have an actor which handles everything in it's isolated context and basically I just need let the start func throw if any of the Tasks throw I open up. Here is a basic sample of how it's structured. Thanks Vinz internal actor MultiConnector { internal var count: Int { connections.count } private var connections: [ConnectionsModel] = [] private let host: String private let port: UInt16 private let parameters: NWParameters internal init(host: String, port: UInt16, parameters: NWParameters) { self.host = host self.port = port self.parameters = parameters } internal func start(count: Int) async throws -> Void { guard connections.isEmpty else { return } guard count > .zero else { return } try await sockets(from: count) } internal func cancel() -> Void { guard !connections.isEmpty else { return } for connection in connections { connection.connection.cancel() } connections.removeAll() } internal func sockets(from count: Int) async throws -> Void { while connections.count < count { try await connect() } } } // MARK: - Private API - private extension MultiConnector { private func connect() async throws -> Void { let uuid = UUID(), connection = MyNetworkFramework(host: host, port: port, parameters: parameters) connections.append(.init(id: uuid, connection: connection)) let task = Task { [weak self] in guard let self else { return }; try await stream(connection: connection, id: uuid) } try await connection.start(); await connection.send(message: "Sample Message") // try await task.value <-- this does not work because stream runs infinite until i cancel it (that's expected and intended but it need to handle if the stream throws an error) } private func stream(connection: MyNetworkFramework, id: UUID) async throws -> Void { for try await result in connection.receive() { if case .message(_) = result { await connection.send(message: "Sample Message") } // ... more to handle } } }
3
0
888
Mar ’24
MapKit in List Breaks Top/Bottom Bar FadeIn/Out Effect
I've encountered a weird issue with the new Map for iOS 17. In my list, which includes a MapView among other elements, I've observed that with the new initializer, the top and bottom bars are persistently displayed. They don't hide and only appear when scrolling, as they should. This problem doesn't occur with the old, now-deprecated initializer. To illustrate this, I have two screenshots: one with the map enabled and the other with the map disabled, demonstrating the issue. Here is also my new Map code: struct MapListRowView: View { @Binding internal var location: LocationModel @State internal var user: Bool = true private var position: CLLocationCoordinate2D { .init(latitude: location.latitude, longitude: location.longitude) } private var isPad: Bool { UIDevice.current.userInterfaceIdiom == .pad ? true : false } var body: some View { Map(bounds: .init(minimumDistance: 1250)) { if user { UserAnnotation() } Annotation("", coordinate: position) { ZStack { Circle().fill().foregroundColor(.white).padding(1) Image(systemName: "mappin.circle.fill") .resizable() .foregroundColor(.indigo) }.frame(width: 20, height: 20).opacity(user ? .zero : 1.0) } } .frame(height: isPad ? 200 : 100) .cornerRadius(8) .listRowInsets(.init(top: -5, leading: .zero, bottom: -5, trailing: .zero)) .padding(.vertical, 5) .disabled(true) } }
1
0
472
Nov ’23
Network.framework Performance issues in Downstream since Sonoma Update
I have built an application to measure network throughput using Network.framework. Since the Sonoma Update, I've encountered some strange performance issues with this framework. I use the Loopback Channel by running the server on my Mac itself, which is written in Golang. Before the update, performance was not an issue. After the update, however, the throughput fluctuates significantly. I started to investigate, I use the following function to parse the data: connection.receive(minimumIncompleteLength: 1, maximumLength: 32768) { // My frame parsing code } When I use a higher maximumLength, for example, 65536 bytes, it starts to fluctuate, and the received message size for parsing varies between 2.6 Mbytes and 7 Mbytes. However, if the maximumLength is 32768 or lower, and the message size is smaller or larger than this range, then the performance is as expected. To further isolate the issue, I forced the server to just send messages and removed my frame parsing code, ensuring that the problem is not related to this. This behavior is very peculiar, and I'm unsure how to fix it. Are there others who have experienced similar performance problems? It's worth noting that this issue occurs only with downstream performance, not with upstream.
1
0
702
Oct ’23
Swift Charts real time update LineMark is slow
Hello I'm currently working on a new gui in my App and I wanted to use the new Swift Charts Framework. It's very beautiful but I'm struggling with performance here. I want to draw a LineMark in realtime. I have code that create me a point every 25ms over a runtime of about 10 seconds. So I have round about 400 Samples which should drawn in realtime to the Chart so I can see the LineMark being drawn. On a first try I used a Binding to the Chart to update the Chart and after 2-3 seconds the ui becomes unresponsive and started lagging. I'm currently using an ObservableObject and the .drawingGroup modifier to improve the Performance. This Helps but it's not perfect. Is there a better way to increase the Performance or what's the way to have a realtime drawing line graph? Here's the Code I use: struct ChartView: View { @ObservedObject public var model = FNMeasurementModel() private let gradient = LinearGradient(gradient: Gradient (colors: [.mint.opacity(0.1),.mint.opacity(0.0)]), startPoint: .top, endPoint: .bottom) var body: some View { Chart() { ForEach(model.data) { item in LineMark( x: .value("Ratio", item.ratio ?? .zero), y: .value("Speed", item.speed ?? .zero) ) .interpolationMethod(.catmullRom) .foregroundStyle(.mint) AreaMark( x: .value("Ratio", item.ratio ?? .zero), y: .value("Speed", item.speed ?? .zero) ) .foregroundStyle(gradient) } } .chartXAxis{ AxisMarks(position: .bottom, values: stride(from: 0, to: 1.0, by: 0.2).map { $0 }) } .chartXScale(domain: 0...1.0) .chartYScale(domain: 0...100) .frame(height: 100) .padding(.vertical, 5) } } The ObservableObject class FNMeasurementModel: ObservableObject { @Published public var data: [FNMeasurementResult] = [] func append(_ sample: FNMeasurementResult) -> Void { data.append(sample) } func reset() -> Void { data.removeAll() } } My Result Type public class FNMeasurementResult: Identifiable { public var id: UUID = UUID() public var ratio: Double? public var speed: Double? public init(speed: Double? = nil, ratio: Double? = nil) { self.ratio = ratio self.speed = speed } }
1
0
2.0k
Apr ’23
NWBrowser scan for arbitrary Bonjour Services with Multicast Entitlement ?!
Dear Girls, Guys and Engineers. I'm currently building a Home Network Scanner App for People which want to know which Bonjour Devices are in her/his Home Network environment. From an older Question I got the answer, that I need an Entitlement to do this. I started to work on the App and requested the Multicast Entitlement from Apple. They gave me the Entitlement for my App and now I'm trying to discover all devices in my Home Network but I got stuck and need Help. I only test direct on device, like the recommendation. I also verified that my app is build with the multicast entitlement there where no problems. My problem is now, that is still not possible to discover all Bonjour services in my Home Network with the Help of the NWBrowser. Can you please help me to make it work ? I tried to scan for the generic service type: let browser = NWBrowser(for: .bonjour(type: "_services._dns-sd._udp.", domain: nil), using: .init()) but this is still not working even tough I have the entitlement and the app was verified that the entitlement is correctly enabled if I scan for this service type, I got the following error: [browser] nw_browser_fail_on_dns_error_locked [B1] Invalid meta query type specified. nw_browser_start_dns_browser_locked failed: BadParam(-65540) So what's the correct way now to find all devices in the home network ? Thank you and best regards Vinz
4
0
1.9k
Jun ’21
NWConnection not establishing WebSocket Connection, Why ?!
Hi Guy's I have trouble creating a WebSocket based Connection by using direct Network.framework's NWConnection. And I don't want to use URLSessions Way! I Watched the Apple Keynote and it's not working for me. I'm trying to connect to a public WebSocket Echo Server. I put the code in a simple playground. Maybe some of you can light me up and explain what is wrong here 'cause i'm not seeing any issue ?! Thanks and best regards Vinz import UIKit import Network import PlaygroundSupport let parameters = NWParameters.tls let options = NWProtocolWebSocket.Options() parameters.defaultProtocolStack.applicationProtocols.insert(options, at: 0) let connection = NWConnection(host: .init("wss://echo.websocket.org/"), port: .https, using: parameters) connection.stateUpdateHandler = { state in     switch state {     case .ready:         print("connection ready")     case .failed(let error):         print("connection failed with:", error)     default:         break     } } print("start") connection.start(queue: .main) PlaygroundPage.current.needsIndefiniteExecution = true
1
0
1.9k
Feb ’21
Xcode 11 XCFramework "... is not a member type of ..." error
Hi Guys,i tried with the final Xcode 11 Version to generate a .xcframework from my framework but it will not work. I successfully generated the .xcframework like apple showed us on WWDC. But when i import the framework in a sample projekt, it throws the error: "Failed to load module ..." if i try to import it. And there are lot of errors from "arm64-apple-ios.swiftinterface". It's the same error for all public protocols, enums, structs-> "... is not a member type of..."This is the interface file where the errors appear and for every FastSocket.Struct, FastSocket.Protocol.. -> for example: "MessageProtocol is not a member type of FastSocket". I dont have any idea why this happen 😟. The Things are all public and the module works like expected. but not as xcframework 😟// swift-interface-format-version: 1.0 // swift-compiler-version: Apple Swift version 5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7) // swift-module-flags: -target arm64-apple-ios13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FastSocket import CryptoKit import Foundation import Network import Swift extension Data : FastSocket.MessageProtocol { } public protocol FastSocketProtocol : AnyObject { var on: FastSocket.FastSocketCallback { get set } var parameters: FastSocket.TransferParameters { get set } init(host: Swift.String, port: Swift.UInt16, type: FastSocket.TransferType) func connect() func disconnect() func send<T>(message: T) where T : FastSocket.MessageProtocol } public struct FastSocketCallback { public var ready: () -> Swift.Void public var close: () -> Swift.Void public var message: (FastSocket.MessageProtocol) -> Swift.Void public var bytes: (FastSocket.ByteCountResult) -> Swift.Void public var error: (Swift.Error?) -> Swift.Void } public protocol MessageTypeProtocol { } public protocol MessageProtocol { } public enum ByteCountResult { case input(Swift.Int) case output(Swift.Int) } extension String : FastSocket.MessageProtocol { } public enum TransferType { case tcp case tls public static func == (a: FastSocket.TransferType, b: FastSocket.TransferType) -> Swift.Bool public var hashValue: Swift.Int { get } public func hash(into hasher: inout Swift.Hasher) } public class FastSocket : FastSocket.FastSocketProtocol { public var on: FastSocket.FastSocketCallback public var parameters: FastSocket.TransferParameters required public init(host: Swift.String, port: Swift.UInt16, type: FastSocket.TransferType = .tcp) public func connect() public func disconnect() public func send<T>(message: T) where T : FastSocket.MessageProtocol @objc deinit } public struct TransferParameters { public var acceptLocalOnly: Swift.Bool public var allowFastOpen: Swift.Bool public var preferNoProxies: Swift.Bool public var prohibitedInterfaceTypes: [Network.NWInterface.InterfaceType] public var prohibitExpensivePaths: Swift.Bool public var requiredInterfaceType: Network.NWInterface.InterfaceType public var serviceClass: Network.NWParameters.ServiceClass public var multipathServiceType: Network.NWParameters.MultipathServiceType } public enum FastSocketError : Swift.Int, Swift.Error { case none case emptyHost case handshakeInitializationFailed case handshakeVerificationFailed case timeoutError case networkUnreachable case sendFailed case sendToEarly case socketClosed case socketUnexpectedClosed case writeBeforeClear case parsingFailure case zeroData case readBufferIssue case readBufferOverflow case writeBufferOverflow case unknownOpcode public typealias RawValue = Swift.Int public init?(rawValue: Swift.Int) public var rawValue: Swift.Int { get } } extension FastSocketError { public static var errorDomain: Swift.String { get } public var errorCode: Swift.Int { get } public var errorUserInfo: [Swift.String : Swift.String] { get } } extension FastSocket.TransferType : Swift.Equatable {} extension FastSocket.TransferType : Swift.Hashable {} extension FastSocket.FastSocketError : Swift.Equatable {} extension FastSocket.FastSocketError : Swift.Hashable {} extension FastSocket.FastSocketError : Swift.RawRepresentable {}i generated it with the following commands and i also set the Build Library for Distribution to Yesxcodebuild archive -scheme FastSocket -destination generic/platform=iOS -archivePath ./FastSocket.xcarchive SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YESxcodebuild -create-xcframework -framework FastSocket.xcarchive/Products/Library/Frameworks/FastSocket.framework -output FastSocket.xcframework
5
1
12k
Sep ’19
NWBrowser find all mDNS Services ?
Hello,i want to find all open mDNS services with the new NWBrowser. With the NetServiceBrowser i got all Services by searching for this type: "_services._dns-sd._udp." but with the NWBrowser i dont get anything. if i search for a specific type like http or companion link i find some devices. How can i get all services with the NWBrowser ? Or is this not possible due to new data collection guidelines ? I tried it in a Playgroundimport Network let parameter = NWParameters() parameter.includePeerToPeer = true let browser = NWBrowser(for: .bonjour(type: "_services._dns-sd._udp.", domain: nil), using: parameter) browser.stateUpdateHandler = { state in switch state { case .ready: print("ready") case .failed(let error): print("error:", error.localizedDescription) default: break } } browser.browseResultsChangedHandler = { result, changed in result.forEach { device in print(device.endpoint) print(device.metadata) } } browser.start(queue: .main) PlaygroundPage.current.needsIndefiniteExecution = true
6
0
5.1k
Jun ’19