Post

Replies

Boosts

Views

Activity

How to drag custom items in SwiftUI on macOS
How can we drag views coupled to an NSItemProvider with a custom typeIdentifier or UTI ? I know you can use the following methods in conjunction with predefined UTI types (like kUTTypeText etc.): onDrag(_: () -> NSItemProvider) -> some View - https://developer.apple.com/documentation/swiftui/view/3289004-ondrag onDrop(of: [String], isTargeted: Binding<Bool>?, perform action: ([NSItemProvider]) -> Bool) -> some View - https://developer.apple.com/documentation/swiftui/view/3289007-ondrop But what if I want to use an itemProvider with a custom UTI? I tried: import SwiftUI struct ContentView: View { static let type = "com.devian.sampleapp.customstring.dragdroptype" @State var dropZoneIsHovered = false var body: some View { VStack { Text("Hello") .padding() .onDrag(createItem) Text("Dropzone") .padding() .background(dropZoneIsHovered ? Color.gray : nil) .onDrop( of: [ContentView.type], isTargeted: $dropZoneIsHovered, perform: acceptDrop(items:) ) }.padding()     } func createItem() -> NSItemProvider { NSItemProvider( item: "Hello" as NSString, typeIdentifier: ContentView.type ) } func acceptDrop(items: [NSItemProvider]) -> Bool { print("Hurray we received a custom item") return true } } But the dropzone does not accept custom UTI's I also tried to export the custom UTI using Info.plist: <array> <dict> <key>UTTypeConformsTo</key> <array> <string>public.data</string> </array> <key>UTTypeIdentifier</key> <string>com.devian.sampleapp.customstring.dragdroptype</string> <key>UTTypeTagSpecification</key> <dict/> </dict> </array> But that did not work either. Then I tried to add it as a document type in Info.plist <array> <dict> <key>CFBundleTypeRole</key> <string>None</string> <key>LSItemContentTypes</key> <array> <string>com.devian.sampleapp.customstring.dragdroptype</string> </array> <key>LSTypeIsPackage</key> <integer>0</integer> </dict> </array> Nothing of the above works on macOS. What am I doing wrong?
1
1
2.1k
Jun ’21
How to write a NWProtocolFramer for Network.framework that splits streams into frames using a delimiter?
I tried to create a framer that splits a stream of ASCII bytes into frames separated by the pipe ascii character: "|". So I made an NWProtocolFramerImplementation as seen in the attached document. Framer Implementation.swift - https://developer.apple.com/forums/content/attachment/fd158172-dcf3-4a00-9e66-fac477ab3c23 The problem is that from the moment I get a chunk that does not end with "|", the framer gets stuck on that chunk. So the other chunks that come after this incomplete chunk never fully arrive in the framer.parseInput(...) call. Because it always parses chunks of minimumIncompleteLength and hence never arrives to the point where the next "|" is. Here is a simple reproduction of this problem: Create a TCP server Setup the server so that it sends chunks of messages when a client connects. Connect to the server (created in 1.) using the framer from above. Start receiving messages. import Network let client = DispatchQueue(label: "Server") let server = DispatchQueue(label: "Client") let networkParameters = NWParameters.tcp networkParameters.defaultProtocolStack.applicationProtocols.insert(NWProtocolFramer.Options(definition: PipeFramer.definition), at: 0) let server = try! NWListener(using: .tcp) server.newConnectionHandler = { connection in &#9;&#9;print("server: new connection from", connection.endpoint) &#9;&#9;print("server (client \(connection.endpoint)): state", connection.state) &#9;&#9;connection.viabilityUpdateHandler = { viable in &#9;&#9;&#9;&#9;print("server (client \(connection.endpoint)): state", connection.state) &#9;&#9;&#9;&#9;if viable { &#9;&#9;&#9;&#9;&#9;&#9;print("server: sending") &#9;&#9;&#9;&#9;&#9;&#9;connection.send(content: "A|Be||Sea".data(using: .utf8)!, isComplete: false, completion: .idempotent) &#9;&#9;&#9;&#9;&#9;&#9;serverQueue.asyncAfter(deadline: .now() + 5) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;print("server: sending second part") &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;connection.send(content: " is longer than expected|0|".data(using: .utf8)!, isComplete: true, completion: .idempotent) &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;serverQueue.asyncAfter(deadline: .now() + 8) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;print("server: sending last part") &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;connection.send(content: "Done|".data(using: .utf8)!, isComplete: true, completion: .idempotent) &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;} &#9;&#9;connection.start(queue: serverQueue) } server.stateUpdateHandler = { state in &#9;&#9;print("server:", state) &#9;&#9;if state == .ready, let port = server.port { &#9;&#9;&#9;&#9;print("server: listening on", port) &#9;&#9;} } server.start(queue: serverQueue) let client = NWConnection(to: .hostPort(host: "localhost", port: server.port!), using: networkParameters) func receiveNext() { &#9;&#9;client.receiveMessage { (data, context, complete, error) in &#9;&#9;&#9;&#9;let content: String &#9;&#9;&#9;&#9;if let data = data { &#9;&#9;&#9;&#9;&#9;&#9;content = String(data: data, encoding: .utf8) ?? data.description &#9;&#9;&#9;&#9;} else { &#9;&#9;&#9;&#9;&#9;&#9;content = data?.debugDescription ?? "<no data>" &#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;print("client: received \"\(content)\"", context.debugDescription, complete, error?.localizedDescription ?? "No error") &#9;&#9;&#9;&#9;receiveNext() &#9;&#9;} } client.stateUpdateHandler = { state in &#9;&#9;print("client:", state) &#9;&#9;if state == .ready { &#9;&#9;&#9;&#9;print("client: receiving") &#9;&#9;&#9;&#9;receiveNext() &#9;&#9;} } client.start(queue: clientQueue) Results in: server: waiting(POSIXErrorCode: Network is down) server: ready server: listening on 54894 client: preparing client: ready client: receiving server: new connection from ::1.53179 server (client ::1.53179): state setup server (client ::1.53179): state ready server: sending client: parsing buffer: "A|Be||Sea" client: minLength set to 1 client: parsing buffer: "Be||Sea" client: minLength set to 1 client: parsing buffer: "|Sea" client: minLength set to 1 client: parsing buffer: "Sea" client: minLength set to 4 client: parsing buffer: "" client: minLength set to 1 client: received "A" Optional(Network.NWConnection.ContentContext) true No error client: received "Be" Optional(Network.NWConnection.ContentContext) true No error client: received "<no data>" Optional(Network.NWConnection.ContentContext) true No error client: parsing buffer: "Sea" client: minLength set to 4 server: sending second part client: parsing buffer: "Sea " client: minLength set to 5 client: parsing buffer: "Sea i" client: minLength set to 6 server: sending last part client: parsing buffer: "Sea is" client: minLength set to 7 client: parsing buffer: "Sea is " client: minLength set to 8 Notice that the fourth and fifth message are never received by the client. How should I write the Framer so that it receives messages after an incoming incomplete chunk?
4
0
2k
Jul ’21