Is MultiPolygon overlay support going to be integrated with SwiftUI?
I have made a post on here previously without a reply :(
Any suggestions on how to display multi-polygons within MapKit for SwiftUI(https://developer.apple.com/documentation/mapkit/mappolygon)?
At the moment it is not supported and only supported by MapKit for UIKit(https://developer.apple.com/documentation/mapkit/mkmultipolygon).
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Post
Replies
Boosts
Views
Activity
We have an iPad app and are using the new TabView and TabSection views in our sidebar. The TabSection is populated with data from a @FetchRequest that fetches data from CoreData. The data in CoreData is updated by a single worker that makes sure every value only exists once. This is done by using an OperationQueue with maxConcurrentOperationCount set to 1.
This is crashing for our users, and we can't figure out why. We can't reproduce it, and it only seems to happen on iPadOS. We have the same code running on macOS and haven't received any reports. (We collect them all via 3rd party).
The error is:
NSInternalInconsistencyException
Fatal: supplied item identifiers are not unique. Duplicate identifiers: {(
...
)}
Where ... is one to many comma separated strings.
In our latest update we made sure the values are unique by passing them through a Set, unfortunately this is till crashing. Here's the fix we tried.
var uniqueTags: [HashTag] {
let set = Set(hashTags)
let array = Array(set)
return array.sorted {
$0.name?.lowercased() ?? "" < $1.name?.lowercased() ?? ""
}
}
We're out of ideas and have no idea what to do next.
I'm working on integrating the new format panel shown in the WWDC24 session "What's New in UIKit" under the Text Improvements section. So far, I've implemented long-press functionality on a text passage, allowing the editing options to appear. From there, you can go to Format > More..., which successfully opens the new format panel.
However, I would also like to add a button to programmatically display this format panel—similar to how the Apple Notes app has a button in the keyboard toolbar to open it.
Does anyone know how to achieve this?
Here's my current code for the text editor (I've enabled text formatting by setting allowsEditingTextAttributes to true):
struct TextEditorView: UIViewRepresentable {
@Binding var text: String
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UITextView {
let textEditorView = UITextView()
textEditorView.delegate = context.coordinator
textEditorView.allowsEditingTextAttributes = true
return textEditorView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
}
class Coordinator: NSObject, UITextViewDelegate {
var parent: TextEditorView
init(_ uiTextView: TextEditorView) {
self.parent = uiTextView
}
func textViewDidChange(_ textView: UITextView) {
self.parent.text = textView.text
}
}
}
Thanks in advance for any guidance!
Hi,
Im developing a data centric App using SwiftData, I noticed that the device I use for testing doesn't sync its data with the simulator although both have same Apple Account ? What's Im missing here ? arched is my project settings.
Kind Regards
I receive the following compiler error:
Cannot infer key path from context; consider explicitly specifying a root type
when I attempt an @Environment(\.foodRepository) lookup in a descendant View.
Here's the setup in my App class:
import SwiftUI
import SwiftData
@main
struct BulkCutApp: App {
private var foodRepository: FoodRepository = /* some code*/
var body: some Scene {
WindowGroup {
ContentView()
.foodRepository(foodRepository)
}
}
}
extension View {
func foodRepository(_ customValue: FoodRepository) -> some View {
environment(\.foodRepository, customValue)
}
}
extension EnvironmentValues {
var foodRepository: FoodRepository {
get { self[FoodRepositoryKey.self] }
set { self[FoodRepositoryKey.self] = newValue }
}
}
struct FoodRepositoryKey: EnvironmentKey {
static var defaultValue: FoodRepository = FoodRepository(food:[])
}
Nothing special in FoodRepository:
@Observable
class FoodRepository {
var food: [Food]
// more code
}
I want to create master details relationship between patient and vitals signs so which of option codes below are better performance wise ? Option one is master - details done manually ..
option 1
@Model
class TestResult {
@Attribute(.primaryKey) var id: UUID
var patientID: UUID
Option 2
@Model
final class Vital {
var patient: Patient?
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 -> [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) -> 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)
}
}
}
When I upgraded to Sequoia 15.1, an app that worked fine under OS 14 stopped working. Out of 4 views on the main screen, only 1 is visible. Yet, if I click where another view should be, I get the expected action so the views are there, just not visible. Only I can't see where I am clicking!
I had to upgrade to Xcode 16 to recompile the app and run it in Debug mode. When I do, I get the following:
NSBundle file:///System/Library/PrivateFrameworks/MetalTools.framework/ principal class is nil because all fallbacks have failed.
Can't find or decode disabled use cases.
applicationSupportsSecureRestorableState
FWIW - the only view that actually shows up is the last subview added to the main view.
I have an app that needs to store a SwiftUI Color within SwiftData and I was wondering if anyone had found a way to do so easily and accurately.
I'd prefer not to have to store the Color components (e.g. RGB values) and would ideally like to have a single variable in the @Model that stores the Color.
I had considered using an extension to the Color type to create a HEX encoded String of the Color and an initializer that creates a Color from the HEX encoded String. Unfortunately, doing so proved not to be accurate due data loss when converting component values to integers.
When testing this in Photoshop, the original color #FBAA1D became #FFAB00.
Is there a way to accurately store the Color in SwiftData, possibly using a binary conversion to Data or somehow storing the Color.Resolved, which itself does not appear to be compatible with SwiftData.
Any thoughts on how to best store the Color accurately within SwiftData would be greatly appreciated.
I have an app with the following model:
@Model class TaskList {
@Attribute(.unique)
var name: String
// Relationships
var parentList: TaskList?
@Relationship(deleteRule: .cascade, inverse: \TaskList.parentList)
var taskLists: [TaskList]?
init(name: String, parentTaskList: TaskList? = nil) {
self.name = name
self.parentList = parentTaskList
self.taskLists = []
}
}
If I run the following test, I get the expected results - Parent has it's taskLists array updated to include the Child list created. I don't explicitly add the child to the parent array - the parentList relationship property on the child causes SwiftData to automatically perform the append into the parent array:
@Test("TaskList with children with independent saves are in the database")
func test_savingRootTaskIndependentOfChildren_SavesAllTaskLists() async throws {
let modelContext = TestHelperUtility.createModelContext(useInMemory: false)
let parentList = TaskList(name: "Parent")
modelContext.insert(parentList)
try modelContext.save()
let childList = TaskList(name: "Child")
childList.parentList = parentList
modelContext.insert(childList)
try modelContext.save()
let fetchedResults = try modelContext.fetch(FetchDescriptor<TaskList>())
let fetchedParent = fetchedResults.first(where: { $0.name == "Parent"})
let fetchedChild = fetchedResults.first(where: { $0.name == "Child" })
#expect(fetchedResults.count == 2)
#expect(fetchedParent?.taskLists.count == 1)
#expect(fetchedChild?.parentList?.name == "Parent")
#expect(fetchedChild?.parentList?.taskLists.count == 1)
}
I have a subsequent test that deletes the child and shows the parent array being updated accordingly.
With this context in mind, I'm not seeing these relationship updates being observed within SwiftUI. This is an app that reproduces the issue. In this example, I am trying to move "Finance" from under the "Work" parent and into the "Home" list.
I have a List that loops through a @Query var taskList: [TaskList] array. It creates a series of children views and passes the current TaskList element down into the view as a binding.
When I perform the operation below the "Finance" element is removed from the "Work" item's taskLists array automatically and the view updates to show the removal within the List. In addition to that, the "Home" item also shows "Finance" within it's taskLists array - showing me that SwiftData is acting how it is supposed to - removed the record from one array and added it to the other.
The View does not reflect this however. While the view does update and show "Finance" being removed from the "Work" list, it does not show the item being added to the "Home" list. If I kill the app and relaunch I can then see the "Finance" list within the "Home" list. From looking at the data in the debugger and in the database, I've confirmed that SwiftData is working as intended. SwiftUI however does not seem to observe the change.
ToolbarItem {
Button("Save") {
list.name = viewModel.name
list.parentList = viewModel.parentTaskList
try! modelContext.save()
dismiss()
}
}
To troubleshoot this, I modified the above code so that I explicitly add the "Finance" list to the "Home" items taskLists array.
ToolbarItem {
Button("Save") {
list.name = viewModel.name
list.parentList = viewModel.parentTaskList
if let newParent = viewModel.parentTaskList {
// MARK: Bug - This resolves relationship not being reflected in the View
newParent.taskLists?.append(list)
}
try! modelContext.save()
dismiss()
}
}
Why does my explicit append call solve for this? My original approach (not manually updating the arrays) works fine in every unit/integration test I run but I can't get SwiftUI to observe the array changes.
Even more strange is that when I look at viewModel.parentTaskList.taskLists in this context, I can see that the list item already exists in it. So my code effectively tries to add it a second time, which SwiftData is smart enough to prevent from happening. When I do this though, SwiftUI observes a change in the array and the UI reflects the desired state.
In addition to this, if I replace my custom list rows with an OutlineGroup this issue doesn't manifest itself. SwiftUI stays updated to match SwiftData when I remove my explicit array addition.
I don't understand why my views, which is passing the TaskList all the way down the stack via Bindable is not updating while an OutlineGroup does.
I have a complete reproducible ContentView file that demonstrates this as a Gist. I tried to provide the source here but it was to much for the post.
One other anecdote. When I navigate to the TaskListEditorScreen and open the TaskListPickerScreen I get the following series of errors:
error: the replacement path doesn't exist: "/var/folders/07/3px_03md30v9n105yh3rqzvw0000gn/T/swift-generated-sources/@_swiftmacro_09SwiftDataA22UIChangeDetectionIssue20TaskListPickerScreenV9taskLists33_A40669FFFCF66BB4EEA5302BB5ED59CELL5QueryfMa.swift"
I saw another post regarding these and I'm wondering if my issue is related to this.
So my question is, do I need to handle observation of SwiftData models containing arrays differently in my custom views? Why do bindings not observe changes made by SwiftData but they observe changes made explicitly by me?
need to use CocoaPods, Ruby, and Xcode to set up a development environment.
trying to install CocoaPods and running into compatibility issues with Ruby versions (>= 2.7.0) and can't use rbenv.
I am trying to work on a new app but everytime I try to run it and test it I get this error
error reading dependency file '/Users/jacobwright/Library/Developer/Xcode/DerivedData/LevelingUp:_Life-baixnmqgtntqiacdkadvwrgeanox/Build/Intermediates.noindex/LevelingUp: Life.build/Debug-iphonesimulator/LevelingUp: Life iOS.build/Objects-normal/arm64/LevelingUp: Life iOS-master-emit-module.d': unexpected character in prerequisites
and I do not know what to do. I even tryed makeing a new project and running it with out doing anything and I get the same thing I have tried Deleting Xcode and Reinstalling, and updating my computer and Xcode. I am not sure what else to try and I was wondering if anyone else is getting this and how do i fix it?
I have a view, and in this view I bind Axis class values — lowerBound which is a regular property and at – computed one which comes from protocol HasPositionProtocol associated with Axis.
struct AxisPropertiesView<Axis>: View
where Axis: StyledAxisProtocol,
Axis: HasPositionProtocol,
Axis: Observable
{
@Bindable var axis: Axis
var body: some View {
HStack {
TextField("", text: $axis.shortName)
.frame(width: 40)
TextField("",
value: $axis.lowerBound,
format: .number)
.frame(width: 45)
//Problem is here:
Slider(value: $axis.at,
in: axis.bounds)
...
Unfortunately I got en error Failed to produce diagnostic for expression; ... for whole View.
But if I remove Slider from View, error disappeared.
What could cause this strange behaviour?
Value of .at comes from:
public extension HasPositionProtocol {
///Absolut position on Axis
var at: Double {
get {
switch position {
case .max:
return bounds.upperBound
case .min:
return bounds.lowerBound
case .number(let number):
return number
}
}
set {
switch newValue {
case bounds.lowerBound:
position = .min
case bounds.upperBound:
position = .max
default:
position = .number(newValue)
}
}
}
}
I am creating an iOS app to install on legacy iPads running iOS 9 and up, using XCode 13.4.1 which is the latest version that will support iOS below 11. The app is working fine but I just added a QuickLook Preview extension, and on iOS 10.3.1 it will not install due to the following error:
This app contains an app extension that specifies an extension point identifier that is not supported on this version of iOS for the value of the NSExtensionPointIdentifier key in its Info.plist. Domain: com.apple.dt.MobileDeviceErrorDomain Code: -402653007
The NSExtensionPointIdentifier key in Info.plist is set by XCode automatically to "com.apple.quicklook.preview".
I want to set the iOS Deployment Target to the lowest iOS version that will support this configuration. The documentation does not provide any guide as to which specific NSExtensionPointIdentifier keys are compatible with which iOS version. It just says 8+ for the whole list. Trial-and-error is limited by availability of legacy Simulators.
If anyone can point to documentation that indicates which iOS is supported by which NSExtensionPointIdentifier key com.apple.quicklook.preview, I would be very grateful. Thanks
(I understand about lack of App Store support etc, this is an app for my use on old iPads)
I'm using SwiftData to store data in my app and I recently had to store both image data and colors.
I have therefore added two variables to my model, one of type Data? and the other of type Color.Resolved?
If both are set to nil then I can call context.save() without any error but when providing a value of type Color.Resolved, the following error message occurs: Thread 1: Fatal error: Composite Coder only supports Keyed Container.
Any guidance on how to solve this and what needs to be done to store image data and colors with SwiftData?
Is it possible to let the user select points of interest on the Map, such as restaurants, grocery stores, gas stations etc. I want the user to be able to select these points of interest that are already on the map, not those that I add to the map. Is this possible with the SwiftUI version of the MapKit Map?
I don't believe it's possible today to access the icon and tint color of a MapFeature although this would be incredibly helpful in the app that I'm building presently as I'm storing places in SwiftData and would like to use the same icon and tint color when listing places in the app.
It would be awesome if this were possible in the next version of iOS, iPadOS visionOS etc., if not presently possible.
Hi,
The dataModule in code below is a swiftData object being passed to the view and its property as key path but when trying to modify it I'm getting the error ."Cannot assign through subscript: 'self' is immutable" how to solve this issue ?
Kind Regards
struct ListSel<T: PersistentModel>: View {
@Bindable var dataModule: T
@Binding var txtValue: String
var keyPath: WritableKeyPath<T, String>
var turncate: CGFloat? = 94.0
var image = ""
var body: some View {
HStack {
Text(txtValue)
.foregroundColor(sysSecondary)
.font(.subheadline)
.onChange(of: txtValue) { value in
dataModule[keyPath: keyPath] = value
}
Image(systemName: image)
.foregroundColor(sysSecondary)
.font(.subheadline)
.imageScale(.small)
.symbolRenderingMode(.hierarchical)
.scaleEffect(0.8)
}
.frame(width: turncate, height: 20, alignment: .leading)
.truncationMode(.tail)
}
}
Is there really no way to hide a TabItem using the built-in TabView?
I have 6 pages, but the 6th one I want hidden from the bottom tab bar, because I have a button that programmatically navigates to it on the navigation bar.
I did not want to have to code a custom tab bar due to losing some useful features like pop to root in Navigation Stack.
I want to play remote videos using an AVPlayer in my SwiftUI App. However, I can't fix the error:
"Main thread blocked by synchronous property query on not-yet-loaded property (PreferredTransform) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network."
My code looks like this atm:
struct CustomVideoPlayer: UIViewControllerRepresentable {
let myUrl: URL
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
let playerItem = AVPlayerItem(url: myUrl)
let player = AVQueuePlayer(playerItem: playerItem)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
context.coordinator.setPlayerLooper(player: player, templateItem: playerItem)
playerViewController.delegate = context.coordinator
playerViewController.beginAppearanceTransition(true, animated: false)
return playerViewController
}
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
}
static func dismantleUIViewController(_ uiViewController: AVPlayerViewController, coordinator: ()) {
uiViewController.beginAppearanceTransition(false, animated: false)
}
class Coordinator: NSObject, AVPlayerViewControllerDelegate {
var parent: CustomVideoPlayer
var player: AVPlayer? = nil
var playerLooper: AVPlayerLooper? = nil
init(_ parent: CustomVideoPlayer) {
self.parent = parent
super.init()
}
func setPlayerLooper(player: AVQueuePlayer, templateItem: AVPlayerItem) {
self.player = player
playerLooper = AVPlayerLooper(player: player, templateItem: templateItem)
}
}
}
I already tried creating the AVPlayerItem/AVAsset on a background thread and I also tried loading the properties asynchronously before setting the player in makeUIViewController:
let player = AVQueuePlayer(playerItem: nil)
...
Task {
let asset = AVAsset(url: myUrl)
let _ = try await asset.load(.preferredTransform)
let item = AVPlayerItem(asset: asset)
player.replaceCurrentItem(with: item)
}
Nothing seems to fix the issue (btw: the main thread is actually blocked, there is a noticable animation hitch).
Any help is much appreciated.