The sessions showing off the new SwiftUI macros are missing a key element.... How are they enabled within XCODE?!??!?
For instance the session "Discover Observation in SwiftUI" starts with the code block.
@Observable class FoodTruckModel {
var orders: [Order] = []
var donuts = Donut.all
}
Well.... Something is missing here! I'm sure it's that I need to import something.... but for an intro session it MIGHT be important to mention what needs to be imported and any other requirements. Because right now all I'm getting is "Unknown attribute 'Observable'"
So far this is a VERY disappointing WWDC. I got all excited about VisionOS... Nope, all the SDK isn't being release for a month. Reality Composer Pro... Not out yet. SwiftUI macros... Sure let's dive right in to step 6 and not tell you what you need to get started with this feature.
Post not yet marked as solved
I'm in the process of migrating to the Observation framework but it seems like it is not compatible with didSet. I cannot find information about if this is just not supported or a new approach needs to be implemented?
import Observation
@Observable class MySettings {
var windowSize: CGSize = .zero
var isInFullscreen = false
var scalingMode: ScalingMode = .scaled {
didSet {
...
}
}
...
}
This code triggers this error:
Instance member 'scalingMode' cannot be used on type 'MySettings'; did you mean to use a value of this type instead?
Anyone knows what needs to be done? Thanks!
Post not yet marked as solved
Why would it not allow to set the value in the init statement. The @Model allows this and as I understand it also acts as an @Observable.
Post not yet marked as solved
I tried to migrate some code to SwiftData and Observable...doing this I wanted to mark a ViewModel-Class with @observable but get errors when using it in combination with didSet.
What's wrong with it?!
@Observable struct LADVAthletes {
var queryName : String = "" {
didSet {
guard oldValue != queryName else { return }
guard queryName.count < 2 else {
athletesList.removeAll()
return
}
}
}
var athletesList : [Athlete] = [Athlete]()
}
I get multiple Errors saying
"Cannot find 'oldValue' in scope"
"Instance member 'queryName' cannot be used on type 'LADVAthletes'; ....
And so on...
What's wrong with it?!
Post not yet marked as solved
They provide an example on using @Observable in minute 5:14 :
@Observable class Account { var userName: String? }
However, if you put that in Xcode this gives an error: @Observable requires property 'userName' to have an initial value (from macro 'Observable')
Anyone else seeing this?
Post not yet marked as solved
When I update a variable inside my model that is marked @Transient, my view does not update with this change. Is this normal? If I update a non-transient variable inside the model at the same time that I update the transient one, then both changes are propagated to my view.
Here is an example of the model:
@Model public class WaterData {
public var target: Double = 3000
@Transient public var samples: [HKQuantitySample] = []
}
Updating samples only does not propagate to my view.
Post not yet marked as solved
Previously, it was recommended to use the @MainActor annotation for ObservableObject implementation.
@MainActor
final class MyModel: ObservableObject {
let session: URLSession
@Published var someText = ""
init(session: URLSession) {
self.session = session
}
}
We could use this as either a @StateObject or @ObservedObject:
struct MyView: View {
@StateObject let model = MyModel(session: .shared)
}
By moving to Observation, I need to the @Observable macro, remove the @Published property wrappers and Switch @StateObject to @State:
@MainActor
@Observable
final class MyModel {
let session: URLSession
var someText = ""
init(session: URLSession) {
self.session = session
}
}
But switching from @StateObject to @State triggers me an error due to a call to main-actor isolated initialiser in a synchronous nonisolated context.
This was not the case with @StateObject of @ObservedObject.
To suppress the warning I could :
mark the initializer as nonisolated but it is not actually what I want
Mark the View with @MainActor but this sounds odd
Both solutions does not sound nice to my eye.
Did I miss something here?
Post not yet marked as solved
We currently have our entire app written as SwiftUI Views with ViewModels (currently set as @StateObjects). SwiftUI has a new feature in iOS 17 called @Observable which simplifies the MVVM pattern and would greatly reduce the complexity of our codebase.
However, our current ViewModels implement Combine pipelines on the @Published properties which allows us to do all sorts of things from validation of inputs to ensuring lists are filtered correctly.
Without the @Published property wrapper in the new @Observable macro, we don't have access to those combine pipelines and so we were wondering how others have solved this?
One idea we are floating around is using CurrentValueSubjects as the variable types, but that does pollute the code a little as we have to utilise .send() and .value in the Views which seems like an anti-pattern.
Any thoughts or help would be greatly appreciated!
Post not yet marked as solved
Apple released their new Observation Framework in WWDC23 and they use it with SwiftUI. I've seen lots of resources about how to use it with SwiftUI but I cannot find anything how can I use it with UIKit. So, I am curious about is there any way to use it with UIKit.
How we can use the two together? If we cannot, Why? and What are the restrictions of Observation Framework?
Post not yet marked as solved
// Before I was able to do something like:
struct ContentView: View {
@EnvironmentObject var listData: ListData
var body: some View {
ListView($listData.listDataArray)
}
}
struct ListView: View {
@Binding var listDataArray: [DataType]
}
class ListData: ObservableObject {
@Published var listDataArray: [DataType] = []
}
// Now, I will get the error "Cannot find '$listData' in scope" on the line indicated below when I try to migrate to the Observable macro
struct ContentView: View {
@Environment(ListData.self) var listData
var body: some View {
ListView($listData.listDataArray) ----------> Error
}
}
struct ListView: View {
@Binding var listDataArray: [DataType]
}
@Observable
class ListData {
var listDataArray: [DataType] = []
}
@main
struct SomeApp: App {
@State private var listData = ListData()
var body: some Scene {
WindowGroup {
ContentView
.environment(listData)
}
}
}
// Before
class A: ObservableObject {
@Published var dataArray: [dataType]
}
class B: ObservableObject {
@Published var dataArray: [dataType]
init(a: A) {
A.$dataArray
.assign(to: &$dataArray)
}
}
// After applying @Observable, I get an error "Cannot find 'A.$anArray' in scope" on the line indicated below.
@Observable
class A {
var dataArray: [dataType]
}
@Observable
class B {
var dataArray: [dataType]
init(a: A) {
A.$dataArray ----------------------------- Error
.assign(to: &$dataArray)
}
}
Class A contains an array to store data fetched from an API. I'm trying to extract some contents from class A into class B. Making them focus on different functionality. All functions in Class B also require the downloaded data.
Post not yet marked as solved
I want to use Throttling and Debouncing to handle the inputs from the user. These are common techniques to reduce the number of events that are triggered by the inputs. I know how to implement them with the ObservableObject protocol and Combine framework. However, I am trying to migrate to the @Observable property wrapper, which is a new feature of SwiftUI. I cannot find a way to support Throttling and Debouncing with @Observable.
Does anyone have any ideas or suggestions on how to solve this problem?
@Environment can't use for Binding?
@Observable
final class View1Model {
var text: String = ""
}
struct View1: View {
@State var viewModel = View1Model()
var body: some View {
View2()
.environment(viewModel)
}
}
struct View2: View {
@Environment(View1Model.self) var viewModel
var body: some View {
TextField("Text", text: $viewModel.text) // Cannot find '$viewModel' in scope
}
}
Post not yet marked as solved
Hi. The binding in a ForEach or List view doesn't work anymore when using the @Observable macro to create the observable object. For example, the following are the modifications I introduced to the Apple's example called "Migrating from the Observable Object Protocol to the Observable Macro" https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro
struct LibraryView: View {
@Environment(Library.self) private var library
var body: some View {
List($library.books) { $book in
BookView(book: book)
}
}
}
All I did was to add the $ to turn the reference to library.books into a binding but I got the error "Cannot find '$library' in scope"
Is this a bug or the procedure to use binding in lists changed?
Thanks
Post not yet marked as solved
I understand that @Observable currently requires all properties to be initialised. However I am surprised that opting out of observation does not work:
@Observable class Assessment {
var name = ""
var processes: [Process] = []
}
@Observable class Process {
var name = ""
@ObservationIgnored weak var parent: Assessment?
}
The error message is Return from initializer without initializing all stored properties from the Process class. Any suggestions?
Hi everyone,
I'm new to programming and I've been experimenting with Apple's SwiftData. I've run into an issue I can't seem to resolve.
I'm creating a personal relationship manager app where I have a Relation model and an Interaction model. Relation has a one-to-many relationship with Interaction. I'm using SwiftData's @Model and @Relationship property wrappers to define these models and their relationship. I've taken inspiration from Apple's sample code, that can be found here:
Adopting SwiftData for a Core Data app
(WWDC23 Session: "Migrate to SwiftData")
The relevant parts of the models look something like this:
@Model
final class Relation {
...
@Relationship(.cascade, inverse: \Interaction.relation)
var interactions: [Interaction] = []
...
}
@Model
final class Interaction {
...
var relation: Relation?
...
}
In my SwiftUI view, I'm adding a new Interaction to a Relation like this:
private func AddItem() {
withAnimation {
let newInteraction = Interaction(...)
modelContext.insert(newInteraction)
newInteraction.relation = relation
relation.interactions.append(newInteraction)
}
}
When I add a new Interaction like this, everything seems to work fine during that app session. I can see the new Interaction in my app's UI. But when I quit the app and relaunch it, the new Interaction is gone. It's as if it was never saved.
I've double-checked my code and as far as I can tell, I'm using SwiftData correctly. My usage aligns with the sample code provided by Apple, and I'm not getting any errors or warnings. I think that this issue is not related to SwiftData being in Beta, because Apple's sample code works perfectly fine.
I have a few questions:
Is there something I'm missing about how to properly save models using SwiftData?
Is there a specific step or method I need to call to persist the changes to the Relation and Interaction objects?
Is there a way to debug what's going wrong when SwiftData attempts to save these changes?
Any help would be greatly appreciated.
Thank you in advance!
Louis
Hello! I'm not able to push a view into a stack using new @Observable macro.
import SwiftUI
import Observation
@Observable class NavigationModel {
var path = NavigationPath()
}
struct ContentView: View {
@State var navigationModel: NavigationModel = NavigationModel()
var body: some View {
NavigationStack(path: $navigationModel.path) {
VStack {
Button {
navigationModel.path.append("Text")
} label: {
Text("Go to the next screen")
}
}
.navigationDestination(for: String.self) { item in
Text("Pushed view")
}
}
}
}
Everything works fine when I use ObservableObject with @Published properties:
class NavigationModel: ObservableObject {
@Published var path = NavigationPath()
}
struct ContentView: View {
@StateObject var navigationModel: NavigationModel = NavigationModel()
var body: some View {
NavigationStack(path: $navigationModel.path) {
Button {
navigationModel.path.append("Text")
} label: {
Text("Go to the next screen")
}
.navigationDestination(for: String.self) { item in
Text("Pushed view")
}
}
}
}
Post not yet marked as solved
Somehow the Swift compiler is unable to this code:
@Observable class ServiceBrowser: NSObject {
typealias ResolveServiceCompletionBlock = (Bool, Error?) -> Void
fileprivate var resolveServiceCompletionHandler: ResolveServiceCompletionBlock? = nil
}
Here's the crash:
4 . While evaluating request ASTLoweringRequest(Lowering AST to SIL for file "/Users/luc/Work/Repositories/app-shared/App/Shared/Connectivity/ServiceBrowser.swift")
5 . While silgen init accessor SIL function "@$s7App14ServiceBrowserC07resolveB17CompletionHandler33_5B15C352D9CC926D1F8A0ECAC5970199LLySb_s5Error_pSgtcSgvi".
for init for resolveServiceCompletionHandler (at /Users/luc/Work/Repositories/ap-shared/App/Shared/Connectivity/ServiceBrowser.swift:86:21)
6 . While emitting reabstraction thunk in SIL function "@$sSbs5Error_pSgIegyg_ytIegd_TR".
Post not yet marked as solved
With the following in an iOS and watch app
import Observation
@Observable final class DataModel {
var common = 0
#if os(iOS)
var iProp = 0
#endif
}
Xcode 15 beta 5 reports error: Cannot find type '_iProp' in scope
Is platform specific property forbidden in Observable objects?
Post not yet marked as solved
Since Xcode 15 beta 5, making a class with the @Observable macro no longer requires all properties to have an initialization value, as seen in the video. Just put an init that collects the properties and everything works correctly.
@Observable
final class Score: Identifiable {
let id: Int
var title: String
var composer: String
var year: Int
var length: Int
var cover: String
var tracks: [String]
init(id: Int, title: String, composer: String, year: Int, length: Int, cover: String, tracks: [String]) {
self.id = id
self.title = title
self.composer = composer
self.year = year
self.length = length
self.cover = cover
self.tracks = tracks
}
}
But there is a problem: the @Observable macro makes each property to integrate the @ObservationTracked macro that seems not to conform the types to Equatable, and in addition, to Hashable.
Obviously, being a feature of each property, it is not useful to conform the class in a forced way with the static func == or with the hash(into:Hasher) function that conforms both protocols.
That any class we want to be @Observable does not conform to Hashable, prevents any instance with the new pattern to be usable within a NavigationStack using the data driven navigation bindings and the navigationDestination(for:) modifier.
I understand that no one has found a solution to this. If you have found it it would be great if you could share it but mainly I am making this post to invoke the mighty developers at Apple to fix this bug. Thank you very much.
P.S. - I also posted a Feedback (FB12535713), but no one replies. At least that I see.