Доклад: Как макросы изменили навигацию / Михаил Рубанов (Dodo Engineering)

Доклад: Как макросы изменили навигацию / Михаил Рубанов (Dodo Engineering)

Introduction to Swift UI Navigation

Overview of the Session

  • The session is hosted by Nikita Krasnov and co-hosted by Evgeny Nofreychik, focusing on Swift UI navigation.
  • Misha Rubanov is introduced as a guest speaker who will discuss how macros have changed navigation in Swift UI.

Speaker Background

  • Misha Rubanov has seven years of experience working at Dodo Pizza and has authored various projects, including a free book on iOS accessibility.
  • He emphasizes the impact of his book on companies' interest in accessibility topics.

Exploring Macros in Swift

Purpose of the Talk

  • The presentation aims to explore modern Swift features, particularly focusing on libraries developed by Point Free's Brandon and Stefan.
  • It will provide an overview rather than deep technical details, encouraging attendees to explore further resources afterward.

Structure of the Presentation

  • The talk will begin with discussing existing problems within Swift before exploring solutions related to macros.
  • Attendees are encouraged to share their experiences with macros via chat during the session.

Identifying Problems in Swift

Key Issues with Data Handling

  • Different data handling methods lead to varying modifiers; structs require different syntax compared to classes (e.g., @State vs. @StateObject).
  • There are performance concerns due to verbose code that operates over Combine, which can hinder efficiency.

Navigation Challenges

  • Historical accumulation of various APIs for navigation creates confusion about which ones should be used effectively.

Understanding Macros and Their Benefits

Definition and Functionality

  • Macros allow developers to add additional code at compile time using markers around specific code sections.

Practical Example: CAS Possible Library

  • [] (Not provided yet; continue from transcript for more insights into practical applications.)

Understanding Enum Usage in Swift

Challenges with Enums and Data Handling

  • The speaker discusses the limitations of enums in Swift, particularly when trying to associate additional objects with enum values, which is not straightforward.
  • In SwiftUI, managing different states (loading, data received, or failure) can be cumbersome due to the lack of direct support for passing data through enums.
  • An example is provided involving a navigation route where specific cases (like phone number or SMS) need to extract corresponding values from an enum.
  • The process of retrieving values requires repetitive code structures for each case, leading to redundancy and inefficiency in coding practices.
  • The speaker highlights that existing code often involves duplicative constructs that are tedious and prone to errors.

Introducing Kсобов Library Macros

  • A library called Kсобов offers macros that simplify working with enums by allowing developers to define properties more declaratively.
  • With these macros, developers can use a special syntax to retrieve enum cases directly into view models without extensive boilerplate code.
  • The macro system allows for expanded functionality; it generates underlying code during compilation that simplifies the developer's workload significantly.
  • By using macros, programmers can create template-like structures that enhance readability and maintainability of their codebase.
  • This approach leads to a more declarative style of programming where properties are clearly defined without excessive complexity.

Observations on SwiftUI Framework Changes

  • The introduction of macros aligns with new features in iOS 17's observation framework aimed at improving state management within SwiftUI applications.
  • The speaker critiques current practices in SwiftUI regarding how observable objects and published properties are handled across views and models.
  • There’s a discussion about the inconsistency in needing multiple annotations (like @StateObject or @EnvironmentObject), which complicates development processes unnecessarily.
  • A comparison is made between traditional methods versus new approaches introduced by Apple’s observation framework for better clarity and efficiency.
  • Observable objects can now be declared more simply using macros rather than requiring complex inheritance or protocol confirmations.

Simplifying Code Structure

  • Overall changes aim at reducing boilerplate while enhancing clarity; observable will now function as a macro simplifying class declarations significantly.

Swift UI Updates and Observations

Changes in Property Subscription

  • The need for signing various publish properties has been eliminated; they can be removed from the project entirely. Apple documentation suggests simply deleting them.
  • Properties are now automatically measured for changes, with a macro handling this process. There is an option to mark properties that do not require observation using @ObservationIgnored.

Simplified State Management

  • Instead of subscribing to a state object, developers can now subscribe directly to the state itself, which simplifies the process significantly.
  • If a view model is created within a view and needs to maintain state across redraws, it must still have its own state added.

Introduction of Bindable

  • A new term "bindable" replaces previous binding methods; it applies to entire classes rather than specific values, allowing views to modify internal object values more intuitively.
  • Other elements like environment remain unchanged; overall syntax between structures and classes has become simpler.

Transitioning Between Code Constructs

  • Developers maintaining legacy Swift code must navigate three different constructs due to these updates, which may complicate refactoring or migration efforts.

Swift UI's Reaction and Observation Protocol Enhancements

  • Swift UI operates on top of Combine; previously published properties required monitoring through Combine but are now handled differently with new protocols.
  • The observation protocol introduces visObservationTracking, which allows for more granular control over property changes affecting views.

Efficient Redraw Mechanism

  • The new mechanism tracks property access within closures; only changes in accessed properties will trigger view updates, enhancing performance by avoiding unnecessary redraws.
  • This approach allows the system to intelligently determine when a view should be redrawn based on specific property changes rather than general model alterations.

Understanding SwiftUI's Observation Tracking

Overview of View Redrawing

  • The body of the view is wrapped in the Vis observation tracking function, which triggers a redraw of the entire view when any values change.
  • A state holds a list of countries with their names and flag links; accessing these properties will cause the view to redraw.
  • If other properties within the view model change, the view does not update, leading to more efficient performance.

Performance Improvements

  • Transitioning to this new observation model can reduce redraw instances significantly—potentially halving them compared to previous implementations.
  • However, there are concerns regarding documentation clarity and usability since this framework was introduced in version 17.

Trade-offs with Macros

  • While macros simplify code writing, they can increase compilation time due to added complexity.
  • Apple has increasingly adopted macros across frameworks, including testing frameworks, indicating a trend towards macro usage.

Simplifying Model Descriptions

  • The observation framework allows for simplified descriptions at the model level; views only redraw based on accessed properties.
  • This introduces some underlying complexities that may make debugging more challenging as behavior changes with macro additions.

Exploring Backporting Options

  • Discussion on how to backport Apple's observation framework using an external library called Perception that adds observable capabilities to models.
  • The Perception library introduces a Perceptable marker for various classes and tracks property changes effectively.

Macro Functionality Insights

  • When expanding macros in Perception, additional code is generated that registers property access and modifications for tracking purposes.
  • Each property access is logged into a change register, allowing views to query whether specific properties have changed before redrawing.

Understanding View Models and Perception in Frameworks

Mechanism of Value Registration

  • The view model registers changes when a value is written, ensuring that any modifications are recorded in a change register.
  • When the view is redrawn, it checks this register to identify what has changed and triggers necessary updates in the UI.

Handling Property Changes

  • Properties marked with "perception ignored" can be excluded from change tracking, improving performance by preventing unnecessary updates.
  • The framework automatically manages getters and setters for properties, simplifying the process of determining what needs to be redrawn in the UI.

Syntax Changes in Framework

  • The transition from observable to perception indicates a shift in terminology within the framework, reflecting its evolution.
  • Key terms have been updated: "bindable" becomes "perception bindable," enhancing clarity around mutable models.

Backporting Framework Features

  • The entire codebase of the previous framework has been backported for use on earlier iOS versions while maintaining native performance.
  • Future upgrades (e.g., iOS 17) allow developers to replace old dependencies seamlessly with new ones without losing functionality.

Implementation Challenges

  • Each view must implement vis perception tracking, which adds complexity and potential for errors during compilation if overlooked.
  • This requirement can lead to longer compile times and obscure error messages; developers may need to temporarily disable tracking for debugging purposes.

User Experience Enhancements

  • Despite challenges, using newer frameworks offers improved user experience through streamlined property management without extensive manual setup.
  • For features like search fields, properties must be marked as "perception bindable" to ensure they trigger UI updates correctly.

Auto-Warning Feature

  • An auto-warning feature alerts developers when they forget to implement necessary functions, helping maintain code integrity without crashing execution.

Perception Tracking in Swift Development

Overview of Perception Tracking

  • The speaker discusses the implementation of perception tracking in their view model, emphasizing its self-reflective nature and ease of use with Xcode's assistance.
  • They highlight the ability to replicate system code through macros, which simplifies future migrations by allowing for easy replacements within the codebase.

Migration Considerations

  • The speaker notes that while adding perception tracking to every view can slow down compilation, it ultimately enhances performance and development speed.
  • They mention that perception tracking must be integrated at multiple points within complex screens, which can lead to increased complexity but is manageable due to Xcode's warnings.

Challenges with Apple's Framework Decisions

  • A key question arises regarding why Apple does not simplify certain processes for developers, leading to additional workarounds in frameworks like UIKit.
  • The speaker expresses frustration over Apple's lack of support for seamless integration between different frameworks, impacting developer efficiency.

Framework Functionality and Integration

  • The discussion shifts to how observation and perception frameworks operate independently from Swift, allowing for data changes within classes without direct ties to Swift itself.
  • They explain how these frameworks enable a more traditional MVVM architecture by linking UI elements directly with view model properties.

Prototyping and Flexibility in Development

  • The speaker describes a streamlined workflow where developers can quickly prototype interfaces using Swift while maintaining a universal view model adaptable across different frameworks.
  • This flexibility allows teams to test features in production environments before deciding on permanent implementations or migrations between frameworks.

Conclusion on Perception Tracking Benefits

  • Ultimately, perception tracking replaces older observation methods by providing granular control over property changes, facilitating the creation of versatile models compatible with both SwiftUI and UIKit.

Frameworks and Navigation in iOS Development

Introduction to Framework Perception

  • The discussion begins with the introduction of the Perception framework, which was released alongside iOS 17. It highlights that this framework was demonstrated at WB DC and became operational by September when iOS 17 launched.
  • Initial concerns about integrating Perception into production were noted, but over time, discussions in the repository revealed that most issues were related to bugs within Apple's Swift frameworks rather than fundamental problems with native Swift.

Challenges in UI Navigation

  • The speaker transitions to discussing navigation challenges within applications, using a task management app (Todoist) as an example. They emphasize the need for multiple modal states for adding, editing, or deleting tasks.
  • A typical user interface scenario is described where different modals are required based on user actions—adding a new task prompts one modal while editing another prompts a different one.

Issues with Current Implementation

  • The current implementation in native Swift UI is critiqued for its complexity; it requires managing multiple properties that can lead to ambiguous behavior during testing.
  • There’s a risk of undefined behavior if all three properties (for showing alerts/modals) are set simultaneously without clear guidance on which should take precedence.

Proposed Solutions Using Enums

  • To address these issues, the speaker suggests using enums to define distinct states for navigation. This approach clarifies what can be displayed at any given time and prevents conflicting modal presentations.
  • By implementing enums with specific cases representing each possible state (e.g., add item, edit item), developers can streamline their code and improve clarity.

Integration of New Framework Features

  • The introduction of new features through frameworks like Case Possible allows developers to manage navigation more effectively by defining single properties tied to enum cases instead of multiple ambiguous flags.
  • This change simplifies how view models interact with views by ensuring only one destination is active at any time, thus reducing confusion during development and testing.

Conclusion: Enhancements Through Framework Adoption

  • The final thoughts focus on how adopting these frameworks leads to clearer code structures and better-defined behaviors in applications. Developers are encouraged to leverage these tools for improved navigation handling.
  • Overall, the integration of enums and enhanced frameworks provides a robust solution for managing complex UI interactions within iOS applications.

Understanding View Models and UI Binding

Transitioning to View Models

  • The discussion highlights a shift from directly accessing properties to utilizing view models, which helps eliminate ambiguity in code interactions.
  • This change ensures that only one alert or window appears at a time, simplifying the testing process and enhancing clarity in unit tests.

Enhancements in Testing

  • The integration of view models improves understanding during unit and integration testing, making it easier to ensure screens appear correctly.
  • The speaker notes that additional wrappers around view controllers enhance binding capabilities, allowing for better management of hidden values within the app.

Observations on SwiftUI

  • In SwiftUI, the concept of "bindable" is introduced to manage state changes when users interact with screens.
  • The framework observation for view models adds a layer of complexity but ultimately aims for simplicity in syntax across different UI frameworks.

Navigation and Syntax Consistency

  • A new line of code can link states within the view model, demonstrating how navigation between SwiftUI and UIKit remains consistent despite underlying complexities.
  • The speaker emphasizes that this consistency allows developers to easily transition between frameworks without significant rework.

Challenges with Onboarding Processes

  • As the speaker transitions jobs, they reflect on onboarding challenges involving multiple user verifications and data entries.
  • They express a desire to automate testing for these processes rather than manually going through each step repeatedly.

Architectural Discussion on User Scenarios

Overview of the User Scenario

  • The speaker discusses the architectural approach to a user scenario involving SMS verification and user creation, emphasizing the simplicity of backend interactions.
  • Key steps include requesting an SMS, confirming it, creating a passcode, and determining if the user is new or returning based on their status.

Decomposing the Scenario into Screens

  • Each screen in the scenario is associated with its own view model, allowing for a structured decomposition of the overall process.
  • The flexibility of screen states is highlighted; elements can be rearranged without affecting the overall scenario flow.

Navigation and View Models

  • Navigation within screens involves stacking view models in an array that observes changes to trigger appropriate UI updates.
  • The speaker emphasizes separating data from UI frameworks to create universal navigation across different platforms (UIKit vs. SwiftUI).

Defining Screen Transitions

  • A list of screens with their respective view models is created to outline transitions between them effectively.
  • The speaker mentions using macros for easier management of these transitions while initiating tests to verify expected outcomes.

Testing Navigation Logic

  • During testing, expectations are set for specific values (like phone numbers) to appear in the navigation array as indicators of successful transitions.
  • A helper function can extract relevant view models based on expected screen names, ensuring that navigation logic functions correctly.

Finalizing Test Scenarios

  • Tests involve simulating user input (e.g., entering phone numbers), checking that subsequent screens appear as intended throughout onboarding processes.
  • The simplicity and effectiveness of this testing approach are noted; it allows for comprehensive validation without excessive complexity in code structure.

Onboarding Navigation Challenges

Issues with Back Button Visibility

  • During onboarding, the back button should disappear in certain scenarios, such as after user data is filled. Users should either log out to restart or not return to previous screens like SMS.

Testing and Architecture Preparation

  • The speaker discusses preparing for a new project and testing by researching architectural schemes for making requests. This preparation includes defining view models and using Test-Driven Development (TDD) to outline screen displays and request handling.

View Model Structure in Swift UI

  • The architecture involves creating a clear separation of concerns where view models are defined first before moving on to layout design. This approach allows for better management of time and complexity across different screens.

Navigation Stack Functionality

  • Swift UI's navigation stack operates similarly to traditional methods, allowing binding to an array that manages various routes. The speaker emphasizes how this integration works seamlessly with Swift UI starting from version 16.

Data Handling and Domain Separation

  • A domain model can be created where each view model corresponds directly with specific data objects, enabling easy updates when adding new screens. Changes in the code trigger compiler warnings for necessary adjustments, ensuring comprehensive testing through automated tests.

Swift Navigation Framework Comparison

Native vs. Framework Navigation

  • The discussion contrasts native Swift UI navigation with the additional capabilities provided by the Swift Navigation framework, which includes backward compatibility features for older iOS versions while maintaining functionality.

Router Implementation in UIKit

  • In UIKit, routing can be implemented within view controllers using similar principles as those found in Swift UI. This flexibility allows developers to extract views based on route values effectively.

Hosting Controller Usage

  • When integrating Swift views into UIKit applications, hosting controllers are used to manage transitions between different types of views while maintaining a consistent navigation experience across platforms.

Migration Flexibility Between Frameworks

  • Developers have the option to gradually migrate from UIKit to Swift UI or vice versa without losing functionality or requiring significant rewrites of existing codebases. This adaptability is crucial for managing risks during development transitions.

Universal Navigation Model and Testing Insights

Overview of the Universal Navigation Model

  • The universal navigation model is effectively tested, allowing easy extraction of data. It operates on top of observation or perception frameworks.
  • When minimum requirements are raised, areas using perception are highlighted with warnings, indicating they need to be removed. This feature enhances usability.

Issues with Swift UI and Framework Bugs

  • Discussions reveal various issues within the framework that often boil down to bugs in the kit itself, which also appear when using native frameworks.
  • The speaker emphasizes that these bugs can hinder development but are not exclusive to any particular library or framework.

Testing Scenarios and Domain Logic Separation

  • A comprehensive scheme is proposed for breaking down scenarios into requests, focusing on separating domain logic from user interface components.
  • The user interface consists of two parts: screens with view models and transition scenarios between those screens. This separation aids in testing efficiency.

Navigational Structure and Flexibility

  • Internal navigation within screens is managed by view models, while stack navigation involves multiple view models combined together, simplifying complexity in design.
  • The upper part of the navigational structure can be universally applied across different frameworks, enabling streamlined testing processes regardless of the underlying technology used.

Advantages of High-Level Testing

  • High-level tests cover business cases effectively while requiring fewer tests overall; they focus on whether applications function correctly rather than individual components like unit tests do.
  • This approach allows developers flexibility in choosing frameworks (Swift or others) without being tied down by specific implementations or designs.

Apple's Role and Framework Recommendations

  • A question arises as to why Apple hasn't developed a more integrated solution for these challenges; it could simplify many aspects of app development significantly if they did so.
  • The speaker recommends exploring macro features in projects despite potential increases in compilation time due to added code complexity—especially relevant for larger projects versus medium-sized ones where performance may remain stable.

Case Possible Framework Insights

  • "Case Possible" is highlighted as a useful framework for extracting values efficiently without excessive boilerplate code—ideal for developers looking to streamline their architecture decisions further.

Observations on New Apple Framework Features

  • Apple's new Observation framework works only with iOS 17 but offers nearly native backporting capabilities through perception features that enhance model universality and reduce code volume while improving performance metrics overall.

Prototyping Flexibility

  • Developers can prototype applications using any framework before deciding what best suits production needs based on performance evaluations during real-world usage scenarios post-launch—an essential strategy moving forward into 2025 as key frameworks become available for older iOS versions like 13+.

Future Directions and Personal Projects

  • As the speaker transitions into developing a new banking application, they express excitement about applying these insights practically while sharing experiences through future updates via their channel—a call-to-action for audience engagement around ongoing developments in this space.

Discussion on TCA and Project Architecture

Overview of TCA Usage in Doda

  • The speaker clarifies that TCA (The Composable Architecture) is not used in Doda, emphasizing that the composable architecture discussed earlier is separate from TCA.
  • The speaker expresses skepticism about building an entire project around a framework like TCA, citing past experiences with various frameworks that initially seemed promising but later faltered.
  • Despite not using TCA, the speaker keeps up with Pointfree's tools and articles, appreciating their innovative use of Swift features.

Testing and Model Management

  • A question arises regarding the necessity of extracting models; Apple recommends keeping them private to avoid complications in testing and navigation within Swift UI projects.
  • The speaker argues against tightly coupling view models to UI components, as it complicates independent testing and can lead to reliance solely on UI tests.
  • Emphasizing architectural responsibility, the speaker highlights the importance of designing for testability to accommodate various scenarios without lengthy wait times for UI tests.

Challenges with View Models

  • A participant raises concerns about potential issues when passing view models between child views, which could lead to screen navigation problems or observation failures.
  • The discussion touches on specific cases where transferring view models might cause bugs or unexpected behavior due to state management complexities.

Conclusion on Framework Limitations

  • The conversation concludes with acknowledgment of new sources of bugs introduced by complex interactions between views and state objects.
  • Participants reflect on common misconceptions regarding testing limitations within Swift UI architectures while expressing interest in further discussions.

Discussion on Swift Macros and Performance

Impact of Macros on Compilation Time

  • The use of macros, such as memberwise init, can automate constructor generation in Swift models, but may increase compilation time due to additional processing.
  • It's crucial to consider the frameworks being used; while some modules may handle macros well, others might not benefit from them.
  • There is a need for empirical testing comparing old and new Swift versions to assess performance impacts accurately.

Performance Concerns with Testing Frameworks

  • Synthetic tests indicate that using certain testing frameworks can lead to significant slowdowns, sometimes by hundreds of times.
  • Anticipation exists for future Apple processors (like M8) that could potentially mitigate these performance issues.

Business Considerations in Development Speed

  • In startup environments where rapid deployment is essential, compilation speed may be deprioritized until financial stability allows for code refactoring.

Testing Animation in Navigation

Approaches to Testing Animations

  • Discussion revolves around how to test navigation animations effectively, including whether flags like animated are triggered correctly during transitions.

Default Behavior in Swift Navigation

  • By default, all transitions in Swift Navigation are animated. Developers can create transactions without animations if needed for instant screen changes.

Challenges with UI Testing

  • Different testing frameworks serve various purposes; logical flow tests require different approaches than UI tests which check data binding and visual presentation.
  • There is uncertainty about how to verify specific animation behaviors through UI tests; community input is encouraged for shared experiences.

Conclusion and Acknowledgments

  • The session concludes with gratitude towards viewers and an invitation for further discussion among participants who remain engaged after the recording ends.
Video description

В Свифте появились макросы, что дало возможность упростить и спрятать шаблонный код, а значит сделать наш код более верхнеуровневым. Так Apple использовала макросы во фреймворке Observation, чтобы упростить SwiftUI, а Point-Free сделала библиотеку, которая позволяет использовать Observation начиная с iOS 13. Еще это позволило использовать Observation вместе с UIKit, что дает нам «нормальный» MVVM и более того — модель данных может быть универсальной между разными UI-фреймворками. Ну и в конце это дало возможность написать универсальную навигацию, которая решает часть задача за нас и которую легко тестировать. Посмотрим на фреймворки CasePathable, Observation, Perception и SwiftNavigation Контакты спикера: https://t.me/akaDuality https://t.me/RubanovMobile Понравилось видео и хочешь узнать что-то еще про Podlodka iOS Crew? Забирай весь плейлист на https://podlodka.io/crew-records или покупай годовой доступ ко всей Библиотеке контента.