New Frameworks, New Mindset: Unveiling the Observation and SwiftData Frameworks

Published on

Get weekly handpicked updates on Swift and SwiftUI!

This content was presented at Let’s VisionOS 2024. For easier reading, I have simplified the original material and adjusted it for a more formal written expression. The core message of this share is to convey the following central idea: Although these new frameworks were designed to address issues in existing frameworks, we should not be constrained by past experiences and conventions. It is necessary to learn and use these new tools with an open mind and a fresh perspective. Adopting new frameworks should be seen as an excellent opportunity to refactor projects towards greater safety and modernization.

You can obtain the PDF version of the Keynotes in Chinese here.

Main Text

Hello everyone, I am Xu Yang, some friends might be more familiar with my other names, “肘子” or “Fat”. I’m glad to discuss application development related content with everyone here. First of all, I want to thank SwiftGG and XR Base for hosting the Let’s VisionOS event, providing this platform for communication.

Today, I will focus on the concept of “New Mindset”, and introduce two new frameworks launched last year, Observation and SwiftData. I won’t delve too much into their specific usages and implementation details, but will instead highlight the background and significance of constructing these two new frameworks, how to learn and use these tools with an open mind, and how to integrate this “New Thinking” into our future development practices.

Observation

The Purpose of Constructing Observation

Let’s talk about the Observation framework first. As its name implies, this framework is intended to provide observation functionality. What problem does it aim to solve?

The core goal of Observation is to introduce a new observation mechanism for SwiftUI applications to enhance their performance.

Why set such a goal? This requires us to start from the current observation mechanism of SwiftUI.

SwiftUI’s Current Observation Mechanism

As a reactive framework, SwiftUI’s views need to update along with the changes in state. This requires it to rely on some mechanism to track these state changes.

Before the introduction of the Observation framework, SwiftUI actually had two different observation mechanisms in place.

First is the observation mechanism for value type states. For example, for simple states within a view, we generally declare them with @State, and these states are mostly value types. For such states, SwiftUI can observe on its own.

However, for those states with broader impacts, even global ones, developers usually place them in a reference type container. For these reference type states, SwiftUI cannot observe independently but needs to rely on the “publisher-subscriber” pattern provided by the Combine framework to achieve observation. In fact, this observation model has some issues in the current SwiftUI.

The Cause of Excessive Invalid View Updates

Let’s look at the root of this issue.

Swift
final class MyObservableObject: ObservableObject {
    @Published var name: String
    @Published var age: Int
    // More properties...
}

extension MyObservableObject {
  var objectWillChange: Self.ObjectWillChangePublisher // An internal publisher instance that views will subscribe to
}

When we use the Combine framework and declare an observable object of type ObservableObject, the first requirement is to conform to the ObservableObject protocol. This protocol creates a publisher instance in the class. Whenever a variable marked with the @Published decorator changes, @Published triggers this publisher in the class to notify all subscribers. However, because these notifications do not contain specific information about the change, subscribers cannot know which @Published marked property has changed.

To delve into how @Published works, you can refer to the article Going Beyond @Published:Empowering Custom Property Wrappers.

In SwiftUI, views associated with the observable object are these subscribers. Even a minor part of the state change in the observable object can lead to updates in all associated views, causing a large number of ineffective view updates, which severely affects the performance of the application.

Through a specific example, we can see this issue more clearly:

Here is an observable object with two properties:

Swift
final class Store: ObservableObject {
  @Published var name = "Fei Fei"
  @Published var age = 5
}

In two different subviews, we reference this object, and each view uses only one of its properties:

Swift
struct NameView: View {
  @ObservedObject var store: Store
  var body: some View {
    let _ = print("NameView Update")
    Text(store.name)
  }
}

struct AgeView: View {
  @ObservedObject var store: Store
  var body: some View {
    let _ = print("AgeView Update")
    Text(store.age, format: .number)
  }
}

Since the NameView view is connected to the store instance (i.e., responds to notifications from that instance), it will be updated even when the age property changes. This reveals the shortcomings of the current observation mechanism.

Methods to Improve Invalid Updates

As we deepen our understanding of how SwiftUI operates, developers have gradually mastered some techniques to improve the aforementioned issue.

To delve deeper into these techniques, it is recommended to read How to Avoid Repeating SwiftUI View Updates for more details.

These common improvement methods include:

  • Introduce State on Demand

    An effective method is to not introduce the entire state container into the view, but only pass the state that the view actually needs. While this approach can reduce unnecessary view updates, it increases the development workload and is only suitable for pure presentation scenarios where there is no need to call methods of the state container in the view.

Swift
struct NameView{
  let name: String
  var body: some View{
    let _ = print("NameView Update")
    Text(name)
  }
}

The adjusted NameView will not update due to changes in the age state.

  • Utilize the Equatable Protocol

    Another method is to make the view conform to the Equatable protocol and customize the comparison logic to avoid redraws caused by updates to irrelevant properties. However, this method is not applicable to container-based classes.

Swift
@State var student = Student(name: "fat", age: 88)

struct StudentNameView: View, Equatable {
    let student: Student
    var body: some View {
        let _ = Self._printChanges()
        Text(student.name)
    }

    static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.student.name == rhs.student.name
    }
}
  • Splitting the State Container

    Splitting a larger state container into several smaller ones is also a solution. This method can narrow the scope of updates but sacrifices the convenience of state management.

Swift
class Store: ObservableObject {
  @Published var a: String
  @Published var b: String
}

class SubStore1: ObservableObject {
  @Published var a: String
}

class SubStore2: ObservableObject {
  @Published var b: String
}
  • Hierarchical Comparison of States

    Some third-party frameworks optimize performance by performing hierarchical comparisons at the time of state changes to exclude unchanged parts. However, this comparison itself also consumes performance. When the state hierarchy is deep, more resources are required for comparison, and the effect of performance improvement is reduced. Additionally, this method increases the learning cost.

Although the above methods are useful in specific scenarios, they do not fundamentally solve the performance issues caused by the observation mechanism; they merely address the symptoms, not the root cause. Therefore, SwiftUI urgently needs a new observation mechanism, specifically for reference type states. We hope this new framework can not only solve the current issue of invalid updates but also provide developers with more flexible and powerful state management capabilities.

It is with this consideration that Apple introduced the Observation framework.

The Observation Mechanism of the Observation Framework

How does the Observation framework create observable objects and build observation operations?

The Observation framework provides developers with two main tools: the @Observable attribute and the withObservationTracking function.

Introduced in Swift 5.9, the attribute aims to reduce the burden on developers by avoiding manual repetition of code, thereby enhancing development efficiency.

@Observable first introduces an “observation coordinator” – an instance of ObservationRegistrar – in the declaration of reference types. This coordinator is responsible for maintaining the connection between observable properties and observers. This is somewhat similar to the process by which the ObservableObject protocol adds a publisher to a class, but the principles and working mechanisms are entirely different.

Next, @Observable transforms stored properties into computed properties to ensure that their storage operations are fully managed by the observation coordinator. This allows for the integration of observation logic, somewhat akin to the working manner of the @Published property wrapper.

After declaring observable objects, we use the global function withObservationTracking to construct the observation. This function requires developers to provide two closures: all properties that need to be observed must appear in the apply closure and have their values read. When the observed properties are about to change, the framework calls the onChange closure, completing the “observe-callback” process.

In this way, Observation offers fine-grained observability of properties, addressing the issue of insufficient precision caused by only being able to observe the entire instance. This is the fundamental solution to the problems existing in the Combine observation mechanism.

Features of the Observation Framework

The observation mechanism provided by the Observation framework exhibits several unique features:

  • Local Observability: Observes only those properties of observable objects that are actually read in the apply closure, ensuring the precision and efficiency of observation.
  • Pre-change Notification: Calls the onChange closure before the actual change of property values (i.e., during the willSet phase), allowing developers to respond before changes occur.
  • One-time Observation: Each observation is one-time; once the onChange closure is triggered, the corresponding observation operation ends.
  • Multi-property, Multi-instance Monitoring: During one observation process, it’s possible to monitor multiple properties of several observable instances simultaneously. The change in any observed property triggers the onChange closure and ends that observation.

Although this observation logic may seem unique, it is actually meticulously designed to meet the specific needs of SwiftUI. It forms a perfect loop: from “creating the observation” (placing the view’s body in apply), to “state changes”, then to “view updates” (calling the onChange closure), and finally “re-creating the observation” (repeating the previous steps). This series of operations is closely linked, adapting to the rendering and updating mechanism of SwiftUI.

In actual SwiftUI development, developers typically do not need to manually construct observations using withObservationTracking, as SwiftUI has already integrated observation operations into its view evaluation logic.

Next, we will modify the previous example based on Combine to use the Observation method, to specifically showcase the changes that the introduction of the new framework can bring.

From Combine to Observation

To migrate observable objects from the Combine framework to Observation, we need to make several key adjustments: remove the ObservableObject protocol declaration, remove all @Published property wrappers, and add the @Observable attribute before the class declaration. By doing so, the @Observable attribute will introduce the functionalities we discussed earlier, further simplifying the declaration process of observable types.

Swift
@Observable
class Store {
  var name: String
  var age: Int
  
  func updateName() {}
}

When referencing this new observable object in the view, we replace the original @StateObject with @State and introduce the instance directly into the subview using the let keyword. After such adjustments, we find that despite the direct use of observable objects in the view, thanks to the more precise observability provided by Observation, the NameView view will not update due to changes in the age property.

This change demonstrates that if your application currently suffers from a large number of ineffective view updates and performance degradation due to insufficient observation precision, simply converting it to the Observation approach can quickly result in significant improvements.

To delve deeper into the specific usage and more details of the Observation framework, it is recommended to read A Deep Dive Into Observation: A New Way to Boost SwiftUI Performance.

The “New Mindset” Brought by Observation

The Observation framework should not only be seen as a tool for enhancing performance. With SwiftUI gaining such advanced observability capabilities, it fundamentally transforms how we conceive and design the state of applications. This transformation is not just about tweaking a few lines of code; it requires us to embrace a completely new mindset—a mindset that makes applications more flexible, reliable, scalable, and efficient.

Let’s explore the new possibilities opened up by the Observation framework, aside from performance enhancement:

  • Flexible Architectural Forms

Observation provides us with a new way to build and organize application states. Now, we can nest an observable object within another, creating state relationships that were difficult to construct before. Under the Combine framework, attempting to implement this kind of nesting would pose significant challenges, as @Published properties do not support observing changes within the internals of reference types.

Swift
@Observable
class A {
   var b = 1
}

@Observable
class B {
   var b = 1
   var a = A() // Nesting one observable object as a property of another
}
  • Precise Observation Construction Logic

With Observation, our view updates become more precise and efficient. It not only drills down to the property level but also to the specific way properties are operated on. An observation relationship is established only when a property of an observable object is actually read (i.e., its getter method is triggered). If there is merely an assignment or a method call within the observable object without triggering property read, no observation relationship with the view is established. In the Combine-based implementation, simply introducing an observable object into a view (for example, using @EnvironmentObject) would necessitate the view to respond to changes in the observable object instance, even if no property or method is used within the body. This precise observability capability of Observation significantly lightens the developer’s load, allowing us to design states with a more relaxed mindset.

Swift
struct A: View {
  let store: Store
  var body: some View {
    Text(store.name) // Reading the property, creating a connection
  }
}

struct B: View {
  let store: Store
  var body: some View {
    Button("Update"){
      store.name = "hello" // Not triggering the getter method, no observation relationship established
    }
  }
}

Through this “new mindset,” we can design and build the state of SwiftUI applications with more confidence and creativity. This change is not just technical but a comprehensive revolution in development thinking. We should embrace these new possibilities, fully leverage the advantages brought by Observation, and bring fundamental changes and enhancements to our applications.

Back-porting

Lastly, let’s discuss another key advantage of the Observation framework: backward compatibility.

While the features of the Observation framework are very appealing, there might be concerns about it only supporting the latest system versions, leaving many users unable to benefit.

Here’s good news: Although Observation is primarily designed for SwiftUI, Apple has chosen to release it as open-source, meaning it’s not limited to SwiftUI or the Apple ecosystem. In fact, the goal of Observation is not only to enhance the application performance of SwiftUI but also to provide property-level observability for reference types in Swift across various platforms.

Thanks to its open-source nature, developers can modify or wrap the framework according to their needs, creating third-party libraries compatible with older system versions, thus enabling all SwiftUI applications to benefit from the innovations of Observation.

For example, using third-party libraries like ObservationBP and Perception, regardless of the development stage of our project or the version of SwiftUI it depends on, we can immediately enjoy the innovations brought by Observation.

Therefore, although Observation is a new framework, its design philosophy and open-source nature ensure it can bring benefits to a broader range of projects. Of course, one might wonder if Observation could be used in other scenarios, such as UIKit or beyond views? Theoretically, it’s feasible, but it might not be convenient at the moment. Observation primarily focuses on serving SwiftUI, so for now, it’s best to consider it a part of SwiftUI. However, in the future, as the community continues to work, the application scenarios of Observation will undoubtedly expand. Therefore, there’s no reason not to start learning and using this framework immediately, embracing a new mindset to enhance the quality of applications.


That concludes our introduction to Observation. Next, we will explore another framework of this theme—SwiftData.


SwiftData

SwiftData is a data management framework launched by Apple last year, considered the successor to Core Data. It combines Core Data’s mature persistence technology with the modern concurrency features of Swift, quickly adding persistence capabilities to your application.

To better understand the changes brought by SwiftData, let’s first briefly introduce Core Data.

Introduction to Core Data

  • Long History: Core Data is a veteran framework. It first appeared in MacOS Tiger in 2005, making it 19 years old now. Its history can be traced back to the Enterprise Objects Framework (EOF) developed during the time of Steve Jobs at NeXTSTEP.

  • Enterprise Origins, Focused on Stability and Security: EOF was designed for enterprise applications and was once popular within financial institutions, hence it particularly emphasized security and reliability.

  • Layered Architecture, Powerful Extensibility: Similarly, as a product aimed at enterprises, EOF adopted a layered architectural design, endowing it with strong extensibility. Stability, security, and extensibility have all been inherited by Core Data. Some of the new features Apple has introduced to Core Data in recent years, such as persistent history tracking and cloud syncing, are based on its strong extensibility.

  • Object Graph Management Framework: In Core Data, all data exists in the form of objects, with Core Data managing the lifecycle, state, and relationships between these objects. Hence, Core Data is often referred to as an object graph management framework.

    Object graphs are usually complex, necessitating tools for better management and representation. Developers mainly use the model editor in Xcode to build data models for Core Data, which is an effective visual construction method for handling complex object relationships. The editor can also automatically generate code corresponding to the data model.

  • Simplified Data Persistence Operations: Core Data users do not need to possess database knowledge to perform data persistence operations. Core Data itself supports multiple data storage forms and allows developers to construct other types of data storage.

As an important foundational framework within the Apple ecosystem, Core Data is widely used in many Apple official applications and other foundational frameworks.

The Advantages of Core Data in the Apple Ecosystem

Compared to other data management frameworks within the Apple ecosystem, Core Data also possesses some additional advantages:

  • System Built-in Framework, Low Resource Consumption: As a system-built-in framework, Core Data keeps application size compact and runtime resource consumption low. This efficiency is particularly suitable for environments with strict memory limitations, such as widgets or browser extensions. Many developers who have worked on widgets might have a deeper understanding of this, as many other data management frameworks cannot be used in these scenarios due to resource limitations.
  • Seamless CloudKit Integration: Since 2019, Apple has enhanced the integration between Core Data and CloudKit, enabling developers to easily implement data cloud storage, sharing, and cross-device synchronization with a one-stop solution. This integration not only simplifies the development process but also brings a core advantage of the Apple ecosystem: free cloud services. Many developers are attracted to Core Data because of this feature.

These advantages collectively establish Core Data’s unique position within the Apple ecosystem.

The Current Issues Faced by Core Data

Despite our exploration of Core Data’s history, advantages, and features, one question remains: if Core Data is so powerful, why introduce a new framework like SwiftData?

In fact, while Core Data has many significant advantages, these primarily reflect its past design goals, hardware standards, and development tools at the time. As times have changed, Core Data has shown limitations in adapting to modern development needs.

  • Shift in Target Audience: Core Data was initially designed for enterprise applications, meticulously equipped for the functional needs of this domain. However, as the focus shifted to desktop and mobile applications, especially in the mobile domain, Core Data’s complexity became overly cumbersome for the vast majority of mobile app developers. Modern developers crave simpler, more intuitive, and efficient data management solutions.
  • Advancements in Development Tools: Currently, Swift has become the mainstream development language. Although Core Data can be utilized in Swift projects, it was built on Objective-C, which can create certain inconveniences and barriers in use. This technical disparity prevents developers from fully leveraging many of Swift’s advanced features, especially those related to type safety and compile-time checks, which are core advantages of the Swift language.
  • Updates in Development Frameworks: The launch of SwiftUI changed the way UI is developed, but there is a lack of natural synergy between Core Data and SwiftUI. Developers often need to build an additional adapter layer to facilitate data display in views. Moreover, Core Data still uses the observation mechanism based on Combine, which seems outdated compared to the newly launched Observation framework.

These issues have made many developers feel that Core Data has a high barrier to entry and requires more effort in development and debugging. For this reason, Apple has been striving to develop a data management framework that not only meets current but also future development trends, ultimately introducing “SwiftData”.

In fact, every year as WWDC approaches, developers using Core Data have been anticipating the release of a new framework, which they have long referred to as SwiftData. It was unexpected but pleasing that Apple eventually adopted this name.

The Legacy and Innovation of SwiftData

As a framework that carries many expectations, can SwiftData live up to its significant responsibility? Does it address the practical issues faced by Core Data?

  • Inherits the Stability of Core Data: SwiftData is built upon the infrastructure of Core Data, retaining the stability that is at the core of its role as a data management framework. Therefore, although SwiftData is a brand-new framework, its stability in data storage and retrieval has already been proven.
  • Compatible with Core Data’s Databases: SwiftData is fully compatible with databases constructed with Core Data. Thus, migrating applications to SwiftData only requires adjustments at the code level, without the need to modify existing data.
  • Fully Utilizes the Features of the Swift Language, Even Promoting Its Development: Being named SwiftData signifies its close integration with the Swift language. It not only fully utilizes Swift’s language features but, thanks to support from Apple and the Swift community, has introduced new functionalities specifically designed for it, allowing developers to enjoy safe concurrency patterns, strong typing, compile-time checks, and other advanced language features.
  • Simplifies Complex Features, Hiding Unnecessary Details: SwiftData deliberately omits those complex, hard-to-understand, or rarely used features from Core Data, simplifies its layered structure, and significantly lowers the learning curve.
  • Deep Integration with the Observation Framework, More SwiftUI Friendly: By improving the way data models are constructed and adopting an observation mechanism based on the Observation framework, SwiftData enhances the convenience of using data in SwiftUI and optimizes application performance.

In summary, SwiftData retains the core advantages of Core Data while introducing ease of learning, ease of use, and tighter integration with SwiftUI. It fully embraces the design philosophy and latest features of the Swift language, redefining the data management framework for the SwiftUI era.


As a brand-new data management framework, SwiftData introduces many innovative features worth exploring in depth. Due to time constraints, I will briefly introduce two particularly notable features.


Pure Code-Based Data Modeling in SwiftData

SwiftData has fundamentally transformed the long-standing visualization-based data modeling approach of Core Data, adopting a pure code-based modeling method. While most other data management frameworks in the Apple ecosystem have already been using code-based approaches, Core Data maintained its visualization-based model construction method due to its powerful capability to handle complex object graphs. However, as application scenarios have evolved, complex object relationship management is no longer a primary requirement, prompting SwiftData to adopt a more mainstream and flexible pure code-based modeling approach.

Indeed, Apple likely recognized this two years ago when it removed the object graph editing mode from Xcode.

qEmjG

Although SwiftData is a newcomer in the realm of pure code-based data model construction, it undoubtedly offers the finest implementation. Developers can define data models in a relaxed, intuitive, and precise manner using code. Leveraging Swift’s macro capabilities and a series of innovative language features, developers can now construct their data models similarly to defining native Swift types. This method significantly lowers the learning curve and notably enhances the readability of model code, making the definition of data structures both clear and intuitive.

Swift
@Model
public final class ImageData {
  @Attribute(.externalStorage)
  public var data: Data?

  @Relationship(deleteRule: .nullify)
  public var asset: ImageAsset?

  public init(data: Data? = nil, asset: ImageAsset? = nil) {
    self.data = data
    self.asset = asset
  }
}

Read Unveiling the Data Modeling Principles of SwiftData for more on modeling details.

SwiftData’s adoption of pure code-based modeling is not just a change in form; it also means that developers can conceptualize and organize their data models in entirely new ways:

  • Encourages developers to encapsulate data logic into independent modules: The code-based approach is better suited for modular development, allowing developers to easily package data models and logic into independent modules, improving code maintainability and reusability.

    We know that in Core Data, after creating a data model, Xcode first generates an xcdatamodeld file, then packages the compiled momd file into the app, which we use to transform into a data model when building the container. Due to the presence of these resource files, many developers dislike separating the model and data handling logic code into an independent module. With SwiftData, there is no such burden; all data models are code-based, thus encouraging developers to better abstract and encapsulate data operations in a modular fashion.

  • Facilitates unit testing for developers: Compared to Core Data, SwiftData’s pure code models are easier to unit test, allowing developers to write more test cases to ensure code quality and stability.

    For instance, building unit tests for Core Data also requires some techniques, especially how to use one data model file to create data containers for different test units. SwiftData makes this much simpler, allowing developers to freely write more test units. This is a project I am currently working on, where nearly 100 tests related to SwiftData can be completed in just a few seconds.

  • More suitable for direct use in views: SwiftData improves the compatibility of data models with SwiftUI views, allowing developers to use models directly in views without an additional adapter layer. Moreover, objects in SwiftData now also adopt the observation mechanism based on Observation, thereby enhancing application performance.

  • Expands the application scenarios of data management frameworks: SwiftData significantly simplifies the way of data modeling, enabling it to replace UserDefaults and file operations in many scenarios, becoming a more secure, streamlined, and efficient persistence solution that also supports cloud synchronization. This advancement greatly broadens the application range of data management frameworks.

Through these changes, SwiftData not only simplifies the declaration process of data models but also pushes the entire project towards a more modernized and secure direction. SwiftData is defining a new paradigm of data management for the SwiftUI era of application development.

Actor-Based Concurrent Operations

Beyond modeling methods, SwiftData also introduces significant innovations in handling concurrent operations.

In the past, although Core Data’s stability was generally good, many developers might have had different opinions regarding its stability in concurrent operations. Safe concurrent operations in Core Data often relied on the developer’s experience and patience and lacked substantial support at the system level.

Since the release of Swift 5.5, Swift officially entered a new era of structured concurrency. Nowadays, more and more developers have enabled strict concurrency checks in anticipation of Swift 6. Innovatively, SwiftData encapsulates data operation logic within Actors, allowing developers to benefit from compiler-supported concurrency safety checks, thereby writing efficient, safe, and concise concurrent code.

Here is an example of implementing concurrent programming in SwiftData, where data operation logic is encapsulated in an Actor marked with the @ModelActor macro. Regardless of which thread the DataHandler methods are called from, all operations are safely executed in a specific serial queue, liberating developers from the cumbersome manual handling of perform code.

Swift
@ModelActor
actor DataHandler {
    func updateItem(identifier: PersistentIdentifier, timestamp: Date) throws {
        guard let item = self[identifier, as: Item.self] else {
            throw MyError.objectNotExist
        }
        item.timestamp = timestamp
        try modelContext.save()
    }

    func newItem(timestamp: Date) throws -> Item {
        let item = Item(timestamp: timestamp)
        modelContext.insert(item)
        try modelContext.save()
        return item
    }
}

For more on concurrency in SwiftData, read Concurrent Programming in SwiftData.

This transformation involved tremendous effort and innovation because, before SwiftData’s emergence, Swift had not provided the capability for custom executors to allow Actors to run on specified threads. With the release of Swift 5.9, the community finally implemented this feature, providing the foundation for SwiftData to build a new paradigm of concurrent programming.

This shift in concurrency logic is not just a technical improvement; it also encourages developers to separate data logic code from SwiftUI views and move it into independent modules, aligning with modern programming trends and enhancing code cleanliness and maintainability.

The encapsulation based on Actors also changes how data operation logic is integrated into views or other state management modules, promoting a safer, more reliable data injection model.

Swift
extension DataProvider {
  public func dataHandlerCreator(configuration: DataStoreConfiguration? = nil) -> @Sendable () async -> DataHandler {
    let configuration = configuration != nil ? configuration! : self.configuration
    let container = persistentContainer
    return { DataHandler(configuration: configuration, modelContainer: container) }
  }
}

struct DataHandlerKey: EnvironmentKey {
  static let defaultValue: @Sendable () async -> DataHandler? = { nil }
}

extension EnvironmentValues {
  var createDataHandler: @Sendable () async -> DataHandler? {
    get { self[DataHandlerKey.self] }
    set { self[DataHandlerKey.self] = newValue }
  }
}

In summary, each innovation in SwiftData is carefully thought out, aimed at prompting developers to reevaluate business logic and project architecture from a new perspective, achieving more modernized and efficient development practices.

Practical SwiftData: Building SwiftUI Applications with Modern Approaches

As a modern successor to Core Data, SwiftData is not just a reshaping of old concepts; it represents a comprehensive innovation in data management philosophy. Therefore, when developers consider integrating it into their projects, they might face some challenges and questions. To help address these issues, I wrote an article titled Practical SwiftData: Building SwiftUI Applications with Modern Approaches a few days before this event. This article comprehensively introduces how to combine SwiftData with modern programming concepts and smoothly integrate it into SwiftUI application development.

In Conclusion

Today, we explored two innovative frameworks launched by Apple last year. Though they target different technical fields, they share significant commonalities:

  • They were born from the need to modernize existing frameworks.
  • They are closely integrated with the advanced features of the Swift language.
  • They have the potential to shape modern application development logic.

The core theme of today’s sharing is “New Frameworks, New Mindset.” We should break free from the limitations of traditional thinking and embrace these emerging APIs with a fresh perspective. It’s important to recognize that Apple’s introduction of these new technologies is not just for enhancing surface-level functionality and efficiency but to meet deeper future development needs, indicating a significant impact on future development logic and design architecture.

It’s been an honor to share and exchange ideas with you all. I hope today’s content brings some inspiration to your learning and development. Thanks again to the organizers for their meticulous planning, and I wish the Let’s VisionOS event greater success in the future, becoming a highlight in the development community.

Weekly Swift & SwiftUI insights, delivered every Monday night. Join developers worldwide.
Easy unsubscribe, zero spam guaranteed