Swift is a powerful and intuitive programming language for Apple platforms and beyond.

Posts under Swift tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

ARKit delegate code broken by Swift 6
I'm porting over some code that uses ARKit to Swift 6 (with Complete Strict Concurrency Checking enabled). Some methods on ARSCNViewDelegate, namely Coordinator.renderer(_:didAdd:for:) among at least one other is causing a consistent crash. On Swift 5 this code works absolutely fine. The above method consistently crashes with _dispatch_assert_queue_fail. My assumption is that in Swift 6 a trap has been inserted by the compiler to validate that my downstream code is running on the main thread. In Implementing a Main Actor Protocol That’s Not @MainActor, Quinn “The Eskimo!” seems to address scenarios of this nature with 3 proposed workarounds yet none of them seem feasible here. For #1, marking ContentView.addPlane(renderer:node:anchor:) nonisolated and using @preconcurrency import ARKit compiles but still crashes :( For #2, applying @preconcurrency to the ARSCNViewDelegate conformance declaration site just yields this warning: @preconcurrency attribute on conformance to 'ARSCNViewDelegate' has no effect For #3, as Quinn recognizes, this is a non-starter as ARSCNViewDelegate is out of our control. The minimal reproducible set of code is below. Simply run the app, scan your camera back and forth across a well lit environment and the app should crash within a few seconds. Switch over to Swift Language Version 5 in build settings, retry and you'll see the current code works fine. import ARKit import SwiftUI struct ContentView: View { @State private var arViewProxy = ARSceneProxy() private let configuration: ARWorldTrackingConfiguration @State private var planeFound = false init() { configuration = ARWorldTrackingConfiguration() configuration.worldAlignment = .gravityAndHeading configuration.planeDetection = [.horizontal] } var body: some View { ARScene(proxy: arViewProxy) .onAddNode { renderer, node, anchor in addPlane(renderer: renderer, node: node, anchor: anchor) } .onAppear { arViewProxy.session.run(configuration) } .onDisappear { arViewProxy.session.pause() } .overlay(alignment: .top) { if !planeFound { Text("Slowly move device horizontally side to side to calibrate") } else { Text("Plane found!") .bold() .foregroundStyle(.green) } } } private func addPlane(renderer: SCNSceneRenderer, node: SCNNode, anchor: ARAnchor) { guard let planeAnchor = anchor as? ARPlaneAnchor, let device = renderer.device, let planeGeometry = ARSCNPlaneGeometry(device: device) else { return } planeFound = true planeGeometry.update(from: planeAnchor.geometry) let material = SCNMaterial() material.isDoubleSided = true material.diffuse.contents = UIColor.white.withAlphaComponent(0.65) planeGeometry.materials = [material] let planeNode = SCNNode(geometry: planeGeometry) node.addChildNode(planeNode) } } struct ARScene { private(set) var onAddNodeAction: ((SCNSceneRenderer, SCNNode, ARAnchor) -> Void)? private let proxy: ARSceneProxy init(proxy: ARSceneProxy) { self.proxy = proxy } func onAddNode( perform action: @escaping (SCNSceneRenderer, SCNNode, ARAnchor) -> Void ) -> Self { var view = self view.onAddNodeAction = action return view } } extension ARScene: UIViewRepresentable { func makeUIView(context: Context) -> ARSCNView { let arView = ARSCNView() arView.delegate = context.coordinator arView.session.delegate = context.coordinator proxy.arView = arView return arView } func updateUIView(_ uiView: ARSCNView, context: Context) { context.coordinator.onAddNodeAction = onAddNodeAction } func makeCoordinator() -> Coordinator { Coordinator() } } extension ARScene { class Coordinator: NSObject, ARSCNViewDelegate, ARSessionDelegate { var onAddNodeAction: ((SCNSceneRenderer, SCNNode, ARAnchor) -> Void)? func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { onAddNodeAction?(renderer, node, anchor) } } } @MainActor class ARSceneProxy: NSObject, @preconcurrency ARSessionProviding { fileprivate var arView: ARSCNView! @objc dynamic var session: ARSession { arView.session } } Any help is greatly appreciated!
1
7
338
Oct ’24
Navigation Bar animation upon Tab change
Hi. Since Xcode 16 and/or iOS 18.0 (I upgraded at the same time), I have an strange effect in the lower (let's say) 20% section of the Navigation Bar when changing to another tab, and this independently if large titles are used or not. Mentioned section is brighter or darker than the rest of the Navigation Bar background, depending on which background tint is used. This effect lasts about 0.3 seconds, but is clearly visible, quite disturbing and new as of Xcode 16 and/or iOS 18.0. I use the code below in AppDelegate to get a gradient coloured Navigation Bar background. let appearance = UINavigationBarAppearance() UINavigationBar.appearance().standardAppearance = appearance UINavigationBar.appearance().compactAppearance = appearance UINavigationBar.appearance().scrollEdgeAppearance = appearance UINavigationBar.appearance().compactScrollEdgeAppearance = appearance If I don't use above code., the background color is filled and without gradient. Subject effect doesn't show in this case. The effect basically looks like when changing tab, the new Navigation Bar background doesn't clear right away, and keeps the background from the previous Navigation Bar for 0.3 seconds before new one Navigation Bar background is rendered. I spent quite some time on changing every possible setting, in code as well as storyboard ... no success so far. Any ideas how to disable this undesired animation?
0
0
217
Oct ’24
trailingSwipeActionsConfigurationProvider causes shadow effect on UICollectionViewListCell gone
Currently, I have achieve shadow and corner effect for UICollectionViewListCell, using the following code. UICollectionViewListCell class NoteCell: UICollectionViewListCell { override func awakeFromNib() { super.awakeFromNib() initShadow() initCorner() } private func updateShadowColor() { // Determine the shadow color based on the current interface style let shadowUIColor = UIColor.label self.layer.shadowColor = shadowUIColor.cgColor } private func initShadow() { // https://www.hackingwithswift.com/example-code/uikit/how-to-add-a-shadow-to-a-uiview self.layer.shadowOpacity = 0.3 self.layer.shadowOffset = CGSize(width: 0.5, height: 0.5) self.layer.shadowRadius = 2 self.layer.masksToBounds = false self.updateShadowColor() // Remove the following two lines if you experience any issues with shadow rendering: self.layer.shouldRasterize = true self.layer.rasterizationScale = UIScreen.main.scale } private func initCorner() { var backgroundConfig = UIBackgroundConfiguration.listPlainCell() backgroundConfig.backgroundColor = .systemBackground backgroundConfig.cornerRadius = 16 self.backgroundConfiguration = backgroundConfig } layout private func layoutConfig() -> UICollectionViewCompositionalLayout { let layout = UICollectionViewCompositionalLayout { section, layoutEnvironment in var config = UICollectionLayoutListConfiguration(appearance: .plain) config.headerMode = .none config.footerMode = .none config.showsSeparators = false config.headerTopPadding = 0 config.backgroundColor = nil config.trailingSwipeActionsConfigurationProvider = { [weak self] indexPath in guard let self = self else { return nil } // Knowing what we are tapping at. var snapshot = dataSource.snapshot() let sectionIdentifier = snapshot.sectionIdentifiers[indexPath.section] let itemIdentifiers = snapshot.itemIdentifiers(inSection: sectionIdentifier) let itemIdentifier: NoteWrapper = itemIdentifiers[indexPath.item] let deleteHandler: UIContextualAction.Handler = { action, view, completion in completion(true) // TODO: //snapshot.reloadItems([itemIdentifier]) } let deleteAction = UIContextualAction(style: .normal, title: "Trash", handler: deleteHandler) var swipeActionsConfiguration = UISwipeActionsConfiguration(actions: [ deleteAction, ]) deleteAction.image = UIImage(systemName: "trash") deleteAction.backgroundColor = UIColor.systemRed swipeActionsConfiguration.performsFirstActionWithFullSwipe = false return swipeActionsConfiguration } // https://developer.apple.com/forums/thread/759987 let layoutSection = NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) layoutSection.interGroupSpacing = 16 // Distance between item. layoutSection.contentInsets = NSDirectionalEdgeInsets( top: 16, // Distance between 1st item and its own header. leading: 16, bottom: 16, // Distance of last item and other header/ bottom edge. trailing: 16 ) return layoutSection } return layout } This is the outcome. However, when I perform swipe action, the shadow effect is gone. Do you have any idea how I can resolve such? Thanks.
0
0
181
Oct ’24
SwiftUI conditional modifier depending on OS type and version
This app may run on MacOS or iOS. I want to use windowResizability modifier (specially In MacOS) which is only available on masOS 13+ and iOS 17+, but still need to run on macOS 12 or iOS 15… So I need something like #if os(macOS) if #available(macOS 13 *) { use windowResizability #else do not use windowResizability #endif #else // iOS if #available(iOS 17 *) { use windowResizability #else do not use windowResizability #endif Here is the code where to apply (in @main) struct TheApp: App { var body: some Scene { WindowGroup { ContentView() // 1.11.2023 .frame( minWidth: 1200, maxWidth: .infinity, minHeight: 600, maxHeight: .infinity) } .windowResizability(.contentSize) // BTW: is that really necessary ? } } How can I achieve this ? Do I need to write a WindowGroup extension for the modifier ? If so, how ? BTW: is windowResizability really necessary ? App seems to work the same without it.
1
1
275
Oct ’24
How to connect SwiftUI state with UITable?
I use @Binding to sync data between SwiftUI component state and UITable state. my observations: while reordering @State variable of the TestView is updating, it can be checked by taping the button inside the table the data is not updating. 'log2' is always the same on reorder and which is more important the app crashes when I try to remove item. What to I missing? import SwiftUI import UIKit struct TestView: View { @State var items = ["item 1", "item 2", "item 3", "item 4", "item 5"] var body: some View { VStack { Button("Print Items") { print("log1", items) } ReorderableListView( items: $items ) { item in Text(item) } } } } private struct ReorderableListView<Content: View>: UIViewControllerRepresentable { @Binding var items: [String] let content: (String) -> Content class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate { var parent: ReorderableListView init(parent: ReorderableListView) { self.parent = parent } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { print("log2", parent.items) return parent.items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) let hostingController = UIHostingController(rootView: parent.content(parent.items[indexPath.row])) hostingController.view.backgroundColor = .clear cell.contentView.subviews.forEach { $0.removeFromSuperview() } cell.contentView.addSubview(hostingController.view) cell.separatorInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15) if indexPath.row == self.parent.items.count - 1 { cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude) } hostingController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ hostingController.view.topAnchor.constraint(equalTo: cell.contentView.topAnchor), hostingController.view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor), hostingController.view.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor), hostingController.view.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor) ]) return cell } func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { let movedObject = parent.items.remove(at: sourceIndexPath.row) parent.items.insert(movedObject, at: destinationIndexPath.row) } func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { parent.items.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .automatic) } } } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIViewController(context: Context) -> UITableViewController { let tableViewController = UITableViewController() tableViewController.tableView.dataSource = context.coordinator tableViewController.tableView.delegate = context.coordinator tableViewController.tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "Cell") tableViewController.tableView.isEditing = true return tableViewController } func updateUIViewController(_ uiViewController: UITableViewController, context: Context) { uiViewController.tableView.reloadData() } } private class CustomTableViewCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) } override func layoutSubviews() { super.layoutSubviews() superview?.subviews.filter({ "\(type(of: $0))" == "UIShadowView" }).forEach { (sv: UIView) in sv.removeFromSuperview() } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } #Preview { TestView() }
1
0
195
Oct ’24
HealthKit Read Permissions Not Displayed in Health App Settings After App Update
I am encountering a problem with HealthKit authorization in my app. In a previous version of the app, write permission for HKWorkoutType was already granted. In the new version of the app, I added a request for read permissions for both HKWorkoutType and HKWorkoutRoute. After updating the app, the following occurs: I can successfully fetch workout data using HKSampleQuery, and authorizationStatus(for: HKObjectType.workoutType()) returns .sharingAuthorized, indicating that the app has access to the data. However, when I check the Health app (Settings -> Health -> Data Access & Devices -> [App Name]), the read permission does not appear in the list. The write permission is still visible, but the newly requested read permission is missing. This behavior is unexpected because, despite being able to access the data programmatically, the read permission is not listed in the Health app settings. I have already verified that I am requesting the read permissions correctly in the code using requestAuthorization for both HKObjectType.workoutType() and HKObjectType.seriesType(forIdentifier: .workoutRoute). I would appreciate guidance on why this issue is occurring and how to ensure that read permissions are displayed correctly in the Health app settings.
1
0
216
Oct ’24
Can SceneKit be used with Swift 6 Concurrency ?
I am trying to port SceneKit projects to Swift 6, and I just can't figure out how that's possible. I even start thinking SceneKit and Swift 6 concurrency just don't match together, and SceneKit projects should - hopefully for the time being only - stick to Swift 5. The SCNSceneRendererDelegate methods are called in the SceneKit Thread. If the delegate is a ViewController: class GameViewController: UIViewController { let aNode = SCNNode() func renderer(_ renderer: any SCNSceneRenderer, updateAtTime time: TimeInterval) { aNode.position.x = 10 } } Then the compiler generates the error "Main actor-isolated instance method 'renderer(_:updateAtTime:)' cannot be used to satisfy nonisolated protocol requirement" Which is fully understandable. The compiler even tells you those methods can't be used for protocol conformance, unless: Conformance is declare as @preconcurrency SCNSceneRendererDelegate like this: class GameViewController: UIViewController, @preconcurrency SCNSceneRendererDelegate { But that just delays the check to runtime, and therefore, crash in the SceneKit Thread happens at runtime... Again, fully understandable. or the delegate method is declared nonisolated like this: nonisolated func renderer(_ renderer: any SCNSceneRenderer, updateAtTime time: TimeInterval) { aNode.position.x = 10 } Which generates the compiler error: "Main actor-isolated property 'position' can not be mutated from a nonisolated context". Again fully understandable. If the delegate is not a ViewController but a nonisolated class, we also have the problem that SCNNode can't be used. Nearly 100% of the SCNSceneRendererDelegate I've seen do use SCNNode or similar MainActor bound types, because they are meant for that. So, where am I wrong ? What is the solution to use SceneKit SCNSceneRendererDelegate methods with full Swift 6 compilation ? Is that even possible for now ?
4
0
392
1d
Can i use c++ in swift app project
Can i use c++ library with c library in swift app project Hello. I want to use a C++ library in my Swift app project. First, our company has an internal solution library. When built, it generates a Static Library in '.a' format, and we use it by connecting the library's Header to the App_Bridging_Header. There's no problem with this part. However, the new feature now includes C++. It also generates a Static Library in '.a' format. So, I tried to use the same method and created an App_Bridging_Header. But an error occurs, and I can't proceed. The first error occurs in the library file: 'iostream' file not found The second error occurs in the App_Bridging_Header: failed to emit precompiled header '/Users/kimjitae/Library/Developer/Xcode/DerivedData/ddddd-glmnoqrwdrgarrhjulxjmalpyikr/Build/Intermediates.noindex/PrecompiledHeaders/ddddd-Bridging-Header-swift_3O89L0OXZ0CPD-clang_188AW1HK8F0Q3.pch' for bridging header '/Users/kimjitae/Desktop/enf4/ddddd/ddddd/ddddd-Bridging-Header.h' Our library is developed in C++ using Xcode, and there's no problem when we run and build just the library project. The build succeeds, and the '.a' file is generated correctly. However, when we try to connect it with the app, the above problems occur. Could there be a problem because we also need to use the existing C library alongside this? The build is successful in an app project created with Objective-C.
4
0
255
Oct ’24
Distorted Audio When Recording External Mics With AVCaptureSession and AVAssetWriter
I’m working on a macOS app, written in Swift. My goal is to record audio from an external microphone, e.g., one connected via USB. For this, I’m using an AVCaptureSession and recording its output with an AVAssetWriter. This works perfectly in principle (and reliably with internal microphones, for example). The problem occurs after my app has successfully completed the first recording and I then want to make additional recordings (which makes me think it might be process-dependent, because it works again after restarting the app). The problem: Noisy or distorted-sounding audio files. In addition, the following error message appears in the Console from CoreAudio / its AudioConverter: Input data proc returned inconsistent 512 packets for 2048 bytes; at 3 bytes per packet, that is actually 682 packets It is easy to reproduce. This problem is reproducible even if I don’t configure the AVAssetWriter manually and instead let it receive its audioSettings using a preset from an AVOutputSettingsAssistant. I’m running on macOS 15.0 (24A335). I’ve filed a feedback including a demo project → FB15333298 🎟️ I would greatly appreciate any help! Have a great day, Martin
5
0
350
1w
AVAssetWriterInput -- inserting sample buffers with pauses in between not working
Hi, I'm trying to insert CMSampleBuffers into an AVAssetWriterInput that has been configured with expectsMediaDataInRealTime = false with pauses. That is, I insert fixed-length audio at specific (increasing and non-overlapping) time points with large gaps in between. E.g., 5 seconds of audio at t=3.0, 5 seconds of audio at t=12.0, etc. The first audio sample plays at t=3 in the final output video as expected. But then all the other samples are bunched up immediately after it instead of being scheduled at the correct time. Below is my code. I'm just loading the asset and then readjusting its timestamps to be correct in the absolute timeline. Why do they not get scheduled correctly when the timestamps and durations are definitely correct and non-overlapping? func addFrame(_ pixelBuffer: CVPixelBuffer) { guard CGSize(width: pixelBuffer.width, height: pixelBuffer.height) == outputSize else { return } let frameTime = CMTimeMake(value: frameCount, timescale: frameRate) if videoInput?.isReadyForMoreMediaData == true { pixelBufferAdaptor?.append(pixelBuffer, withPresentationTime: frameTime) frameCount += 1 currentTime = frameTime } } func addMP3AudioClip(_ audioData: Data) async throws { let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString + ".mp3") defer { try? FileManager.default.removeItem(at: tempURL) } try audioData.write(to: tempURL) let asset = AVAsset(url: tempURL) let duration = try await asset.load(.duration) let audioTrack = try await asset.loadTracks(withMediaType: .audio).first! let audioReader = try AVAssetReader(asset: asset) let outputSettings: [String: Any] = [ AVFormatIDKey: kAudioFormatLinearPCM, AVSampleRateKey: 44100, AVNumberOfChannelsKey: 2, AVLinearPCMBitDepthKey: 16, AVLinearPCMIsFloatKey: false, AVLinearPCMIsBigEndianKey: false, AVLinearPCMIsNonInterleaved: false ] let audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: outputSettings) audioReader.add(audioReaderOutput) guard audioReader.startReading() else { throw NSError(domain: "AudioReaderError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to start reading audio"]) } let baseInsertionTime = currentTime.convertScale(duration.timescale, method: .default) // Capture the current video time when the method is called print("Adding audio clip at \(baseInsertionTime.seconds) seconds, duration: \(duration.seconds) seconds") var audioTime = CMTime.zero var totalDuration: Double = 0 while let sampleBuffer = audioReaderOutput.copyNextSampleBuffer() { let bufferDuration = CMSampleBufferGetDuration(sampleBuffer) let adjustedBuffer = adjustTimeStamp(of: sampleBuffer, by: baseInsertionTime) while !audioInput!.isReadyForMoreMediaData { try await Task.sleep(nanoseconds: 100_000_000) // 0.1 second } audioInput!.append(adjustedBuffer) print(" Adjusted time: \(adjustedBuffer.presentationTimeStamp.seconds)") audioTime = CMTimeAdd(audioTime, bufferDuration) totalDuration += bufferDuration.seconds } print("Finished adding audio clip. Last sample at: \(CMTimeAdd(baseInsertionTime, audioTime).seconds) seconds") print(" totalDuration=\(totalDuration)") } private func adjustTimeStamp(of sampleBuffer: CMSampleBuffer, by timeOffset: CMTime) -> CMSampleBuffer { var count: CMItemCount = 0 CMSampleBufferGetSampleTimingInfoArray(sampleBuffer, entryCount: 0, arrayToFill: nil, entriesNeededOut: &count) var timingInfo = [CMSampleTimingInfo](repeating: CMSampleTimingInfo(), count: count) CMSampleBufferGetSampleTimingInfoArray(sampleBuffer, entryCount: count, arrayToFill: &timingInfo, entriesNeededOut: nil) for i in 0..<count { timingInfo[i].presentationTimeStamp = CMTimeAdd(timingInfo[i].presentationTimeStamp, timeOffset) if timingInfo[i].decodeTimeStamp != .invalid { timingInfo[i].decodeTimeStamp = CMTimeAdd(timingInfo[i].decodeTimeStamp, timeOffset) } else { timingInfo[i].decodeTimeStamp = timingInfo[i].presentationTimeStamp } } var adjustedBuffer: CMSampleBuffer? CMSampleBufferCreateCopyWithNewTiming(allocator: nil, sampleBuffer: sampleBuffer, sampleTimingEntryCount: count, sampleTimingArray: &timingInfo, sampleBufferOut: &adjustedBuffer) return adjustedBuffer! }
0
0
228
Oct ’24
Casting `[String: Any]` to `[String: any Sendable]`
I have a simple wrapper class around WCSession to allow for easier unit testing. I'm trying to update it to Swift 6 concurrency standards, but running into some issues. One of them is in the sendMessage function (docs here It takes [String: Any] as a param, and returns them as the reply. Here's my code that calls this: @discardableResult public func sendMessage(_ message: [String: Any]) async throws -&gt; [String: Any] { return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation&lt;[String: Any], Error&gt;) in wcSession.sendMessage(message) { response in continuation.resume(returning: response) // ERROR HERE } errorHandler: { error in continuation.resume(throwing: error) } } } However, I get this error: Sending 'response' risks causing data races; this is an error in the Swift 6 language mode Which I think is because Any is not Sendable. I tried casting [String: Any] to [String: any Sendable] but then it says: Conditional cast from '[String : Any]' to '[String : any Sendable]' always succeeds Any ideas on how to get this to work?
3
1
365
Oct ’24
How to share PHAsset with UIActivityViewController like Photos App?
I am building an app about photos and I want to create a photo sharing feature like Apple's Photos App. Please see Steps to Reproduce and attached project. The current share method has the following issues The file name of the shared photo changes to “FullSizeRender”. The creation and update dates of shared photos will change to the date they were edited or shared. I want to ensure that the following conditions are definitely met Share the latest edited version. The creation date should be when the original photo was first created. How can I improve the code? STEPS TO REPRODUCE class PHAssetShareManager { static func shareAssets(_ assets: [PHAsset], from viewController: UIViewController, sourceView: UIView) { let manager = PHAssetResourceManager.default() var filesToShare: [URL] = [] let group = DispatchGroup() for asset in assets { group.enter() getAssetFile(asset, resourceManager: manager) { fileURL in if let fileURL = fileURL { filesToShare.append(fileURL) } group.leave() } } group.notify(queue: .main) { self.presentShareSheet(filesToShare, from: viewController, sourceView: sourceView) } } private static func getAssetFile(_ asset: PHAsset, resourceManager: PHAssetResourceManager, completion: @escaping (URL?) -> Void) { print("getAssetFile") let resources: [PHAssetResource] switch asset.mediaType { case .image: if asset.mediaSubtypes.contains(.photoLive) { // let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizePairedVideo } // let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .pairedVideo } let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizePhoto } let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .photo } resources = editedResources.isEmpty ? originalResources : editedResources } else { let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizePhoto } let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .photo } resources = editedResources.isEmpty ? originalResources : editedResources } case .video: let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizeVideo } let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .video } resources = editedResources.isEmpty ? originalResources : editedResources default: print("Unsupported media type") completion(nil) return } guard let resource = resources.first else { print("No resource found") completion(nil) return } let fileName = resource.originalFilename let tempDirectoryURL = FileManager.default.temporaryDirectory let localURL = tempDirectoryURL.appendingPathComponent(fileName) // Delete existing files and reset cache if FileManager.default.fileExists(atPath: localURL.path) { do { try FileManager.default.removeItem(at: localURL) } catch { print("Error removing existing file: \(error)") } } let options = PHAssetResourceRequestOptions() options.isNetworkAccessAllowed = true resourceManager.writeData(for: resource, toFile: localURL, options: options) { (error) in if let error = error { print("Error writing asset data: \(error)") completion(nil) } else { completion(localURL) } } } private static func presentShareSheet(_ items: [Any], from viewController: UIViewController, sourceView: UIView) { print("presentShareSheet") let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: nil) if UIDevice.current.userInterfaceIdiom == .pad { activityViewController.popoverPresentationController?.sourceView = sourceView activityViewController.popoverPresentationController?.sourceRect = sourceView.bounds } viewController.present(activityViewController, animated: true, completion: nil) } }```
0
0
193
Oct ’24
SwiftUI iOS18 Bug: 'contextMenu' does not recognize 'scaleEffect' and similar outside of 'ScrollView' parent
The Issue I am building a MessageChannelView, I take most advantage of all ScrollView mechanics by flipping it on it's head with .scaleEffect(y: -1), and then the content inside of it again with .scaleEffect(y: -1), so the content is back to normal. Putting .contextMenu() on any of the elements flipped back to normality will cause an ugly bug on iOS18, but not on iOS17. This is because .contextMenu() on iOS18 does not recognize the .scaleEffect(y: -1) outside of it's ScrollView parent. Minimal Replication 1.) Create any View with SwiftUI similar to this: ScrollViewReader { scrollView in ScrollView { VStack { Text("Test!") .contextMenu { Button(action: {}) { Label("Copy Link", systemImage: "doc.on.doc") } } } .scaleEffect(y: -1) } .scaleEffect(y: -1) } 2.) Run on a physical device with iOS18 More I tested this on three different physical iPhone devices, iOS16, iOS17 and my main device iOS18. The bug only exists on iOS18.
1
1
248
Oct ’24
ITMS-90426: Invalid Swift Support when uploading VisionOS app to Appstore Connect with dylib
I'm trying to upload a build to app store connect. It's a build from a Unity project with the polyspatial SDK, and I also need to include a c++ library, which I've added as a dylib signed with the same provisioning profile as the app. The profile is an Apple Distribution profile created from an enterprise account. It succesfully uploads to Appstore connect, but fails with the following error message: ITMS-90426: Invalid Swift Support - The SwiftSupport folder is missing. Rebuild your app using the current public (GM) version of Xcode and resubmit it. This is unhelpful as I'm using a current version of Xcode. I've read that it's a provisioning issue, but I'm using the provisioning profile for apple distribution on an enterprise account, not an ad hoc profile. I've tried manually adding the SwiftSupport folder from the Xcode toolchain to the ipa/xarchive, resign and upload with Transporter, but that doesn't work. After spending a day trying to troubleshoot this, I'm at a loss. Any help with this is much appreciated. Note: I can sideload the app onto an AVP with an ad hoc build and ad hoc provisioning profile (I've added the signed dylib to build phases Link with Libraries and Embed Frameworks). Somehow this doesn't need the SwiftSupport?
2
0
523
Oct ’24
Unable to change UITabbar Background color in iOS 18 for ipad
I am trying to change UITabBar background color runtime as theme changed. It is already working in iOS 17 as I am updating UITabBar.appearance().barTintColor and tintColor But for iOS first i need to change because I don't want that new elevated tabbar so I create custom tabbar controller as described in https://stackoverflow.com/questions/78631030/how-to-disable-the-new-uitabbarcontroller-view-style-in-ipados-18 Accepted Answer by awulf. And by doing this, My tabbar looks same like Old and it is working in iPhone and ipad for iOS 16, iOS 17 and iOS 18 too. But the issue is that I am unable to change my tabbar background color. I have also checked this forum: https://forums.developer.apple.com/forums/thread/761056 But not able to change I have set below 3 properties but no effect let appearance = UITabBar.appearance() appearance.backgroundColor = appearance.barTintColor = appearance.tintColor = I have created CustomTabBarController in storyboard and all working fine Also the appearance changed only once per application lifecycle. It will change color by restarting the app then it will pick last selected theme and the colors are changed. but not able to change colors runtime I have also did below code for reloading purpose tabBar.setNeedsLayout() tabBar.setNeedsDisplay() But nothing work
0
0
393
Oct ’24
Implementing multiple Model Containers
Hi, When using just one model container, I have the following code: let modelContainer: ModelContainer init() { do { entriesModel = try ModelContainer(for: Model.self) } catch { fatalError("Could not initialize ModelContainer") } } I am attempting to implement two like so: let model1: ModelContainer let model2: ModelContainer init() { do { model1 = try ModelContainer(for: Model1.self) model2 = try ModelContainer(for: Model2.self) } catch { fatalError("Could not initialize ModelContainer") } } var body: some Scene { WindowGroup { ContentView() .modelContainer(model1) .modelContainer(model2) } } However, when in the Views that I'd like to implement I don't know how to declare the models. I tried this: @Environment(\.model1) private var model1 @Query private var data: [Model1] But I get the error: Cannot infer key path type from context; consider explicitly specifying a root type How do I implement multiple model containers in multiple different views?
2
0
466
Oct ’24
Crash with Incorrect actor executor assumption
I'm seeing a crash compiling with Swift 6 that I can reproduce with the following code. It crashes with "Incorrect actor executor assumption". Is there something that the compiler should be warning about so that this isn't a runtime crash? Note - if I use a for in loop instead of the .forEach closure, the crash does not happen. Is the compiler somehow inferring the wrong isolation domain for the closure? import SwiftUI struct ContentView: View { var body: some View { Text("Hello, world!") .task { _ = try? await MyActor(store: MyStore()) } } } actor MyActor { var credentials = [String]() init(store: MyStore) async throws { try await store.persisted.forEach { credentials.append($0) } } } final class MyStore: Sendable { var persisted: [String] { get async throws { return ["abc"] } } } The stack trace is: * thread #6, queue = 'com.apple.root.user-initiated-qos.cooperative', stop reason = signal SIGABRT frame #0: 0x0000000101988f30 libsystem_kernel.dylib`__pthread_kill + 8 frame #1: 0x0000000100e2f124 libsystem_pthread.dylib`pthread_kill + 256 frame #2: 0x000000018016c4ec libsystem_c.dylib`abort + 104 frame #3: 0x00000002444c944c libswift_Concurrency.dylib`swift::swift_Concurrency_fatalErrorv(unsigned int, char const*, char*) + 28 frame #4: 0x00000002444c9468 libswift_Concurrency.dylib`swift::swift_Concurrency_fatalError(unsigned int, char const*, ...) + 28 frame #5: 0x00000002444c90e0 libswift_Concurrency.dylib`swift_task_checkIsolated + 152 frame #6: 0x00000002444c63e0 libswift_Concurrency.dylib`swift_task_isCurrentExecutorImpl(swift::SerialExecutorRef) + 284 frame #7: 0x0000000100d58944 IncorrectActorExecutorAssumption.debug.dylib`closure #1 in MyActor.init($0="abc") at <stdin>:0 frame #8: 0x0000000100d58b94 IncorrectActorExecutorAssumption.debug.dylib`partial apply for closure #1 in MyActor.init(store:) at <compiler-generated>:0 frame #9: 0x00000001947f8c80 libswiftCore.dylib`Swift.Sequence.forEach((τ_0_0.Element) throws -> ()) throws -> () + 428 * frame #10: 0x0000000100d58748 IncorrectActorExecutorAssumption.debug.dylib`MyActor.init(store=0x0000600000010ba0) at ContentView.swift:27:35 frame #11: 0x0000000100d57734 IncorrectActorExecutorAssumption.debug.dylib`closure #1 in ContentView.body.getter at ContentView.swift:14:32 frame #12: 0x0000000100d57734 IncorrectActorExecutorAssumption.debug.dylib`closure #1 in ContentView.body.getter at ContentView.swift:14:32 frame #13: 0x00000001d1817138 SwiftUI`(1) await resume partial function for partial apply forwarder for closure #1 () async -> () in closure #1 (inout Swift.TaskGroup<()>) async -> () in closure #1 () async -> () in SwiftUI.AppDelegate.application(_: __C.UIApplication, handleEventsForBackgroundURLSession: Swift.String, completionHandler: () -> ()) -> () frame #14: 0x00000001d17b1e48 SwiftUI`(1) await resume partial function for dispatch thunk of static SwiftUI.PreviewModifier.makeSharedContext() async throws -> τ_0_0.Context frame #15: 0x00000001d19c10c0 SwiftUI`(1) await resume partial function for generic specialization <()> of reabstraction thunk helper <τ_0_0 where τ_0_0: Swift.Sendable> from @escaping @isolated(any) @callee_guaranteed @async () -> (@out τ_0_0) to @escaping @callee_guaranteed @async () -> (@out τ_0_0, @error @owned Swift.Error) frame #16: 0x00000001d17b1e48 SwiftUI`(1) await resume partial function for dispatch thunk of static SwiftUI.PreviewModifier.makeSharedContext() async throws -> τ_0_0.Context
2
0
529
Oct ’24