Discuss Swift.

Swift Documentation

Post

Replies

Boosts

Views

Activity

NSTextInputClient concurrency issues in Swift 6
Hello! In our codebase we have a NSView subclass that conforms to NSTextInputClient. This protocol is currently not marked as a main actor, but in the decade this has been in use here it has always been called on the main thread from AppKit. With Swift 6 (or complete concurrency checking in Swift 5) this conformance causes issues since NSView is a main actor but not this protocol. I've tried a few of the usual fixes (MainActor.assumeIsolated or prefixing the protocol conformance with @preconcurrency) but they were not able to resolve all warnings. So I dug in the AppKit headers and found that NSTextInputClient is usually implemented by the view itself, but that that is not a hard requirement (see NSTextInputContext.h the documentation for the client property or here). With that I turned my NSView subclass extension into a separate class that is not a main actor and in my NSView subclass create an instance of it and NSTextInputContext. This all seems to work fine in my initial tests, the delegate methods are called. But when the window loses and then regains key, I see a warning message in the console output. -[TUINSCursorUIController activate:]: Foo.TextInputClient isn't subclass of NSView. So my question is, am I doing it wrong with the custom class that implements the protocol? Or is the warning wrong? I would also appreciate a hint on how to better resolve the concurrency issues with NSTextInputClient. Is a main actor annotation coming at some point from your end? Thanks! Markus
0
0
38
17h
Data storage for a Matrix struct when working with Accelerate
I have a Matrix structure as defined below for working with 2D numerical data in Accelerate. The underlying numerical data in this Matrix struct is stored as an Array. struct Matrix<T> { let rows: Int let columns: Int var data: [T] init(rows: Int, columns: Int, fill: T) { self.rows = rows self.columns = columns self.data = Array(repeating: fill, count: rows * columns) } init(rows: Int, columns: Int, source: (inout UnsafeMutableBufferPointer<T>) -> Void) { self.rows = rows self.columns = columns self.data = Array(unsafeUninitializedCapacity: rows * columns) { buffer, initializedCount in source(&buffer) initializedCount = rows * columns } } subscript(row: Int, column: Int) -> T { get { return self.data[(row * self.columns) + column] } set { self.data[(row * self.columns) + column] = newValue } } } Multiplication is implemented by the functions shown below. import Accelerate infix operator .* func .* (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrices must have same dimensions") let result = Matrix<Double>(rows: lhs.rows, columns: rhs.columns) { buffer in vDSP.multiply(lhs.data, rhs.data, result: &buffer) } return result } func * (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.columns == rhs.rows, "Number of columns in left matrix must equal number of rows in right matrix") var a = lhs.data var b = rhs.data let m = lhs.rows // number of rows in matrices A and C let n = rhs.columns // number of columns in matrices B and C let k = lhs.columns // number of columns in matrix A; number of rows in matrix B let alpha = 1.0 let beta = 0.0 // matrix multiplication where C ← αAB + βC let c = Matrix<Double>(rows: lhs.rows, columns: rhs.columns) { buffer in cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, n, k, alpha, &a, k, &b, n, beta, buffer.baseAddress, n) } return c } I can also define a Matrix structure where the underlying data is an UnsafeMutableBufferPointer. The buffer is handled by the MatrixData class. struct Matrix<T> { let rows: Int let columns: Int var data: MatrixData<T> init(rows: Int, columns: Int, fill: T) { self.rows = rows self.columns = columns self.data = MatrixData(count: rows * columns, fill: fill) } init(rows: Int, columns: Int) { self.rows = rows self.columns = columns self.data = MatrixData(count: rows * columns) } subscript(row: Int, column: Int) -> T { get { return self.data.buffer[(row * self.columns) + column] } set { self.data.buffer[(row * self.columns) + column] = newValue } } } class MatrixData<T> { var buffer: UnsafeMutableBufferPointer<T> var baseAddress: UnsafeMutablePointer<T> { get { self.buffer.baseAddress! } } init(count: Int, fill: T) { let start = UnsafeMutablePointer<T>.allocate(capacity: count) self.buffer = UnsafeMutableBufferPointer(start: start, count: count) self.buffer.initialize(repeating: fill) } init(count: Int) { let start = UnsafeMutablePointer<T>.allocate(capacity: count) self.buffer = UnsafeMutableBufferPointer(start: start, count: count) } deinit { self.buffer.deinitialize() self.buffer.deallocate() } } Multiplication for this approach is implemented by the functions shown here. import Accelerate infix operator .* func .* (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrices must have same dimensions") let result = Matrix<Double>(rows: lhs.rows, columns: lhs.columns) vDSP.multiply(lhs.data.buffer, rhs.data.buffer, result: &result.data.buffer) return result } func * (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.columns == rhs.rows, "Number of columns in left matrix must equal number of rows in right matrix") let a = lhs.data.baseAddress let b = rhs.data.baseAddress let m = lhs.rows // number of rows in matrices A and C let n = rhs.columns // number of columns in matrices B and C let k = lhs.columns // number of columns in matrix A; number of rows in matrix B let alpha = 1.0 let beta = 0.0 // matrix multiplication where C ← αAB + βC let c = Matrix<Double>(rows: lhs.rows, columns: rhs.columns) cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, n, k, alpha, a, k, b, n, beta, c.data.baseAddress, n) return c } Both of these approaches give me similar performance. The only difference that I have noticed is the matrix buffer approach allows for reference semantics. For example, the code below uses half the memory with the matrix buffer approach compared to the matrix array approach. This is because b acts as a reference to a using the matrix buffer approach; otherwise, the matrix array approach makes a full copy of a. let n = 10_000 let a = Matrix<Double>(rows: n, columns: n, fill: 0) var b = a b[0, 0] = 99 b[0, 1] = 22 Other than reference semantics, are there any reasons to use one of these approaches over the other?
2
0
83
23h
Appending an item to an optional array within a struct
Hello All, some background information first. I have the following struct: Struct Category: Identifiable, Codeable, Hashable { var id: UUID var name: String var subCategory: [Category]? } var categories: [Category] There is no limit how many levels deep the subcategory can be. The user is essentially creating a hierarchical data filing system. Given that the number of subCategory levels is unlimited, I am recursing over the subcategories to find the correct level at which to insert the newCategory. The recursive function to add category is declared as: func recursiveAddCategory(newCategory: Category, subCategoryOf: inout [Category]?) you will note that I am trying to pass the subCategory as a reference (using inout), so that I can add to the original and the function is called as recursiveAddCategory(newCategory, &categories.subCategory!) the actual append statement within the recursiveAddCategory function is: categories.subCategory?.append(newCategory) I am encountering no errors but also find that the newCategory is not being added to the categories array. Any help or guidance appreciated. Thanks
1
0
63
1w
Main actor-isolated property can not be reference from a Sendable closure
I am working thru the issues of turning on Strict Concurrency Checking. I have a SwiftData application, and I am compressing images before saving them as data. My save function is pretty simple private func save() { ImageCompressor.compress(image: (frontImageSelected?.asUIImage())!, maxByte: 1_048_576) { image in guard image != nil else { print("Error compressing image") return } if let greetingCard { greetingCard.cardName = cardName greetingCard.cardFront = image?.pngData() greetingCard.cardManufacturer = cardManufacturer greetingCard.cardURL = cardURL greetingCard.eventType = eventType } else { let newGreetingCard = GreetingCard(cardName: cardName, cardFront: image?.pngData(), eventType: eventType, cardManufacturer: cardManufacturer, cardURL: cardURL) modelContext.insert(newGreetingCard) } } } I compress the selected image, I had to change my ImageCompressor.compress closure to Sendable, but now every assignment above is flagging with the above warning. I define the greetingCard as var greetingCard: GreetingCard? in my view, since I can have it passed in for edit, or generated if new. I also get the same warning on modelContext, which is defined as @Environment(\.modelContext) private var modelContext. It's not clear to me how to address this warning. Any pointers would be helpful.
1
0
127
1w
Offloading task from the cooperative thread pool
Hi, When using Swift Concurrency blocking tasks like file I/O, GPU work and networking can prevent forward moving progress and have the potential to exhaust the cooperative thread pool and under utilize the CPU. It's been recommended to offload these tasks from the cooperative thread pool. Is my understanding correct that the preferred way to do this is by creating async tasks via Dispatch or OperationQueue? And combining these with Continuations if a return value from the task is required? Or should I always be using Continuations in combination with Dispatch/OperationQueue? There are also Executors but the documentation seems a bit limited on how to use these. The new TaskExecutor is also only available on the latest beta's. My question is basically what is the recommend way to offload a task? Thanks!
0
0
98
1w
Action Will Not Run The Second Time Method is called
In my method moveSun() it successfully rotates and plays the sound the first time it is called. However, subsequent calls to the method only play the sound and do not execute the rotate action. Does anyone know what may be causing this? Here's the relevant code: func moveSun() { print(sunMoving) let rotateAction = SKAction.rotate(toAngle: 2 * CGFloat.pi, duration: 2) let playGearSound = SKAction.playSoundFileNamed("spinningGear", waitForCompletion: true) let rotateAndPlayGearSound = SKAction.group([rotateAction, playGearSound]) sun.run(rotateAndPlayGearSound, completion: { self.sunMoving = false; print("completed completion handler") }) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchDown(atPoint: t.location(in: self)) } } func touchDown(atPoint pos : CGPoint) { let touchedNodes = nodes(at: pos) for touchedNode in touchedNodes { print("touchNode: \(String(describing: touchedNode.name))") if touchedNode.name == "sun" && !sunMoving { sunMoving = true moveSun() } } }
1
0
101
1w
How to avoid Swift 6 concurrency warning from UIAccessibility.post()
I have the following var in an @Observable class: var displayResult: String { if let currentResult = currentResult, let decimalResult = Decimal(string: currentResult) { let result = decimalResult.formatForDisplay() UIAccessibility.post(notification: .announcement, argument: "Current result \(result)") return result } else { return "0" } } The UIAccessiblity.post gives me this warning: Reference to static property 'announcement' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6 How can I avoid this?
3
0
197
1w
Fix actor-isolated class is different from nonisolated subclass error
I'm trying to migrate my fairly large application to Swift Concurrency. I've have a class marked as @MainActor that sub-classes a 3rd party abstract class that is not migrated to Swift Concurrency. I get the following error: Main actor-isolated class 'MyClass' has different actor isolation from nonisolated superclass 'OtherAbstractClass'; this is an error in the Swift 6 language mode My class needs to be MainActor as it uses other code that is required to be on the MainActor. I can't see how to suppress this warning, I know as a guarantee that the abstract class will always be on the main thread so I need a way of telling the compiler that when I don't own the 3rd party code. import OtherAbstractModule @MainActor class MyClass: OtherAbstractClass { .... } How can I satisfy the compiler in this case?
1
0
207
1w
Approach to adoption of Swift Testing
Currently Swift Testing has much less features than XCTest, so the adoption will be very slow from our side. Notable features we miss are UI tests, performance tests and attachments. I did not want to create many issues in Swift Testing GitHub project as lots of these shortcoming are most probably tracked internally (I can see lots of references to radars in GitHub issues.) So, my question is: Is it a good idea to wait with wider adoption or should we experiment with other tools like swift Benchmarks?
3
0
228
1w
The DateFormatter is returning wrong date format 2024-04-23T7:52:49.352 AMZ, 2024-05-23T11:16:24.706 a.m.Z
import Foundation let formatter = DateFormatter() let displayLocalFormat = true or false let timeZone = UTC let dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" let currentDate = Date() formatter.locale = displayLocalFormat ? Locale.current : Locale(identifier: "en_US_POSIX") formatter.dateFormat = dateFormat formatter.timeZone = timeZone formatter.string(from: date) // This function returns date format 2024-05-23T11:16:24.706 a.m.Z
6
0
228
1w
HCE iOS, get default payment app
Hello, I develop an HCE payment app. In this app I can redirect users in Settings to set the default payment app UIApplication.shared.open(URL(string: "App-prefs:General&path=CONTACTLESS_NFC") But is it possible to know which app is selected or if my app is already set as default ?
1
0
161
2w
representation error in swift generated header
I have a public swift function with the below declaration : public func InternalMain (_ pNumOfArgs : Int32, _ pCmdlineArgs : UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>) -> Int32 {..} I need this function as public because I need to invoke in from a different library. But the above declaration produces an error in my generated swift header i.e '-swift.h' file because 'UnsafeMutablePointer<UnsafeMutablePointer?>' type cannot be represented in the swift generated header. Can someone help how do I get past this. This is a class independent function and I tried using the '@nonobj' to prevent this from getting in the generated header but it still gives an error.
2
0
290
2w
NSString.getBytes does not crash even when an invalid range is passed.
When we pass some special words, NSString.getBytes does not crash even when we pass an invalid range. It seems a bug. The below code is an example. func testNSStringGetBytes() { let originalString: String = "􁜁あ" let bufferSize = 256 var buffer = [UInt8](repeating: 0, count: bufferSize) var usedLength = 0 // An invalid range is passed let range = NSRange(location: 0, length: originalString.count + 1) var remainingRange = NSRange() (originalString as NSString) .getBytes( &buffer, maxLength: bufferSize, usedLength: &usedLength, encoding: String.Encoding.utf8.rawValue, options: [], range: range, remaining: &remainingRange ) print("Used Length: \(usedLength)") print("Buffer: \(buffer[0..<usedLength])") if remainingRange.length > 0 { print("Did not convert the whole string. Remaining range: \(remainingRange)") } else { print("Entire string was converted successfully.") } }
1
0
210
2w
loaded array from plist. call using AppDelegate() returns empty array.
In app delegate I'm trying to load an array with strings from a plist. I print the plist it prints fine... func loadTypesArray() { guard let path = Bundle.main.path(forResource: "Types", ofType: "plist") else {return} let url = URL(fileURLWithPath: path) let data = try! Data(contentsOf: url) guard let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil) as? [String] else {return} print(plist) typesArray = plist // print(typesArray) } But when I try and access it from a different part of the app using let typesArray = AppDelegate().typesArray the array I get is an empty array! any help?
2
0
279
2w
Archiving my macOS target app fails with BOOL error
I'm building a macOS target for my App (which also has some Obj-C code). Building and running the app is fine but when I archive the app in XCode, the process / build fails with the following error Type 'BOOL' (aka ;Int32') cannot be used as a boolean;test for '!=0' instead It happens in a couple of places, one of the places being private func getRootDirectory(createIfNotExists: Bool = true) throws -> URL { return try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) } where it complains that create: true is not acceptable and throws the above error. If I comment out this line, the archive works successfully. When i Cmd + click the definition of Filemanager.default.url , i get this @available(macOS 10.6, *) open func url(for directory: FileManager.SearchPathDirectory, in domain: FileManager.SearchPathDomainMask, appropriateFor url: URL?, create shouldCreate: BOOL) throws -> URL This looks fishy since it it says create shouldCreate: BOOL whereas the documentation says it should be just Bool func url( for directory: FileManager.SearchPathDirectory, in domain: FileManager.SearchPathDomainMask, appropriateFor url: URL?, create shouldCreate: Bool ) throws -> URL My minimum deployment target is macOS 13.0 I'm quite stumped at this error - which happens only while archiving. Does anybody know why?
4
0
288
3w
Files App Share Context with Security scoped resource fails
I'm creating an App that can accepted PDFs from a shared context. I am using iOS, Swift, and UIKit with IOS 17.1+ The logic is: get the context see who is sending in (this is always unknown) see if I can open in place (in case I want to save later) send the URL off to open the (PDF) document and load it into PDFKit's pdfView.document I have no trouble loading PDF docs with the file picker. And everything works as expected for shares from apps like Messages, email, etc... (in which case URLContexts.first.options.openInPlace == False) The problem is with opening (sharing) a PDF that is sent from the Files App. (openInPlace == True) If the PDF is in the App's Document Folder, I need the Security scoped resource, to access the URL from the File's App so that I can copy the PDF's data to the PDFViewer.document. I get Security scoped resource access granted each time I get the File App's context URL. But, when I call fileCoordinator.coordinate and try to access a file outside of the App's document folder using the newUrl, I get an error. FYI - The newUrl (byAccessor) and context url (readingItemAt) paths are always same for the Files App URL share context. I can, however, copy the file to a new location in my apps directory and then open it from there and load in the data. But I really do not want to do that. . . . . . Questions: Am I missing something in my pList or are there other parameters specific to sharing a file from the Files App? I'd appreciate if someone shed some light on this? . . . . . Here are the parts of my code related to this with some print statements... . . . . . SceneDelegate func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { // nothing to see here, move along guard let urlContext = URLContexts.first else { print("No URLContext found") return } // let's get the URL (it will be a PDF) let url = urlContext.url let openInPlace = urlContext.options.openInPlace let bundleID = urlContext.options.sourceApplication print("Triggered with URL: \(url)") print("Can Open In Place?: \(openInPlace)") print("For Bundle ID: \(bundleID ?? "None")") // get my Root ViewController from window if let rootViewController = self.window?.rootViewController { // currently using just the view if let targetViewController = rootViewController as? ViewController { targetViewController.prepareToLoadSharedPDFDocument(at: url) } // I might use a UINavigationController in the future else if let navigationController = rootViewController as? UINavigationController, let targetViewController = navigationController.viewControllers.first as? ViewController { targetViewController.prepareToLoadSharedPDFDocument(at: url) } } } . . . . ViewController function I broke out the if statement for accessingScope just to make it easier for me the debug and play around with the code in accessingScope == True func loadPDF(fromUrl url: URL) { // If using the File Picker / don't use this // If going through a Share.... we pass the URL and have three outcomes (1, 2a, 2b) // 1. Security scoped resource access NOT needed if from a Share Like Messages or EMail // 2. Security scoped resource access granted/needed from 'Files' App // a. success if in the App's doc directory // b. fail if NOT in the App's doc directory // Set the securty scope variable var accessingScope = false // Log the URLs for debugging print("URL String: \(url.absoluteString)") print("URL Path: \(url.path())") // Check if the URL requires security scoped resource access if url.startAccessingSecurityScopedResource() { accessingScope = true print("Security scoped resource access granted.") } else { print("Security scoped resource access denied or not needed.") } // Stop accessing the scope once everything is compeleted defer { if accessingScope { url.stopAccessingSecurityScopedResource() print("Security scoped resource access stopped.") } } // Make sure the file is still there (it should be in this case) guard FileManager.default.fileExists(atPath: url.path) else { print("File does not exist at URL: \(url)") return } // Let's see if we can open it in place if accessingScope { let fileCoordinator = NSFileCoordinator() var error: NSError? fileCoordinator.coordinate(readingItemAt: url, options: [], error: &error) { (newUrl) in DispatchQueue.main.async { print(url.path()) print(newUrl.path()) if let document = PDFDocument(url: newUrl) { self.pdfView.document = document self.documentFileName = newUrl.deletingPathExtension().lastPathComponent self.fileLoadLocation = newUrl.path() self.updateGUI(pdfLoaded: true) self.setPDFScale(to: self.VM.pdfPageScale, asNewPDF: true) } else { print("Could not load PDF directly from url: \(newUrl)") } } } if let error = error { PRINT("File coordination error: \(error)") } } else { DispatchQueue.main.async { if let document = PDFDocument(url: url) { self.pdfView.document = document self.documentFileName = url.deletingPathExtension().lastPathComponent self.fileLoadLocation = url.path() self.updateGUI(pdfLoaded: true) self.setPDFScale(to: self.VM.pdfPageScale, asNewPDF: true) } else { PRINT("Could not load PDF from url: \(url)") } } } } . . . . Other relevant pList settings I've added are: Supports opening documents in place - YES Document types - PDFs (com.adobe.pdf) UIDocumentBrowserRecentDocumentContentTypes - com.adobe.pdf Application supports iTunes file sharing - YES And iCloud is one for Entitlements with iCloud Container Identifiers Ubiquity Container Identifiers . . . . Thank you in advance!. B
1
0
269
3w