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!
Swift
RSS for tagSwift 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
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?
If I put the phone flat on a table, the left and right swipe gestures is not working but up and down gestures works.
Only when I put the iPhone to some vertical degree, the left and right swipe works.
Tested on 2 iPhone 7 Plus and 2 iPhone 13.
Anyone has similar experience? If yes, why?
Are there any known memory leaks in the Network framework? When using the start function on NWConnection I find a small leak appear every time (see attached image). I am using it for websockets
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.
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.
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()
}
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.
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 ?
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.
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
I want to dismiss a window when a user presses a button. I have tried the @Environment dismissWindow, however that's macOS 14+. My app requires compatibility with macOS 13 at minimum.
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!
}
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 -> [String: Any] {
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<[String: Any], Error>) 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?
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)
}
}```
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.
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?
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
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?
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