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

Issue with Property Wrapper Publisher Being Deallocated Prematurely When Not Stored as a Property
Hello everyone, I've built a @CurrentValue property wrapper that mimics the behavior of @Published, allowing a property to publish values on "did set". I've also created my own assign(to:) implementation that works with @CurrentValue properties, allowing values to be assigned from a publisher to a @CurrentValue property. However, I'm running into an issue. When I use this property wrapper with two classes and the source class (providing the publisher) is not stored as a property, the subscription is deallocated, and values are no longer forwarded. Here's the property wrapper code: @propertyWrapper public struct CurrentValue<Value> { /// A publisher for properties marked with the `@CurrentValue` attribute. public struct Publisher: Combine.Publisher { public typealias Output = Value public typealias Failure = Never /// A subscription that forwards the values from the CurrentValueSubject to the downstream subscriber private class CurrentValueSubscription<S>: Subscription where S: Subscriber, S.Input == Output, S.Failure == Failure { private var subscriber: S? private var currentValueSubject: CurrentValueSubject<S.Input, S.Failure>? private var cancellable: AnyCancellable? init(subscriber: S, publisher: CurrentValue<Value>.Publisher) { self.subscriber = subscriber self.currentValueSubject = publisher.subject } func request(_ demand: Subscribers.Demand) { var demand = demand cancellable = currentValueSubject?.sink { [weak self] value in // We'll continue to emit new values as long as there's demand if let subscriber = self?.subscriber, demand > 0 { demand -= 1 demand += subscriber.receive(value) } else { // If we have no demand, we'll cancel our subscription: self?.subscriber?.receive(completion: .finished) self?.cancel() } } } func cancel() { cancellable = nil subscriber = nil currentValueSubject = nil } } /// A subscription store that holds a reference to all the assign subscribers so we can cancel them when self is deallocated fileprivate final class AssignSubscriptionStore { fileprivate var cancellables: Set<AnyCancellable> = [] } fileprivate let subject: CurrentValueSubject<Value, Never> fileprivate let assignSubscriptionStore: AssignSubscriptionStore = .init() fileprivate var value: Value { get { subject.value } nonmutating set { subject.value = newValue } } init(_ initialValue: Output) { self.subject = .init(initialValue) } public func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input { let subscription = CurrentValueSubscription(subscriber: subscriber, publisher: self) subscriber.receive(subscription: subscription) } } public var wrappedValue: Value { get { publisher.value } nonmutating set { publisher.value = newValue } } public var projectedValue: Publisher { get { publisher } mutating set { publisher = newValue } } private var publisher: Publisher public init(wrappedValue: Value) { publisher = .init(wrappedValue) } } /// A subscriber that receives values from an upstream publisher and assigns them to a downstream CurrentValue property. private final class AssignSubscriber<Input>: Subscriber, Cancellable { typealias Failure = Never private var receivingSubject: CurrentValueSubject<Input, Never>? private weak var assignSubscriberStore: CurrentValue<Input>.Publisher.AssignSubscriptionStore? init(currentValue: CurrentValue<Input>.Publisher) { self.receivingSubject = currentValue.subject self.assignSubscriberStore = currentValue.assignSubscriptionStore } func receive(subscription: Subscription) { // Hold a reference to the subscription in the downstream publisher // so when it deallocates, the susbcription is automatically cancelled assignSubscriberStore?.cancellables.insert(AnyCancellable(subscription)) subscription.request(.unlimited) } func receive(_ input: Input) -> Subscribers.Demand { receivingSubject?.value = input return .none } func receive(completion: Subscribers.Completion<Never>) { // Nothing to do here } public func cancel() { receivingSubject = nil assignSubscriberStore = nil } } public extension Publisher where Self.Failure == Never { /// Assigns the output of the upstream publisher to a downstream CurrentValue property /// - Parameter currentValue: The CurrentValue property to assign the values to func assign(to currentValue: inout CurrentValue<Self.Output>.Publisher) { let subscriber = AssignSubscriber(currentValue: currentValue) self.subscribe(subscriber) } } Here’s an example demonstrating the issue, where two classes are used: Source, which owns the @CurrentValue property, and Forwarder1, which subscribes to updates from Source: final class Source { @CurrentValue public private(set) var value: Int = 1 func update(value: Int) { self.value = value } } final class Forwarder1 { @CurrentValue public private(set) var value: Int init(source: Source) { self.value = source.value source.$value.dropFirst().assign(to: &$value) // The source is not stored as a property, so the subscription deallocates } func update(value: Int) { self.value = value } } With this setup, if source isn’t retained as a property in Forwarder1, the subscription is deallocated prematurely, and value in Forwarder1 stops receiving updates from Source. However, this doesn’t happen with @Published properties in Combine. Even if source isn’t retained, @Published subscriptions seem to stay active, propagating values as expected. My Questions: What does Combine do internally with @Published properties that prevents the subscription from being deallocated prematurely, even if the publisher source isn’t retained as a property? Is there a recommended approach to address this in my custom property wrapper to achieve similar behavior, ensuring the subscription isn’t lost? Any insights into Combine’s internals or suggestions on how to resolve this would be greatly appreciated. Thank you!
0
3
87
1w
Background Tasks runs foreground
Hello everyone! I'm having a problem with background tasks running in the foreground. When a user enters the app, a background task is triggered. I've written some code to check if the app is in the foreground and to prevent the task from running, but it doesn't always work. Sometimes the task runs in the background as expected, but other times it runs in the foreground, as I mentioned earlier. Could it be that I'm doing something wrong? Any suggestions would be appreciated. here is code: class BackgroundTaskService { @Environment(\.scenePhase) var scenePhase static let shared = BackgroundTaskService() private init() {} // MARK: - create task func createCheckTask() { let identifier = TaskIdentifier.check BGTaskScheduler.shared.getPendingTaskRequests { requests in if requests.contains(where: { $0.identifier == identifier.rawValue }) { return } self.createByInterval(identifier: identifier.rawValue, interval: identifier.interval) } } private func createByInterval(identifier: String, interval: TimeInterval) { let request = BGProcessingTaskRequest(identifier: identifier) request.earliestBeginDate = Date(timeIntervalSinceNow: interval) scheduleTask(request: request) } // MARK: submit task private func scheduleTask(request: BGProcessingTaskRequest) { do { try BGTaskScheduler.shared.submit(request) } catch { // some actions with error } } // MARK: background actions func checkTask(task: BGProcessingTask) { let today = Calendar.current.startOfDay(for: Date()) let lastExecutionDate = UserDefaults.standard.object(forKey: "lastCheckExecutionDate") as? Date ?? Date.distantPast let notRunnedToday = !Calendar.current.isDate(today, inSameDayAs: lastExecutionDate) guard notRunnedToday else { task.setTaskCompleted(success: true) createCheckTask() return } if scenePhase == .background { TaskActionStore.shared.getAction(for: task.identifier)?() } task.setTaskCompleted(success: true) UserDefaults.standard.set(today, forKey: "lastCheckExecutionDate") createCheckTask() } } And in AppDelegate: BGTaskScheduler.shared.register(forTaskWithIdentifier: "check", using: nil) { task in guard let task = task as? BGProcessingTask else { return } BackgroundTaskService.shared.checkNodeTask(task: task) } BackgroundTaskService.shared.createCheckTask()
1
0
110
6d
Do i need to put any OS Error handling for Unmanaged.passRetain (obj) or Unmanaged.takeRetain (objptr)
In below Swift code , is there any possiblities of failure of Unmanaged.passRetain and Unmanaged.takeRetain calls ? // can below call fail (constructor returns nil due to OS or language error) and do i need to do explicit error handling here? let str = TWSwiftString(pnew) // Increasing RC by 1 // can below call fail (assuming str is valid) and do i need to do explicit error handling for the same ? let ptr:UnsafeMutableRawPointer? = Unmanaged.passRetained(str).toOpaque() // decrease RC by 1 // can below call fail (assuming ptr is valid) ? and do i need to do explicit error handling Unmanaged<TWSwiftString>.fromOpaque(pStringptr).release()
1
0
165
1w
Custom Alarm Sound Not Working in Background or Lock Screen Using Swift 5 and AVAudioPlayer
Hello everyone, I’m developing an alarm app in Swift 5, and I’m running into an issue with playing custom alarm sounds. Here’s the setup: I’m using AVAudioPlayer to play a custom sound when the alarm goes off. I’m triggering the alarm through a local notification, which works perfectly while the app is in the foreground. However, when the app is in the background or the screen is locked, the custom alarm sound doesn’t play. I’ve looked at other apps on the App Store, like Alarmy, which seem to play alarms even when the iPhone is locked or the app is in the background. I’m trying to achieve similar functionality but haven’t been successful. If anyone has experience with creating alarm apps or has a workaround for playing sounds in the background/lock screen, I’d really appreciate your insights. Are there specific permissions or settings I need to enable, or a different approach to handling sound playback? Thank you so much in advance for your help!
0
0
67
1w
How to draw emojis like the Lock Screen customisation?
On iOS you can create a new Lock Screen that contains a bunch of emoji, and they'll get put on the screen in a repeating pattern, like this: When you have two or more emoji they're placed in alternating patterns, like this: How do I write something like that? I need to handle up to three emoji, and I need the canvas as large as the device's screen, and it needs to be saved as an image. Thanks! (I've already written an emojiToImage() extension on String, but it just plonks one massive emoji in the middle of an image, so I'm doing something wrong there.)
0
0
113
1w
AttributeGraph: AG::Graph::update_main_refs(AG::AttributeID)
Hello, I recently have crashes on my application, it results in many crashes with different reasons, here are the different main reasons: AttributeGraph: AG::Graph::update_main_refs(AG::AttributeID) SwiftUICore: closure #1 in ViewLayoutEngine.explicitAlignment(_:at:) SwiftUICore: __swift_instantiateGenericMetadata My main problem is that these crashes appeared without any major changes to my app, and they never happen when I emulate the app from xcode whether on a simulator or a real device. I have other crashes with other errors I can provide them if necessary. So I have a lot of trouble identifying where the errors come from, I tried to activate zombie objects, and address sanitizer without it revealing anything. Thanks in advance for the answers.
0
0
133
1w
refreshed/updated data on widgets
Hello, I have a small lightweight macOS application that includes a medium widget but the widget does not update with new data as often as I'd like. I understand that in apple's WidgetKit documentation they mention that apple controls when the widget updates due to battery life concerns, but I'd like to know if theres any way at all to control when the widget updates or when I think it makes sense to do so if I am not able to control how often it refreshes new data. https://github.com/Alexx1105/MacStat-v2.1
2
0
147
1w
Failed to generate TargetContentIdentifier for criteria
I have implemented ShowInAppSearchResultsIntent and AppShortcutsProvider. But on iOS 18.1+ getting and error in console :- Failed to generate TargetContentIdentifier for criteria. In iOS 18.0 it's working fine. The code I have implemented @AssistantIntent(schema: .system.search) struct SearchIntent: ShowInAppSearchResultsIntent { // static let title: LocalizedStringResource = "Search in Cineverse for" static let searchScopes: [StringSearchScope] = [.general] @Parameter(requestValueDialog: IntentDialog("What would you like to search for?")) var criteria: StringSearchCriteria @MainActor func perform() async throws -> some IntentResult { let searchString = criteria.term print("Searching for \(searchString)") return .result() } } class AppShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: SearchIntent(), phrases: [ "using \(.applicationName) search for", "search on \(.applicationName) app" ], shortTitle: "Search Movie", systemImageName: "magnifyingglass" ) } }
0
0
146
1w
SwiftUI View cannot conform custom Equatable protocol in Swift 6.
In Swift 6, stricter concurrency rules can lead to challenges when making SwiftUI views conform to Equatable. Specifically, the == operator required for Equatable must be nonisolated, which means it cannot access @MainActor-isolated properties. This creates an error when trying to compare views with such properties: Error Example: struct MyView: View, Equatable { let title: String let count: Int static func ==(lhs: MyView, rhs: MyView) -> Bool { // Accessing `title` here would trigger an error due to actor isolation. return lhs.count == rhs.count } var body: some View { Text(title) } } Error Message: Main actor-isolated operator function '==' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode. Any suggestions? Thanks FB: FB15753655 (SwiftUI View cannot conform custom Equatable protocol in Swift 6.)
4
0
143
1w
Network framework crashes from nw_browser_cancel call
Hi, I'm using the Network framework to browse for devices on the local network. Unfortunately, I get many crash reports that crash in nw_browser_cancel, of which two are attached. This discussion seems to have a similar issue, but it was never resolved: https://forums.developer.apple.com/forums/thread/696037 Contrary to the situation in the linked thread, my implementation uses DispatchQueue.main as the queue for the browser, so I don't think over-releasing the queue is the problem. I am unable to reproduce this problem myself, but one of my users can reproduce it reliably it seems. How can I resolve this crash? 2024-11-10_14-24-35.3886_+0100-4fdbdb8e944a4b655d60df53da3aa8c759f4fd1f.crash 2024-11-08_08-54-31.6366_+0100-303cabefb74bf89cdea3127b1cad122ee46016f2.crash
2
0
107
1w
UICollectionView Auto cell height problem
Hi, I'm trying to create a UICollectionView where the cell high is automatic. Cells contains a UILabel with all anchors to the contentView of the cell. It seems to work but I have a strange behavior with longer text, on reload data and on device rotation: Cells do not display the whole text or they change row, both randomly. To create my collection view I first create the collection view with a custom flow layout setting the automatic size on viewWillAppear: let collectionViewFlowLayout = CustomFlowLayout() collectionViewFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout) and I have also overridden: override func willAnimateRotation(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { collectionView.setNeedsLayout() self.collectionView.layoutIfNeeded() self.collectionView.collectionViewLayout.invalidateLayout() //self.collectionView.reloadData() } Then, I created the custom layout as follow: import UIKit final class CustomFlowLayout: UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ $0.copy() } as? [UICollectionViewLayoutAttributes] layoutAttributesObjects?.forEach({ layoutAttributes in if layoutAttributes.representedElementCategory == .cell { if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame { layoutAttributes.frame = newFrame } } }) return layoutAttributesObjects } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { guard let collectionView = collectionView else { fatalError() } guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else { return nil } layoutAttributes.frame.origin.x = sectionInset.left if(indexPath.section == 0){ layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right } else if (indexPath.section == collectionView.numberOfSections - 1){ let width = ScreenUtility.getCollectionCellWidthForElement(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing, multiplier: 3) layoutAttributes.frame.origin.x = ScreenUtility.getCollectionCellOriginForElement(in: collectionView, at: indexPath, forElementHavingWidth: width, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing, multiplier: 3) layoutAttributes.frame.size.width = width } else if (indexPath.section == collectionView.numberOfSections - 3) || (indexPath.section == collectionView.numberOfSections - 4){ let width = ScreenUtility.getCollectionCellWidthForElement(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing) layoutAttributes.frame.origin.x = ScreenUtility.getCollectionCellOriginForElement(in: collectionView, at: indexPath, forElementHavingWidth: width, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing) layoutAttributes.frame.size.width = width } else { let width = ScreenUtility.getCollectionCellSizeForElementFullRow(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right) layoutAttributes.frame.origin.x = ScreenUtility.getCollectionCellOriginForElementFullRow(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right) layoutAttributes.frame.size.width = width } return layoutAttributes } } And finally on collection view cells: override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { setNeedsLayout() layoutIfNeeded() let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0) layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) return layoutAttributes } override func prepareForReuse() { self.nameLabel.text = "" self.idLabel.text = "" self.contentView.setNeedsLayout() self.contentView.layoutIfNeeded() } Let me show you an example on the iPad that is the worst. First Time I open the collection view I have cells on wrong rows and not sized properly Then I rotate the device portrait and the cells are fine On landscape again it changes behavior: This is just an example, things happens apparently randomly, and also sometimes cells disappear (I think the height is set to 0). I really do not understand why, cells width seems to be computed correctly, and cell label is set via setter: open var step: String = "" { didSet { nameLabel.text = step nameLabel.sizeToFit() self.contentView.setNeedsLayout() self.contentView.layoutIfNeeded() } }
2
0
114
1w
Async/Await and updating state
When using conformance to ObservableObject and then doing async work in a Task, you will get a warning courtesy of Combine if you then update an @Published or @State var from anywhere but the main thread. However, if you are using @Observable there is no such warning. Also, Thread.current is unavailable in asynchronous contexts, so says the warning. And I have read that in a sense you simply aren't concerned with what thread an async task is on. So for me, that begs a question. Is the lack of a warning, which when using Combine is rather important as ignoring it could lead to crashes, a pretty major bug that Apple seemingly should have addressed long ago? Or is it just not an issue to update state from another thread, because Xcode is doing that work for us behind the scenes too, just as it manages what thread the async task is running on when we don't specify? I see a lot of posts about this from around the initial release of Async/Await talking about using await MainActor.run {} at the point the state variable is updated, usually also complaining about the lack of a warning. But ow years later there is still no warning and I have to wonder if this is actually a non issue. On some ways similar to the fact that many of the early posts I have seen related to @Observable have examples of an @Observable ViewModel instantiated in the view as an @State variable, but in fact this is not needed as that is addressed behind the scenes for all properties of an @Observable type. At least, that is my understanding now, but I am learning Swift coming from a PowerShell background so I question my understanding a lot.
3
0
235
1w
No ObservableObject of Type "" found.
Im building an recipe app for the social media of my mother. i already have the functionality for the users, when a user gets created an empty array gets initiated at the database named favoriteRecipes, which stores the id of his favorite recipes to show in a view. This is my AuthViewModel which is relevant for the user stuff: import Firebase import FirebaseAuth import FirebaseFirestore protocol AuthenticationFormProtocol { var formIsValid: Bool { get } } @MainActor class AuthViewModel : ObservableObject { @Published var userSession: FirebaseAuth.User? @Published var currentUser: User? @Published var currentUserId: String? init() { self.userSession = Auth.auth().currentUser Task { await fetchUser() } } func signIn(withEmail email: String, password: String) async throws { do { let result = try await Auth.auth().signIn(withEmail: email, password: password) self.userSession = result.user await fetchUser() // fetch user sonst profileview blank } catch { print("DEBUG: Failed to log in with error \(error.localizedDescription)") } } func createUser(withEmail email: String, password: String, fullName: String) async throws { do { let result = try await Auth.auth().createUser(withEmail: email, password: password) self.userSession = result.user let user = User(id: result.user.uid, fullName: fullName, email: email) let encodedUser = try Firestore.Encoder().encode(user) try await Firestore.firestore().collection("users").document(result.user.uid).setData(encodedUser) await fetchUser() } catch { print("Debug: Failed to create user with error \(error.localizedDescription)") } } func signOut() { do { try Auth.auth().signOut() // sign out user on backend self.userSession = nil // wipe out user session and take back to login screen self.currentUser = nil // wipe out current user data model } catch { print("DEBUG: Failed to sign out with error \(error.localizedDescription)") } } func deleteAcocount() { let user = Auth.auth().currentUser user?.delete { error in if let error = error { print("DEBUG: Error deleting user: \(error.localizedDescription)") } else { self.userSession = nil self.currentUser = nil } } } func fetchUser() async { guard let uid = Auth.auth().currentUser?.uid else { return } currentUserId = uid let userRef = Firestore.firestore().collection("users").document(uid) do { let snapshot = try await userRef.getDocument() if snapshot.exists { self.currentUser = try? snapshot.data(as: User.self) print("DEBUG: current user is \(String(describing: self.currentUser))") } else { // Benutzer existiert nicht mehr in Firebase, daher setzen wir die userSession auf nil self.userSession = nil self.currentUser = nil } } catch { print("DEBUG: Fehler beim Laden des Benutzers: \(error.localizedDescription)") } } } This is the code to fetch the favorite recipes, i use the id of the user to access the collection and get the favoriteRecipes out of the array: import SwiftUI @MainActor class FavoriteRecipeViewModel: ObservableObject { @Published var favoriteRecipes: [Recipe] = [] @EnvironmentObject var viewModel: AuthViewModel private var db = Firestore.firestore() init() { Task { await fetchFavoriteRecipes() } } func fetchFavoriteRecipes() async{ let userRef = db.collection("users").document(viewModel.userSession?.uid ?? "") do { let snapshot = try await userRef.collection("favoriteRecipes").getDocuments() let favoriteIDs = snapshot.documents.map { $0.documentID } let favoriteRecipes = try await fetchRecipes(recipeIDs: favoriteIDs) } catch { print("DEBUG: Failed to load favorite recipes for user: \(error.localizedDescription)") } } func fetchRecipes(recipeIDs: [String]) async throws -&gt; [Recipe] { var recipes: [Recipe] = [] for id in recipeIDs { let snapshot = try await db.collection("recipes").document(id).getDocument() if let recipe = try? snapshot.data(as: Recipe.self) { recipes.append(recipe) } } return recipes } } Now the Problem occurs at the build of the project, i get the error SwiftUICore/EnvironmentObject.swift:92: Fatal error: No ObservableObject of type AuthViewModel found. A View.environmentObject(_:) for AuthViewModel may be missing as an ancestor of this view. I already passed the ViewModel instances as EnvironmentObject in the App Struct. import SwiftUI import FirebaseCore class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -&gt; Bool { FirebaseApp.configure() return true } } @main struct NimetAndSonApp: App { @StateObject var viewModel = AuthViewModel() @StateObject var recipeViewModel = RecipeViewModel() @StateObject var favoriteRecipeViewModel = FavoriteRecipeViewModel() @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView() .environmentObject(viewModel) .environmentObject(recipeViewModel) .environmentObject(favoriteRecipeViewModel) } } }
1
0
163
1w
Different information values depending on how the metadata of the image is obtained (PHAsset vs PHPickerResult)
While customizing ImagePicker and using it, we find out that the metadata is not reflected normally and report it. The situation is as follows. The time or time zone of an image is changed in the Photos app. Changing the time zone of an image with an actual capture date of 2024:11:08 08:27:44 → 2024:11:07 17:27:44 Image data is extracted from a PHAsset using PHImageManager. The metadata is obtained from this image data. The time zone information exposed in the Exif tag information does not reflect the time or time zone changed in the Photos app. let asset: PHAsset = ... .... let options = PHImageRequestOptions() options.isSynchronous = true options.version = .current options.deliveryMode = .highQualityFormat options.resizeMode = .none options.normalizedCropRect = .zero options.isNetworkAccessAllowed = true options.progressHandler = { progress, error, _, _ in } PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options) { imageData, uti, orientation, info in let cgImageSource = CGImageSourceCreateWithData(imageData! as CFData, nil) let properties = CGImageSourceCopyPropertiesAtIndex(cgImageSource!, 0, nil) as? Dictionary&lt;String, Any&gt; let exif = properties!["{Exif}"] let dictionary = exif as? Dictionary&lt;String, Any&gt; } Metadata Check In this case, it is reflected in the creationDate of PHAsset, so it can be somewhat compensated by forcibly replacing the metadata. However, because PHAsset does not include time zone information, when changing the time zone as well, it's impossible to calculate the correct time according to the time zone. PHPicker This issue is resolved when using the PHPickerResult provided by PHPicker. extension PhotosPickerViewController: PHPickerViewControllerDelegate { public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { ..... for result in results { let identifier = UTType.image.identifier if result.itemProvider.hasItemConformingToTypeIdentifier(identifier) { result.itemProvider.loadDataRepresentation(forTypeIdentifier: identifier) { data, error in guard let data = data, let cgImageSource = CGImageSourceCreateWithData(data as CFData, nil), let properties = CGImageSourceCopyPropertiesAtIndex(cgImageSource, 0, nil) as? Dictionary&lt;String, Any&gt;, let exif = properties["{Exif}"], let dictionary = exif as? Dictionary&lt;String, Any&gt; else { return } } } } } } Metadata Check Question I wonder why this happens, and if this is normal behavior. Instead of the System Picker that Apple provides as a base, I wonder if there is any way I can supplement it in that situation if I use a customizer.
0
0
218
1w
Swift optimization issue in macOS Sequoia
I'm using this library for encoding / decoding RSA keys. https://github.com/Kitura/BlueRSA It's worked fine up until macOS sequoia. The issue I'm having is the tests pass when in Debug mode, but the moment I switch to Release mode, the library no longer works. I ruled this down the swift optimization level. If I change the Release mode to no optimization, the library works again. Wondering where in the code this could be an issue? How would optimization break the functionality?
1
0
209
1w
[cxx-interop] Avoid breaking changes after enabling Swift C++ interoperability in library
Hi all, Background: I am working as a library developer and would like to enable Swift C++ interoperability in our library. Our library supports both CocoaPods and SPM. Question: I would like to know whether it is possible to avoid breaking changes bring to the library users after enabling Swift C++ interoperability. In my experiment, all apps and packages depend on the library needs to enable interoperability in Xcode or package manage tools, otherwise the source code cannot be complied. I am wondering is there any ways to bypass this? For example, is there a way to only enable Swift C++ interoperability only in our libraries?
1
0
156
1w
JavascriptCore and event loop / timers
JavascriptCore doesn't come with any support for setTimeout (which is an API on the window/DOM object not provide din JavaScriptCore). So you need to implement a version of this yourself - no worries on that (there are examples to refer to out there, so it is fairly easy to set this up). But I have come across an issue with this that I am not sure how to handle properly. It relates to when the timer callback fires and runs code in the JavaScript engine itself. Consider this code snippet (assume I have provided an implementation of setTimeout): console.log('Hello - here we go'); setTimeout(() => { console.log('Hi from setTimeout callback ...'); }, 0); Promise.resolve().then(() => { console.log('Hi from promise'); }); console.log('Hi from main block'); In Node.js or say Safari, I would see this output: Hello - here we go Hi from main block Hi from promise Hi from setTimeout callback ... So the promise then() is handled before the settimeout callback is handled. I think this is basically because Promise then() handlers are pushed onto something like a microtask queue, and the setttimeout callbacks on a separate queue, and the microtask queue is emptied before any other queue is processed (after completing the current event loop of course). But when I implement this in JavaScript core, I don't always see the above - instead I can have: Hello - here we go Hi from main block Hi from setTimeout callback ... Hi from promise So the timeout callback can be run BEFORE the promise handler. This obviously is different from Node or Safari. Now I assume that is because the timeout callback is triggered from Swift native code that uses the call() API on a JSValue object that is provided when the settimeout is given to the native layer to process. And it seems that when native code attempts to execute JavaScript code (via call() or similar) then this is just executed as soon as possible - obviously not interrupting the Javascript core when executing any current event loop code, but potentially running between the point when the Javascript core finishes a normal event loop cycle and then starts processing the queued promise handlers. This means that code that runs nicely in Node (for example) might not work the same way due to this behaviour. Also, I also notice another thing: if JavaScript code makes a call to a native-provided method (e.g. by calling the setTimeout I show above, which I implement via a native-side handler) then during that call from JavaScript, it is possible for the native side to execute a call() and run Javascript code it wants. Again this is not what would happen in Node or Safari: it is not possible for timeouts (or network completions) to interrupt any 'builtin' function call, but in JavascriptCore it certainly is (to get around this I set a flag on the JavaScript side indicating a native call is being made, and if any native-triggered callback occurs on the javascript side when this flag is set, I have to 'queue' it via a promise handler for execution AFTER the current event loop is complete). Are these known issues with Javascript core and are there ways to get around them? thanks
0
1
135
1w
Scrolling is backwards with external devices when rotating to landscape mode
We recently converted an existing app to adopt scenes (for CarPlay). The app has one main view controller that presents a WKWebView to show our content. Everything works fine in both landscape and portait mode when swiping on the screen to scroll. But with an iPad using an external Magic Keyboard, once you rotate to landscape mode the scrolling gestures are reversed. Swiping vertically on the trackpad is scrolling the page horizontally and vice versa. When this happens an error like below is logged (this error also shows up when in portait mode, but scrolling works as expected): Unexpected window orientation: <UIWindow: 0x10370d8f0; orientation: landscapeLeft (4)> { hidden = NO; frame = {{0, 0}, {1180, 820}}; bounds = {{0, 0}, {1180, 820}}; ownsOrientation = NO; ownsOrientationTransform = NO; autorotationDisabled = NO; windowInterfaceOrientation = unknown (0); rootTransformOrientation = landscapeLeft (4); viewTransformOrientation = unknown (0); autorotationDisabled = NO; orientationVC = ... { providedSupportedOrientations = ( Pu Ll Lr Pd ); resolvedSupportedOrientations = ( Pu Ll Lr Pd ); canPreferOrientation = NO; }; }, event type: 6 It seems to suggest that while the view controller orientation is set correctly. It doesn't know what the orientation is for the window. I have been unable to figure out what would change with adopting scenes that would explain this behavior. I assume it has to do with the potential multi-window nature of it but haven't found any docs that describe how to ensure the window is setup to use the same orientation as the device. Any suggestions on things to check?
1
0
194
2w
Memory crash at String._bridgeToObjectiveCImpl()
I'll describe my crash with an example, looking for some insights into the reason why this is happening. @objc public protocol LauncherContainer { var launcher: Launcher { get } } @objc public protocol Launcher: UIViewControllerTransitioningDelegate { func initiateLaunch(url: URL, launchingHotInstance: Bool) } @objc final class LauncherContainer: NSObject, LauncherContainer, TabsContentCellTapHandler { ... init( ... ) { ... super.init() } ... // // ContentCellTapHandler // public func tabContentCellItemDidTap( tabId: String ) { ... launcher.initiateNewTabNavigation( tabId: tabId // Crash happens here ) } public class Launcher: NSObject, Launcher, FooterPillTapHandler { public func initiateNewTabNavigation(tabId: String) { ... } } public protocol TabsContentCellTapHandler: NSObject { func tabContentCellItemDidTap( tabId: String, }
2
0
190
1w